LCOV - code coverage report
Current view: top level - svx/source/stbctrls - zoomsliderctrl.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 100 194 51.5 %
Date: 2014-11-03 Functions: 13 17 76.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <svx/zoomsliderctrl.hxx>
      21             : #include <vcl/status.hxx>
      22             : #include <vcl/menu.hxx>
      23             : #include <vcl/image.hxx>
      24             : #include <vcl/svapp.hxx>
      25             : #include <vcl/settings.hxx>
      26             : #include <svx/zoomslideritem.hxx>
      27             : #include <svx/dialmgr.hxx>
      28             : #include <svx/dialogs.hrc>
      29             : #include <basegfx/tools/zoomtools.hxx>
      30             : 
      31             : #include <set>
      32             : 
      33        1688 : SFX_IMPL_STATUSBAR_CONTROL( SvxZoomSliderControl, SvxZoomSliderItem );
      34             : 
      35        1464 : struct SvxZoomSliderControl::SvxZoomSliderControl_Impl
      36             : {
      37             :     sal_uInt16                   mnCurrentZoom;
      38             :     sal_uInt16                   mnMinZoom;
      39             :     sal_uInt16                   mnMaxZoom;
      40             :     sal_uInt16                   mnSliderCenter;
      41             :     std::vector< long >      maSnappingPointOffsets;
      42             :     std::vector< sal_uInt16 >    maSnappingPointZooms;
      43             :     Image                    maSliderButton;
      44             :     Image                    maIncreaseButton;
      45             :     Image                    maDecreaseButton;
      46             :     bool                     mbValuesSet;
      47             :     bool                     mbOmitPaint;
      48             : 
      49        1464 :     SvxZoomSliderControl_Impl() :
      50             :         mnCurrentZoom( 0 ),
      51             :         mnMinZoom( 0 ),
      52             :         mnMaxZoom( 0 ),
      53             :         mnSliderCenter( 0 ),
      54             :         maSnappingPointOffsets(),
      55             :         maSnappingPointZooms(),
      56             :         maSliderButton(),
      57             :         maIncreaseButton(),
      58             :         maDecreaseButton(),
      59             :         mbValuesSet( false ),
      60        1464 :         mbOmitPaint( false ) {}
      61             : };
      62             : 
      63             : const long nSliderXOffset = 20;
      64             : const long nSnappingEpsilon = 5; // snapping epsilon in pixels
      65             : const long nSnappingPointsMinDist = nSnappingEpsilon; // minimum distance of two adjacent snapping points
      66             : 
      67             : // nOffset referes to the origin of the control:
      68             : // + ----------- -
      69           0 : sal_uInt16 SvxZoomSliderControl::Offset2Zoom( long nOffset ) const
      70             : {
      71           0 :     const long nControlWidth = getControlRect().GetWidth();
      72           0 :     sal_uInt16 nRet = 0;
      73             : 
      74           0 :     if ( nOffset < nSliderXOffset )
      75           0 :         return mpImpl->mnMinZoom;
      76             : 
      77           0 :     if ( nOffset > nControlWidth - nSliderXOffset )
      78           0 :         return mpImpl->mnMaxZoom;
      79             : 
      80             :     // check for snapping points:
      81           0 :     sal_uInt16 nCount = 0;
      82           0 :     std::vector< long >::iterator aSnappingPointIter;
      83           0 :     for ( aSnappingPointIter = mpImpl->maSnappingPointOffsets.begin();
      84           0 :           aSnappingPointIter != mpImpl->maSnappingPointOffsets.end();
      85             :           ++aSnappingPointIter )
      86             :     {
      87           0 :         const long nCurrent = *aSnappingPointIter;
      88           0 :         if ( std::abs(nCurrent - nOffset) < nSnappingEpsilon )
      89             :         {
      90           0 :             nOffset = nCurrent;
      91           0 :             nRet = mpImpl->maSnappingPointZooms[ nCount ];
      92           0 :             break;
      93             :         }
      94           0 :         ++nCount;
      95             :     }
      96             : 
      97           0 :     if ( 0 == nRet )
      98             :     {
      99           0 :         if ( nOffset < nControlWidth / 2 )
     100             :         {
     101             :             // first half of slider
     102           0 :             const long nFirstHalfRange = mpImpl->mnSliderCenter - mpImpl->mnMinZoom;
     103           0 :             const long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
     104           0 :             const long nZoomPerSliderPixel = (1000 * nFirstHalfRange) / nHalfSliderWidth;
     105           0 :             const long nOffsetToSliderLeft = nOffset - nSliderXOffset;
     106           0 :             nRet = mpImpl->mnMinZoom + sal_uInt16( nOffsetToSliderLeft * nZoomPerSliderPixel / 1000 );
     107             :         }
     108             :         else
     109             :         {
     110             :             // second half of slider
     111           0 :             const long nSecondHalfRange = mpImpl->mnMaxZoom - mpImpl->mnSliderCenter;
     112           0 :             const long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
     113           0 :             const long nZoomPerSliderPixel = 1000 * nSecondHalfRange / nHalfSliderWidth;
     114           0 :             const long nOffsetToSliderCenter = nOffset - nControlWidth/2;
     115           0 :             nRet = mpImpl->mnSliderCenter + sal_uInt16( nOffsetToSliderCenter * nZoomPerSliderPixel / 1000 );
     116             :         }
     117             :     }
     118             : 
     119           0 :     if ( nRet < mpImpl->mnMinZoom )
     120           0 :         nRet = mpImpl->mnMinZoom;
     121           0 :     else if ( nRet > mpImpl->mnMaxZoom )
     122           0 :         nRet = mpImpl->mnMaxZoom;
     123             : 
     124           0 :     return nRet;
     125             : }
     126             : 
     127             : // returns the offset to the left control border
     128        4983 : long SvxZoomSliderControl::Zoom2Offset( sal_uInt16 nCurrentZoom ) const
     129             : {
     130        4983 :     const long nControlWidth = getControlRect().GetWidth();
     131        4983 :     long nRet = nSliderXOffset;
     132             : 
     133        4983 :     const long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
     134             : 
     135        4983 :     if ( nCurrentZoom <= mpImpl->mnSliderCenter )
     136             :     {
     137        4943 :         nCurrentZoom = nCurrentZoom - mpImpl->mnMinZoom;
     138        4943 :         const long nFirstHalfRange = mpImpl->mnSliderCenter - mpImpl->mnMinZoom;
     139        4943 :         const long nSliderPixelPerZoomPercent = 1000 * nHalfSliderWidth  / nFirstHalfRange;
     140        4943 :         const long nOffset = (nSliderPixelPerZoomPercent * nCurrentZoom) / 1000;
     141        4943 :         nRet += nOffset;
     142             :     }
     143             :     else
     144             :     {
     145          40 :         nCurrentZoom = nCurrentZoom - mpImpl->mnSliderCenter;
     146          40 :         const long nSecondHalfRange = mpImpl->mnMaxZoom - mpImpl->mnSliderCenter;
     147          40 :         const long nSliderPixelPerZoomPercent = 1000 * nHalfSliderWidth  / nSecondHalfRange;
     148          40 :         const long nOffset = (nSliderPixelPerZoomPercent * nCurrentZoom) / 1000;
     149          40 :         nRet += nHalfSliderWidth + nOffset;
     150             :     }
     151             : 
     152        4983 :     return nRet;
     153             : }
     154             : 
     155        1464 : SvxZoomSliderControl::SvxZoomSliderControl( sal_uInt16 _nSlotId,  sal_uInt16 _nId, StatusBar& _rStb ) :
     156             :     SfxStatusBarControl( _nSlotId, _nId, _rStb ),
     157        1464 :     mpImpl( new SvxZoomSliderControl_Impl )
     158             : {
     159        1464 :     mpImpl->maSliderButton   = Image( SVX_RES( RID_SVXBMP_SLIDERBUTTON   ) );
     160        1464 :     mpImpl->maIncreaseButton = Image( SVX_RES( RID_SVXBMP_SLIDERINCREASE ) );
     161        1464 :     mpImpl->maDecreaseButton = Image( SVX_RES( RID_SVXBMP_SLIDERDECREASE ) );
     162             : 
     163             : //#ifndef MACOSX
     164        1464 :     if ( _rStb.GetDPIScaleFactor() > 1)
     165             :     {
     166           0 :         Image arr[3] = {mpImpl->maSliderButton, mpImpl->maIncreaseButton, mpImpl->maDecreaseButton};
     167             : 
     168           0 :         for (int i = 0; i < 3; i++)
     169             :         {
     170           0 :             BitmapEx b = arr[i].GetBitmapEx();
     171             :             //Use Lanczos scaling for the slider button because it does a better job with circles
     172           0 :             b.Scale(_rStb.GetDPIScaleFactor(), _rStb.GetDPIScaleFactor(), i == 0 ? BMP_SCALE_LANCZOS : BMP_SCALE_FAST);
     173           0 :             arr[i] = Image(b);
     174           0 :         }
     175           0 :         mpImpl->maSliderButton = arr[0];
     176           0 :         mpImpl->maIncreaseButton = arr[1];
     177           0 :         mpImpl->maDecreaseButton = arr[2];
     178             :     }
     179             : //#endif
     180        1464 : }
     181             : 
     182        2928 : SvxZoomSliderControl::~SvxZoomSliderControl()
     183             : {
     184        2928 : }
     185             : 
     186        1684 : void SvxZoomSliderControl::StateChanged( sal_uInt16 /*nSID*/, SfxItemState eState, const SfxPoolItem* pState )
     187             : {
     188        1684 :     if ( (SfxItemState::DEFAULT != eState) || pState->ISA( SfxVoidItem ) )
     189             :     {
     190           0 :         GetStatusBar().SetItemText( GetId(), "" );
     191           0 :         mpImpl->mbValuesSet   = false;
     192             :     }
     193             :     else
     194             :     {
     195             :         OSL_ENSURE( pState->ISA( SvxZoomSliderItem ), "invalid item type: should be a SvxZoomSliderItem" );
     196        1684 :         mpImpl->mnCurrentZoom = static_cast<const SvxZoomSliderItem*>( pState )->GetValue();
     197        1684 :         mpImpl->mnMinZoom     = static_cast<const SvxZoomSliderItem*>( pState )->GetMinZoom();
     198        1684 :         mpImpl->mnMaxZoom     = static_cast<const SvxZoomSliderItem*>( pState )->GetMaxZoom();
     199        1684 :         mpImpl->mnSliderCenter= 100;
     200        1684 :         mpImpl->mbValuesSet   = true;
     201             : 
     202        1684 :         if ( mpImpl->mnSliderCenter == mpImpl->mnMaxZoom )
     203           0 :             mpImpl->mnSliderCenter = mpImpl->mnMinZoom + (sal_uInt16)((mpImpl->mnMaxZoom - mpImpl->mnMinZoom) * 0.5);
     204             : 
     205             : 
     206             :         DBG_ASSERT( mpImpl->mnMinZoom <= mpImpl->mnCurrentZoom &&
     207             :                     mpImpl->mnMinZoom <  mpImpl->mnSliderCenter &&
     208             :                     mpImpl->mnMaxZoom >= mpImpl->mnCurrentZoom &&
     209             :                     mpImpl->mnMaxZoom > mpImpl->mnSliderCenter,
     210             :                     "Looks like the zoom slider item is corrupted" );
     211             : 
     212        1684 :         const com::sun::star::uno::Sequence < sal_Int32 > rSnappingPoints = static_cast<const SvxZoomSliderItem*>( pState )->GetSnappingPoints();
     213        1684 :         mpImpl->maSnappingPointOffsets.clear();
     214        1684 :         mpImpl->maSnappingPointZooms.clear();
     215             : 
     216             :         // get all snapping points:
     217        3368 :         std::set< sal_uInt16 > aTmpSnappingPoints;
     218        5651 :         for ( sal_uInt16 j = 0; j < rSnappingPoints.getLength(); ++j )
     219             :         {
     220        3967 :             const sal_Int32 nSnappingPoint = rSnappingPoints[j];
     221        3967 :             aTmpSnappingPoints.insert( (sal_uInt16)nSnappingPoint );
     222             :         }
     223             : 
     224             :         // remove snapping points that are to close to each other:
     225        1684 :         std::set< sal_uInt16 >::iterator aSnappingPointIter;
     226        1684 :         long nLastOffset = 0;
     227             : 
     228        4618 :         for ( aSnappingPointIter = aTmpSnappingPoints.begin(); aSnappingPointIter != aTmpSnappingPoints.end(); ++aSnappingPointIter )
     229             :         {
     230        2934 :             const sal_uInt16 nCurrent = *aSnappingPointIter;
     231        2934 :             const long nCurrentOffset = Zoom2Offset( nCurrent );
     232             : 
     233        2934 :             if ( nCurrentOffset - nLastOffset >= nSnappingPointsMinDist )
     234             :             {
     235        1926 :                 mpImpl->maSnappingPointOffsets.push_back( nCurrentOffset );
     236        1926 :                 mpImpl->maSnappingPointZooms.push_back( nCurrent );
     237        1926 :                 nLastOffset = nCurrentOffset;
     238             :             }
     239        1684 :         }
     240             :     }
     241             : 
     242        1684 :     if (!mpImpl->mbOmitPaint)
     243        1684 :         forceRepaint();
     244        1684 : }
     245             : 
     246        2049 : void SvxZoomSliderControl::Paint( const UserDrawEvent& rUsrEvt )
     247             : {
     248        2049 :     if ( !mpImpl->mbValuesSet || mpImpl->mbOmitPaint )
     249        2049 :         return;
     250             : 
     251        2049 :     const Rectangle     aControlRect = getControlRect();
     252        2049 :     OutputDevice*       pDev =  rUsrEvt.GetDevice();
     253        2049 :     Rectangle           aRect = rUsrEvt.GetRect();
     254        2049 :     Rectangle           aSlider = aRect;
     255             : 
     256        2049 :     long nSliderHeight  = 2 * pDev->GetDPIScaleFactor();
     257        2049 :     long nSnappingHeight = 4 * pDev->GetDPIScaleFactor();
     258             : 
     259        2049 :     aSlider.Top()   += (aControlRect.GetHeight() - nSliderHeight)/2;
     260        2049 :     aSlider.Bottom() = aSlider.Top() + nSliderHeight - 1;
     261        2049 :     aSlider.Left()  += nSliderXOffset;
     262        2049 :     aSlider.Right() -= nSliderXOffset;
     263             : 
     264        2049 :     Color               aOldLineColor = pDev->GetLineColor();
     265        2049 :     Color               aOldFillColor = pDev->GetFillColor();
     266             : 
     267        2049 :     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
     268        2049 :     pDev->SetLineColor( rStyleSettings.GetShadowColor() );
     269        2049 :     pDev->SetFillColor( rStyleSettings.GetShadowColor() );
     270             : 
     271             : 
     272             :     // draw snapping points:
     273        2049 :     std::vector< long >::iterator aSnappingPointIter;
     274       13362 :     for ( aSnappingPointIter = mpImpl->maSnappingPointOffsets.begin();
     275        8908 :           aSnappingPointIter != mpImpl->maSnappingPointOffsets.end();
     276             :           ++aSnappingPointIter )
     277             :     {
     278        2405 :         long nSnapPosX = aRect.Left() + *aSnappingPointIter;
     279             : 
     280        2405 :         pDev->DrawRect( Rectangle( nSnapPosX - 1, aSlider.Top() - nSnappingHeight,
     281        4810 :                     nSnapPosX, aSlider.Bottom() + nSnappingHeight ) );
     282             :     }
     283             : 
     284             :     // draw slider
     285        2049 :     pDev->DrawRect( aSlider );
     286             : 
     287             :     // draw slider button
     288        2049 :     Point aImagePoint = aRect.TopLeft();
     289        2049 :     aImagePoint.X() += Zoom2Offset( mpImpl->mnCurrentZoom );
     290        2049 :     aImagePoint.X() -= mpImpl->maSliderButton.GetSizePixel().Width()/2;
     291        2049 :     aImagePoint.Y() += (aControlRect.GetHeight() - mpImpl->maSliderButton.GetSizePixel().Height())/2;
     292        2049 :     pDev->DrawImage( aImagePoint, mpImpl->maSliderButton );
     293             : 
     294             :     // draw decrease button
     295        2049 :     aImagePoint = aRect.TopLeft();
     296        2049 :     aImagePoint.X() += (nSliderXOffset - mpImpl->maDecreaseButton.GetSizePixel().Width())/2;
     297        2049 :     aImagePoint.Y() += (aControlRect.GetHeight() - mpImpl->maDecreaseButton.GetSizePixel().Height())/2;
     298        2049 :     pDev->DrawImage( aImagePoint, mpImpl->maDecreaseButton );
     299             : 
     300             :     // draw increase button
     301        2049 :     aImagePoint.X() = aRect.TopLeft().X() + aControlRect.GetWidth() - mpImpl->maIncreaseButton.GetSizePixel().Width() - (nSliderXOffset - mpImpl->maIncreaseButton.GetSizePixel().Height())/2;
     302        2049 :     pDev->DrawImage( aImagePoint, mpImpl->maIncreaseButton );
     303             : 
     304        2049 :     pDev->SetLineColor( aOldLineColor );
     305        2049 :     pDev->SetFillColor( aOldFillColor );
     306             : }
     307             : 
     308           0 : bool SvxZoomSliderControl::MouseButtonDown( const MouseEvent & rEvt )
     309             : {
     310           0 :     if ( !mpImpl->mbValuesSet )
     311           0 :         return true;
     312             : 
     313           0 :     const Rectangle aControlRect = getControlRect();
     314           0 :     const Point aPoint = rEvt.GetPosPixel();
     315           0 :     const sal_Int32 nXDiff = aPoint.X() - aControlRect.Left();
     316             : 
     317           0 :     long nIncDecWidth   = mpImpl->maIncreaseButton.GetSizePixel().Width();
     318             : 
     319           0 :     const long nButtonLeftOffset = (nSliderXOffset - nIncDecWidth)/2;
     320           0 :     const long nButtonRightOffset = (nSliderXOffset + nIncDecWidth)/2;
     321             : 
     322           0 :     const long nOldZoom = mpImpl->mnCurrentZoom;
     323             : 
     324             :     // click to - button
     325           0 :     if ( nXDiff >= nButtonLeftOffset && nXDiff <= nButtonRightOffset )
     326           0 :         mpImpl->mnCurrentZoom = basegfx::zoomtools::zoomOut( static_cast<int>(mpImpl->mnCurrentZoom) );
     327             :     // click to + button
     328           0 :     else if ( nXDiff >= aControlRect.GetWidth() - nSliderXOffset + nButtonLeftOffset &&
     329           0 :               nXDiff <= aControlRect.GetWidth() - nSliderXOffset + nButtonRightOffset )
     330           0 :         mpImpl->mnCurrentZoom = basegfx::zoomtools::zoomIn( static_cast<int>(mpImpl->mnCurrentZoom) );
     331             :     // click to slider
     332           0 :     else if( nXDiff >= nSliderXOffset && nXDiff <= aControlRect.GetWidth() - nSliderXOffset )
     333           0 :         mpImpl->mnCurrentZoom = Offset2Zoom( nXDiff );
     334             : 
     335           0 :     if ( mpImpl->mnCurrentZoom < mpImpl->mnMinZoom )
     336           0 :         mpImpl->mnCurrentZoom = mpImpl->mnMinZoom;
     337           0 :     else if ( mpImpl->mnCurrentZoom > mpImpl->mnMaxZoom )
     338           0 :         mpImpl->mnCurrentZoom = mpImpl->mnMaxZoom;
     339             : 
     340           0 :     if ( nOldZoom == mpImpl->mnCurrentZoom )
     341           0 :         return true;
     342             : 
     343           0 :     repaintAndExecute();
     344             : 
     345           0 :     return true;
     346             : }
     347             : 
     348           0 : bool SvxZoomSliderControl::MouseMove( const MouseEvent & rEvt )
     349             : {
     350           0 :     if ( !mpImpl->mbValuesSet )
     351           0 :         return true;
     352             : 
     353           0 :     const short nButtons = rEvt.GetButtons();
     354             : 
     355             :     // check mouse move with button pressed
     356           0 :     if ( 1 == nButtons )
     357             :     {
     358           0 :         const Rectangle aControlRect = getControlRect();
     359           0 :         const Point aPoint = rEvt.GetPosPixel();
     360           0 :         const sal_Int32 nXDiff = aPoint.X() - aControlRect.Left();
     361             : 
     362           0 :         if ( nXDiff >= nSliderXOffset && nXDiff <= aControlRect.GetWidth() - nSliderXOffset )
     363             :         {
     364           0 :             mpImpl->mnCurrentZoom = Offset2Zoom( nXDiff );
     365             : 
     366           0 :             repaintAndExecute();
     367             :         }
     368             :     }
     369             : 
     370           0 :     return true;
     371             : }
     372             : 
     373        1684 : void SvxZoomSliderControl::forceRepaint() const
     374             : {
     375        1684 :     if (GetStatusBar().AreItemsVisible())
     376        1684 :         GetStatusBar().SetItemData(GetId(), 0);
     377        1684 : }
     378             : 
     379           0 : void SvxZoomSliderControl::repaintAndExecute()
     380             : {
     381           0 :     forceRepaint();
     382             : 
     383           0 :     mpImpl->mbOmitPaint = true; // optimization: paint before executing command,
     384             :                                 // then omit painting which is triggered by the execute function
     385             : 
     386             :     // commit state change
     387           0 :     SvxZoomSliderItem aZoomSliderItem(mpImpl->mnCurrentZoom);
     388             : 
     389           0 :     css::uno::Any any;
     390           0 :     aZoomSliderItem.QueryValue(any);
     391             : 
     392           0 :     css::uno::Sequence<css::beans::PropertyValue> aArgs(1);
     393           0 :     aArgs[0].Name = "ZoomSlider";
     394           0 :     aArgs[0].Value = any;
     395             : 
     396           0 :     execute(aArgs);
     397             : 
     398           0 :     mpImpl->mbOmitPaint = false;
     399         594 : }
     400             : 
     401             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10