blob: ef59488d395d7cb74ebe8065d0865731efc36fe8 [file] [log] [blame]
/**************************************************************
*
* 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.
*
*************************************************************/
#include "precompiled_sc.hxx"
#ifndef _SC_ZOOMSLIDERTBCONTRL_HXX
#include "tbzoomsliderctrl.hxx"
#endif
#ifndef _SV_IMAGE_HXX
#include <vcl/image.hxx>
#endif
#ifndef _SV_TOOLBOX_HXX
#include <vcl/toolbox.hxx>
#endif
#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _SV_GRADIENT_HXX
#include <vcl/gradient.hxx>
#endif
#include <svl/itemset.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/objsh.hxx>
#include <svx/zoomslideritem.hxx>
#include <svx/dialmgr.hxx>
#include <svx/dialogs.hrc>
#include <set>
#include "docsh.hxx"
#include "stlpool.hxx"
#include "scitems.hxx"
#include "printfun.hxx"
//========================================================================
// class ScZoomSliderControl ---------------------------------------
//========================================================================
// -----------------------------------------------------------------------
SFX_IMPL_TOOLBOX_CONTROL( ScZoomSliderControl, SvxZoomSliderItem );
// -----------------------------------------------------------------------
ScZoomSliderControl::ScZoomSliderControl(
sal_uInt16 nSlotId,
sal_uInt16 nId,
ToolBox& rTbx )
:SfxToolBoxControl( nSlotId, nId, rTbx )
{
rTbx.Invalidate();
}
// -----------------------------------------------------------------------
__EXPORT ScZoomSliderControl::~ScZoomSliderControl()
{
}
// -----------------------------------------------------------------------
void ScZoomSliderControl::StateChanged( sal_uInt16 /*nSID*/, SfxItemState eState,
const SfxPoolItem* pState )
{
sal_uInt16 nId = GetId();
ToolBox& rTbx = GetToolBox();
ScZoomSliderWnd* pBox = (ScZoomSliderWnd*)(rTbx.GetItemWindow( nId ));
DBG_ASSERT( pBox ,"Control not found!" );
if ( SFX_ITEM_AVAILABLE != eState || pState->ISA( SfxVoidItem ) )
{
SvxZoomSliderItem aZoomSliderItem( 100 );
pBox->Disable();
pBox->UpdateFromItem( &aZoomSliderItem );
}
else
{
pBox->Enable();
DBG_ASSERT( pState->ISA( SvxZoomSliderItem ), "invalid item type" );
const SvxZoomSliderItem* pZoomSliderItem = dynamic_cast< const SvxZoomSliderItem* >( pState );
DBG_ASSERT( pZoomSliderItem, "Sc::ScZoomSliderControl::StateChanged(), wrong item type!" );
if( pZoomSliderItem )
pBox->UpdateFromItem( pZoomSliderItem );
}
}
// -----------------------------------------------------------------------
Window* ScZoomSliderControl::CreateItemWindow( Window *pParent )
{
// #i98000# Don't try to get a value via SfxViewFrame::Current here.
// The view's value is always notified via StateChanged later.
ScZoomSliderWnd* pSlider = new ScZoomSliderWnd( pParent,
::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider >( m_xFrame->getController(),
::com::sun::star::uno::UNO_QUERY ), m_xFrame, 100 );
return pSlider;
}
// -----------------------------------------------------------------------
struct ScZoomSliderWnd::ScZoomSliderWnd_Impl
{
sal_uInt16 mnCurrentZoom;
sal_uInt16 mnMinZoom;
sal_uInt16 mnMaxZoom;
sal_uInt16 mnSliderCenter;
std::vector< long > maSnappingPointOffsets;
std::vector< sal_uInt16 > maSnappingPointZooms;
Image maSliderButton;
Image maIncreaseButton;
Image maDecreaseButton;
bool mbValuesSet;
bool mbOmitPaint;
ScZoomSliderWnd_Impl( sal_uInt16 nCurrentZoom ) :
mnCurrentZoom( nCurrentZoom ),
mnMinZoom( 10 ),
mnMaxZoom( 400 ),
mnSliderCenter( 100 ),
maSnappingPointOffsets(),
maSnappingPointZooms(),
maSliderButton(),
maIncreaseButton(),
maDecreaseButton(),
mbValuesSet( true ),
mbOmitPaint( false )
{
}
};
// -----------------------------------------------------------------------
const long nButtonWidth = 10;
const long nButtonHeight = 10;
const long nIncDecWidth = 11;
const long nIncDecHeight = 11;
const long nSliderHeight = 2; //
const long nSliderWidth = 4; //
const long nSnappingHeight = 4;
const long nSliderXOffset = 20;
const long nSnappingEpsilon = 5; // snapping epsilon in pixels
const long nSnappingPointsMinDist = nSnappingEpsilon; // minimum distance of two adjacent snapping points
// -----------------------------------------------------------------------
sal_uInt16 ScZoomSliderWnd::Offset2Zoom( long nOffset ) const
{
Size aSliderWindowSize = GetOutputSizePixel();
const long nControlWidth = aSliderWindowSize.Width();
sal_uInt16 nRet = 0;
if( nOffset < nSliderXOffset )
return mpImpl->mnMinZoom;
if( nOffset > nControlWidth - nSliderXOffset )
return mpImpl->mnMaxZoom;
// check for snapping points:
sal_uInt16 nCount = 0;
std::vector< long >::iterator aSnappingPointIter;
for ( aSnappingPointIter = mpImpl->maSnappingPointOffsets.begin();
aSnappingPointIter != mpImpl->maSnappingPointOffsets.end();
++aSnappingPointIter )
{
const long nCurrent = *aSnappingPointIter;
if ( Abs(nCurrent - nOffset) < nSnappingEpsilon )
{
nOffset = nCurrent;
nRet = mpImpl->maSnappingPointZooms[ nCount ];
break;
}
++nCount;
}
if( 0 == nRet )
{
if( nOffset < nControlWidth / 2 )
{
// first half of slider
const long nFirstHalfRange = mpImpl->mnSliderCenter - mpImpl->mnMinZoom;
const long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
const long nZoomPerSliderPixel = (1000 * nFirstHalfRange) / nHalfSliderWidth;
const long nOffsetToSliderLeft = nOffset - nSliderXOffset;
nRet = mpImpl->mnMinZoom + sal_uInt16( nOffsetToSliderLeft * nZoomPerSliderPixel / 1000 );
}
else
{
// second half of slider
const long nSecondHalfRange = mpImpl->mnMaxZoom - mpImpl->mnSliderCenter;
const long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
const long nZoomPerSliderPixel = 1000 * nSecondHalfRange / nHalfSliderWidth;
const long nOffsetToSliderCenter = nOffset - nControlWidth/2;
nRet = mpImpl->mnSliderCenter + sal_uInt16( nOffsetToSliderCenter * nZoomPerSliderPixel / 1000 );
}
}
if( nRet < mpImpl->mnMinZoom )
return mpImpl->mnMinZoom;
else if( nRet > mpImpl->mnMaxZoom )
return mpImpl->mnMaxZoom;
return nRet;
}
// -----------------------------------------------------------------------
long ScZoomSliderWnd::Zoom2Offset( sal_uInt16 nCurrentZoom ) const
{
Size aSliderWindowSize = GetOutputSizePixel();
const long nControlWidth = aSliderWindowSize.Width();
long nRect = nSliderXOffset;
const long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
if( nCurrentZoom <= mpImpl->mnSliderCenter )
{
nCurrentZoom = nCurrentZoom - mpImpl->mnMinZoom;
const long nFirstHalfRange = mpImpl->mnSliderCenter - mpImpl->mnMinZoom;
const long nSliderPixelPerZoomPercent = 1000 * nHalfSliderWidth / nFirstHalfRange;
const long nOffset = (nSliderPixelPerZoomPercent * nCurrentZoom) / 1000;
nRect += nOffset;
}
else
{
nCurrentZoom = nCurrentZoom - mpImpl->mnSliderCenter;
const long nSecondHalfRange = mpImpl->mnMaxZoom - mpImpl->mnSliderCenter;
const long nSliderPixelPerZoomPercent = 1000 * nHalfSliderWidth / nSecondHalfRange;
const long nOffset = (nSliderPixelPerZoomPercent * nCurrentZoom) / 1000;
nRect += nHalfSliderWidth + nOffset;
}
return nRect;
}
// -----------------------------------------------------------------------
ScZoomSliderWnd::ScZoomSliderWnd( Window* pParent, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider >& rDispatchProvider,
const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& _xFrame , sal_uInt16 nCurrentZoom ):
Window( pParent ),
mpImpl( new ScZoomSliderWnd_Impl( nCurrentZoom ) ),
aLogicalSize( 115, 40 ),
m_xDispatchProvider( rDispatchProvider ),
m_xFrame( _xFrame )
{
sal_Bool bIsHC = GetSettings().GetStyleSettings().GetHighContrastMode();
mpImpl->maSliderButton = Image( SVX_RES( bIsHC ? RID_SVXBMP_SLIDERBUTTON_HC : RID_SVXBMP_SLIDERBUTTON ) );
mpImpl->maIncreaseButton = Image( SVX_RES( bIsHC ? RID_SVXBMP_SLIDERINCREASE_HC : RID_SVXBMP_SLIDERINCREASE ) );
mpImpl->maDecreaseButton = Image( SVX_RES( bIsHC ? RID_SVXBMP_SLIDERDECREASE_HC : RID_SVXBMP_SLIDERDECREASE ) );
Size aSliderSize = LogicToPixel( Size( aLogicalSize), MapMode( MAP_10TH_MM ) );
SetSizePixel( Size( aSliderSize.Width() * nSliderWidth-1, aSliderSize.Height() + nSliderHeight ) );
}
// -----------------------------------------------------------------------
ScZoomSliderWnd::~ScZoomSliderWnd()
{
delete mpImpl;
}
// -----------------------------------------------------------------------
void ScZoomSliderWnd::MouseButtonDown( const MouseEvent& rMEvt )
{
if ( !mpImpl->mbValuesSet )
return ;
Size aSliderWindowSize = GetOutputSizePixel();
const Point aPoint = rMEvt.GetPosPixel();
const long nButtonLeftOffset = ( nSliderXOffset - nIncDecWidth )/2;
const long nButtonRightOffset = ( nSliderXOffset + nIncDecWidth )/2;
const long nOldZoom = mpImpl->mnCurrentZoom;
// click to - button
if ( aPoint.X() >= nButtonLeftOffset && aPoint.X() <= nButtonRightOffset )
{
mpImpl->mnCurrentZoom = mpImpl->mnCurrentZoom - 5;
}
// click to + button
else if ( aPoint.X() >= aSliderWindowSize.Width() - nSliderXOffset + nButtonLeftOffset &&
aPoint.X() <= aSliderWindowSize.Width() - nSliderXOffset + nButtonRightOffset )
{
mpImpl->mnCurrentZoom = mpImpl->mnCurrentZoom + 5;
}
else if( aPoint.X() >= nSliderXOffset && aPoint.X() <= aSliderWindowSize.Width() - nSliderXOffset )
{
mpImpl->mnCurrentZoom = Offset2Zoom( aPoint.X() );
}
if( mpImpl->mnCurrentZoom < mpImpl->mnMinZoom )
mpImpl->mnCurrentZoom = mpImpl->mnMinZoom;
else if( mpImpl->mnCurrentZoom > mpImpl->mnMaxZoom )
mpImpl->mnCurrentZoom = mpImpl->mnMaxZoom;
if( nOldZoom == mpImpl->mnCurrentZoom )
return ;
Rectangle aRect( Point( 0, 0 ), aSliderWindowSize );
Paint( aRect );
mpImpl->mbOmitPaint = true;
SvxZoomSliderItem aZoomSliderItem( mpImpl->mnCurrentZoom );
::com::sun::star::uno::Any a;
aZoomSliderItem.QueryValue( a );
::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aArgs( 1 );
aArgs[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ScalingFactor" ));
aArgs[0].Value = a;
SfxToolBoxControl::Dispatch( m_xDispatchProvider, String::CreateFromAscii(".uno:ScalingFactor"), aArgs );
mpImpl->mbOmitPaint = false;
}
// -----------------------------------------------------------------------
void ScZoomSliderWnd::MouseMove( const MouseEvent& rMEvt )
{
if ( !mpImpl->mbValuesSet )
return ;
Size aSliderWindowSize = GetOutputSizePixel();
const long nControlWidth = aSliderWindowSize.Width();
const short nButtons = rMEvt.GetButtons();
// check mouse move with button pressed
if ( 1 == nButtons )
{
const Point aPoint = rMEvt.GetPosPixel();
if ( aPoint.X() >= nSliderXOffset && aPoint.X() <= nControlWidth - nSliderXOffset )
{
mpImpl->mnCurrentZoom = Offset2Zoom( aPoint.X() );
Rectangle aRect( Point( 0, 0 ), aSliderWindowSize );
Paint( aRect );
mpImpl->mbOmitPaint = true; // optimization: paint before executing command,
// commit state change
SvxZoomSliderItem aZoomSliderItem( mpImpl->mnCurrentZoom );
::com::sun::star::uno::Any a;
aZoomSliderItem.QueryValue( a );
::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aArgs( 1 );
aArgs[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ScalingFactor" ));
aArgs[0].Value = a;
SfxToolBoxControl::Dispatch( m_xDispatchProvider, String::CreateFromAscii(".uno:ScalingFactor"), aArgs );
mpImpl->mbOmitPaint = false;
}
}
}
// -----------------------------------------------------------------------
void ScZoomSliderWnd::UpdateFromItem( const SvxZoomSliderItem* pZoomSliderItem )
{
if( pZoomSliderItem )
{
mpImpl->mnCurrentZoom = pZoomSliderItem->GetValue();
mpImpl->mnMinZoom = pZoomSliderItem->GetMinZoom();
mpImpl->mnMaxZoom = pZoomSliderItem->GetMaxZoom();
DBG_ASSERT( mpImpl->mnMinZoom <= mpImpl->mnCurrentZoom &&
mpImpl->mnMinZoom < mpImpl->mnSliderCenter &&
mpImpl->mnMaxZoom >= mpImpl->mnCurrentZoom &&
mpImpl->mnMaxZoom > mpImpl->mnSliderCenter,
"Looks like the zoom slider item is corrupted" );
const com::sun::star::uno::Sequence < sal_Int32 > rSnappingPoints = pZoomSliderItem->GetSnappingPoints();
mpImpl->maSnappingPointOffsets.clear();
mpImpl->maSnappingPointZooms.clear();
// get all snapping points:
std::set< sal_uInt16 > aTmpSnappingPoints;
for ( sal_uInt16 j = 0; j < rSnappingPoints.getLength(); ++j )
{
const sal_Int32 nSnappingPoint = rSnappingPoints[j];
aTmpSnappingPoints.insert( (sal_uInt16)nSnappingPoint );
}
// remove snapping points that are to close to each other:
std::set< sal_uInt16 >::iterator aSnappingPointIter;
long nLastOffset = 0;
for ( aSnappingPointIter = aTmpSnappingPoints.begin(); aSnappingPointIter != aTmpSnappingPoints.end(); ++aSnappingPointIter )
{
const sal_uInt16 nCurrent = *aSnappingPointIter;
const long nCurrentOffset = Zoom2Offset( nCurrent );
if ( nCurrentOffset - nLastOffset >= nSnappingPointsMinDist )
{
mpImpl->maSnappingPointOffsets.push_back( nCurrentOffset );
mpImpl->maSnappingPointZooms.push_back( nCurrent );
nLastOffset = nCurrentOffset;
}
}
}
Size aSliderWindowSize = GetOutputSizePixel();
Rectangle aRect( Point( 0, 0 ), aSliderWindowSize );
if ( !mpImpl->mbOmitPaint )
Paint(aRect);
}
// -----------------------------------------------------------------------
void ScZoomSliderWnd::Paint( const Rectangle& rRect )
{
DoPaint( rRect );
}
// -----------------------------------------------------------------------
void ScZoomSliderWnd::DoPaint( const Rectangle& /*rRect*/ )
{
if( mpImpl->mbOmitPaint )
return;
Size aSliderWindowSize = GetOutputSizePixel();
Rectangle aRect( Point( 0, 0 ), aSliderWindowSize );
VirtualDevice* pVDev = new VirtualDevice( *this );
pVDev->SetOutputSizePixel( aSliderWindowSize );
Rectangle aSlider = aRect;
aSlider.Top() += ( aSliderWindowSize.Height() - nSliderHeight )/2 - 1;
aSlider.Bottom() = aSlider.Top() + nSliderHeight;
aSlider.Left() += nSliderXOffset;
aSlider.Right() -= nSliderXOffset;
Rectangle aFirstLine( aSlider );
aFirstLine.Bottom() = aFirstLine.Top();
Rectangle aSecondLine( aSlider );
aSecondLine.Top() = aSecondLine.Bottom();
Rectangle aLeft( aSlider );
aLeft.Right() = aLeft.Left();
Rectangle aRight( aSlider );
aRight.Left() = aRight.Right();
// draw VirtualDevice's background color
Color aStartColor,aEndColor;
aStartColor = GetSettings().GetStyleSettings().GetFaceColor();
aEndColor = GetSettings().GetStyleSettings().GetFaceColor();
if( aEndColor.IsDark() )
aStartColor = aEndColor;
Gradient g;
g.SetAngle( 0 );
g.SetStyle( GRADIENT_LINEAR );
g.SetStartColor( aStartColor );
g.SetEndColor( aEndColor );
pVDev->DrawGradient( aRect, g );
// draw slider
pVDev->SetLineColor( Color ( COL_WHITE ) );
pVDev->DrawRect( aSecondLine );
pVDev->DrawRect( aRight );
pVDev->SetLineColor( Color( COL_GRAY ) );
pVDev->DrawRect( aFirstLine );
pVDev->DrawRect( aLeft );
// draw snapping points:
std::vector< long >::iterator aSnappingPointIter;
for ( aSnappingPointIter = mpImpl->maSnappingPointOffsets.begin();
aSnappingPointIter != mpImpl->maSnappingPointOffsets.end();
++aSnappingPointIter )
{
pVDev->SetLineColor( Color( COL_GRAY ) );
Rectangle aSnapping( aRect );
aSnapping.Bottom() = aSlider.Top();
aSnapping.Top() = aSnapping.Bottom() - nSnappingHeight;
aSnapping.Left() += *aSnappingPointIter;
aSnapping.Right() = aSnapping.Left();
pVDev->DrawRect( aSnapping );
aSnapping.Top() += nSnappingHeight + nSliderHeight;
aSnapping.Bottom() += nSnappingHeight + nSliderHeight;
pVDev->DrawRect( aSnapping );
}
// draw slider button
Point aImagePoint = aRect.TopLeft();
aImagePoint.X() += Zoom2Offset( mpImpl->mnCurrentZoom );
aImagePoint.X() -= nButtonWidth/2;
aImagePoint.Y() += ( aSliderWindowSize.Height() - nButtonHeight)/2;
pVDev->DrawImage( aImagePoint, mpImpl->maSliderButton );
// draw decrease button
aImagePoint = aRect.TopLeft();
aImagePoint.X() += (nSliderXOffset - nIncDecWidth)/2;
aImagePoint.Y() += ( aSliderWindowSize.Height() - nIncDecHeight)/2;
pVDev->DrawImage( aImagePoint, mpImpl->maDecreaseButton );
// draw increase button
aImagePoint.X() = aRect.TopLeft().X() + aSliderWindowSize.Width() - nIncDecWidth - (nSliderXOffset - nIncDecWidth)/2;
pVDev->DrawImage( aImagePoint, mpImpl->maIncreaseButton );
DrawOutDev( Point(0, 0), aSliderWindowSize, Point(0, 0), aSliderWindowSize, *pVDev );
delete pVDev;
}
// -----------------------------------------------------------------------