1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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 <svx/zoomslideritem.hxx>
26 #include <svx/dialmgr.hxx>
27 #include <svx/dialogs.hrc>
29 #include <basegfx/tools/zoomtools.hxx>
33 // -----------------------------------------------------------------------
35 SFX_IMPL_STATUSBAR_CONTROL( SvxZoomSliderControl
, SvxZoomSliderItem
);
37 // -----------------------------------------------------------------------
39 struct SvxZoomSliderControl::SvxZoomSliderControl_Impl
41 sal_uInt16 mnCurrentZoom
;
44 sal_uInt16 mnSliderCenter
;
45 std::vector
< long > maSnappingPointOffsets
;
46 std::vector
< sal_uInt16
> maSnappingPointZooms
;
48 Image maIncreaseButton
;
49 Image maDecreaseButton
;
53 SvxZoomSliderControl_Impl() :
58 maSnappingPointOffsets(),
59 maSnappingPointZooms(),
64 mbOmitPaint( false ) {}
67 // -----------------------------------------------------------------------
69 const long nButtonWidth
= 10;
70 const long nButtonHeight
= 10;
71 const long nIncDecWidth
= 10;
72 const long nIncDecHeight
= 10;
73 const long nSliderHeight
= 2;
74 const long nSnappingHeight
= 4;
75 const long nSliderXOffset
= 20;
76 const long nSnappingEpsilon
= 5; // snapping epsilon in pixels
77 const long nSnappingPointsMinDist
= nSnappingEpsilon
; // minimum distance of two adjacent snapping points
79 // -----------------------------------------------------------------------
81 // nOffset referes to the origin of the control:
83 sal_uInt16
SvxZoomSliderControl::Offset2Zoom( long nOffset
) const
85 const long nControlWidth
= getControlRect().GetWidth();
88 if ( nOffset
< nSliderXOffset
)
89 return mpImpl
->mnMinZoom
;
91 if ( nOffset
> nControlWidth
- nSliderXOffset
)
92 return mpImpl
->mnMaxZoom
;
94 // check for snapping points:
95 sal_uInt16 nCount
= 0;
96 std::vector
< long >::iterator aSnappingPointIter
;
97 for ( aSnappingPointIter
= mpImpl
->maSnappingPointOffsets
.begin();
98 aSnappingPointIter
!= mpImpl
->maSnappingPointOffsets
.end();
99 ++aSnappingPointIter
)
101 const long nCurrent
= *aSnappingPointIter
;
102 if ( std::abs(nCurrent
- nOffset
) < nSnappingEpsilon
)
105 nRet
= mpImpl
->maSnappingPointZooms
[ nCount
];
113 if ( nOffset
< nControlWidth
/ 2 )
115 // first half of slider
116 const long nFirstHalfRange
= mpImpl
->mnSliderCenter
- mpImpl
->mnMinZoom
;
117 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
118 const long nZoomPerSliderPixel
= (1000 * nFirstHalfRange
) / nHalfSliderWidth
;
119 const long nOffsetToSliderLeft
= nOffset
- nSliderXOffset
;
120 nRet
= mpImpl
->mnMinZoom
+ sal_uInt16( nOffsetToSliderLeft
* nZoomPerSliderPixel
/ 1000 );
124 // second half of slider
125 const long nSecondHalfRange
= mpImpl
->mnMaxZoom
- mpImpl
->mnSliderCenter
;
126 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
127 const long nZoomPerSliderPixel
= 1000 * nSecondHalfRange
/ nHalfSliderWidth
;
128 const long nOffsetToSliderCenter
= nOffset
- nControlWidth
/2;
129 nRet
= mpImpl
->mnSliderCenter
+ sal_uInt16( nOffsetToSliderCenter
* nZoomPerSliderPixel
/ 1000 );
133 if ( nRet
< mpImpl
->mnMinZoom
)
134 nRet
= mpImpl
->mnMinZoom
;
135 else if ( nRet
> mpImpl
->mnMaxZoom
)
136 nRet
= mpImpl
->mnMaxZoom
;
141 // returns the offset to the left control border
142 long SvxZoomSliderControl::Zoom2Offset( sal_uInt16 nCurrentZoom
) const
144 const long nControlWidth
= getControlRect().GetWidth();
145 long nRet
= nSliderXOffset
;
147 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
149 if ( nCurrentZoom
<= mpImpl
->mnSliderCenter
)
151 nCurrentZoom
= nCurrentZoom
- mpImpl
->mnMinZoom
;
152 const long nFirstHalfRange
= mpImpl
->mnSliderCenter
- mpImpl
->mnMinZoom
;
153 const long nSliderPixelPerZoomPercent
= 1000 * nHalfSliderWidth
/ nFirstHalfRange
;
154 const long nOffset
= (nSliderPixelPerZoomPercent
* nCurrentZoom
) / 1000;
159 nCurrentZoom
= nCurrentZoom
- mpImpl
->mnSliderCenter
;
160 const long nSecondHalfRange
= mpImpl
->mnMaxZoom
- mpImpl
->mnSliderCenter
;
161 const long nSliderPixelPerZoomPercent
= 1000 * nHalfSliderWidth
/ nSecondHalfRange
;
162 const long nOffset
= (nSliderPixelPerZoomPercent
* nCurrentZoom
) / 1000;
163 nRet
+= nHalfSliderWidth
+ nOffset
;
169 // -----------------------------------------------------------------------
171 SvxZoomSliderControl::SvxZoomSliderControl( sal_uInt16 _nSlotId
, sal_uInt16 _nId
, StatusBar
& _rStb
) :
172 SfxStatusBarControl( _nSlotId
, _nId
, _rStb
),
173 mpImpl( new SvxZoomSliderControl_Impl
)
175 mpImpl
->maSliderButton
= Image( SVX_RES( RID_SVXBMP_SLIDERBUTTON
) );
176 mpImpl
->maIncreaseButton
= Image( SVX_RES( RID_SVXBMP_SLIDERINCREASE
) );
177 mpImpl
->maDecreaseButton
= Image( SVX_RES( RID_SVXBMP_SLIDERDECREASE
) );
180 // -----------------------------------------------------------------------
182 SvxZoomSliderControl::~SvxZoomSliderControl()
187 // -----------------------------------------------------------------------
189 void SvxZoomSliderControl::StateChanged( sal_uInt16
/*nSID*/, SfxItemState eState
, const SfxPoolItem
* pState
)
191 if ( (SFX_ITEM_AVAILABLE
!= eState
) || pState
->ISA( SfxVoidItem
) )
193 GetStatusBar().SetItemText( GetId(), String() );
194 mpImpl
->mbValuesSet
= false;
198 OSL_ENSURE( pState
->ISA( SvxZoomSliderItem
), "invalid item type: should be a SvxZoomSliderItem" );
199 mpImpl
->mnCurrentZoom
= static_cast<const SvxZoomSliderItem
*>( pState
)->GetValue();
200 mpImpl
->mnMinZoom
= static_cast<const SvxZoomSliderItem
*>( pState
)->GetMinZoom();
201 mpImpl
->mnMaxZoom
= static_cast<const SvxZoomSliderItem
*>( pState
)->GetMaxZoom();
202 mpImpl
->mnSliderCenter
= 100;
203 mpImpl
->mbValuesSet
= true;
205 if ( mpImpl
->mnSliderCenter
== mpImpl
->mnMaxZoom
)
206 mpImpl
->mnSliderCenter
= mpImpl
->mnMinZoom
+ (sal_uInt16
)((mpImpl
->mnMaxZoom
- mpImpl
->mnMinZoom
) * 0.5);
209 DBG_ASSERT( mpImpl
->mnMinZoom
<= mpImpl
->mnCurrentZoom
&&
210 mpImpl
->mnMinZoom
< mpImpl
->mnSliderCenter
&&
211 mpImpl
->mnMaxZoom
>= mpImpl
->mnCurrentZoom
&&
212 mpImpl
->mnMaxZoom
> mpImpl
->mnSliderCenter
,
213 "Looks like the zoom slider item is corrupted" );
215 const com::sun::star::uno::Sequence
< sal_Int32
> rSnappingPoints
= static_cast<const SvxZoomSliderItem
*>( pState
)->GetSnappingPoints();
216 mpImpl
->maSnappingPointOffsets
.clear();
217 mpImpl
->maSnappingPointZooms
.clear();
219 // get all snapping points:
220 std::set
< sal_uInt16
> aTmpSnappingPoints
;
221 for ( sal_uInt16 j
= 0; j
< rSnappingPoints
.getLength(); ++j
)
223 const sal_Int32 nSnappingPoint
= rSnappingPoints
[j
];
224 aTmpSnappingPoints
.insert( (sal_uInt16
)nSnappingPoint
);
227 // remove snapping points that are to close to each other:
228 std::set
< sal_uInt16
>::iterator aSnappingPointIter
;
229 long nLastOffset
= 0;
231 for ( aSnappingPointIter
= aTmpSnappingPoints
.begin(); aSnappingPointIter
!= aTmpSnappingPoints
.end(); ++aSnappingPointIter
)
233 const sal_uInt16 nCurrent
= *aSnappingPointIter
;
234 const long nCurrentOffset
= Zoom2Offset( nCurrent
);
236 if ( nCurrentOffset
- nLastOffset
>= nSnappingPointsMinDist
)
238 mpImpl
->maSnappingPointOffsets
.push_back( nCurrentOffset
);
239 mpImpl
->maSnappingPointZooms
.push_back( nCurrent
);
240 nLastOffset
= nCurrentOffset
;
245 if ( !mpImpl
->mbOmitPaint
&& GetStatusBar().AreItemsVisible() )
246 GetStatusBar().SetItemData( GetId(), 0 ); // force repaint
249 // -----------------------------------------------------------------------
251 void SvxZoomSliderControl::Paint( const UserDrawEvent
& rUsrEvt
)
253 if ( !mpImpl
->mbValuesSet
|| mpImpl
->mbOmitPaint
)
256 const Rectangle aControlRect
= getControlRect();
257 OutputDevice
* pDev
= rUsrEvt
.GetDevice();
258 Rectangle aRect
= rUsrEvt
.GetRect();
259 Rectangle aSlider
= aRect
;
261 aSlider
.Top() += (aControlRect
.GetHeight() - nSliderHeight
)/2;
262 aSlider
.Bottom() = aSlider
.Top() + nSliderHeight
- 1;
263 aSlider
.Left() += nSliderXOffset
;
264 aSlider
.Right() -= nSliderXOffset
;
266 Color aOldLineColor
= pDev
->GetLineColor();
267 Color aOldFillColor
= pDev
->GetFillColor();
269 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
270 pDev
->SetLineColor( rStyleSettings
.GetShadowColor() );
271 pDev
->SetFillColor( rStyleSettings
.GetShadowColor() );
273 // draw snapping points:
274 std::vector
< long >::iterator aSnappingPointIter
;
275 for ( aSnappingPointIter
= mpImpl
->maSnappingPointOffsets
.begin();
276 aSnappingPointIter
!= mpImpl
->maSnappingPointOffsets
.end();
277 ++aSnappingPointIter
)
279 long nSnapPosX
= aRect
.Left() + *aSnappingPointIter
;
281 pDev
->DrawRect( Rectangle( nSnapPosX
- 1, aSlider
.Top() - nSnappingHeight
,
282 nSnapPosX
, aSlider
.Bottom() + nSnappingHeight
) );
286 pDev
->DrawRect( aSlider
);
288 // draw slider button
289 Point aImagePoint
= aRect
.TopLeft();
290 aImagePoint
.X() += Zoom2Offset( mpImpl
->mnCurrentZoom
);
291 aImagePoint
.X() -= nButtonWidth
/2;
292 aImagePoint
.Y() += (aControlRect
.GetHeight() - nButtonHeight
)/2;
293 pDev
->DrawImage( aImagePoint
, mpImpl
->maSliderButton
);
295 // draw decrease button
296 aImagePoint
= aRect
.TopLeft();
297 aImagePoint
.X() += (nSliderXOffset
- nIncDecWidth
)/2;
298 aImagePoint
.Y() += (aControlRect
.GetHeight() - nIncDecHeight
)/2;
299 pDev
->DrawImage( aImagePoint
, mpImpl
->maDecreaseButton
);
301 // draw increase button
302 aImagePoint
.X() = aRect
.TopLeft().X() + aControlRect
.GetWidth() - nIncDecWidth
- (nSliderXOffset
- nIncDecWidth
)/2;
303 pDev
->DrawImage( aImagePoint
, mpImpl
->maIncreaseButton
);
305 pDev
->SetLineColor( aOldLineColor
);
306 pDev
->SetFillColor( aOldFillColor
);
309 // -----------------------------------------------------------------------
311 sal_Bool
SvxZoomSliderControl::MouseButtonDown( const MouseEvent
& rEvt
)
313 if ( !mpImpl
->mbValuesSet
)
316 const Rectangle aControlRect
= getControlRect();
317 const Point aPoint
= rEvt
.GetPosPixel();
318 const sal_Int32 nXDiff
= aPoint
.X() - aControlRect
.Left();
320 const long nButtonLeftOffset
= (nSliderXOffset
- nIncDecWidth
)/2;
321 const long nButtonRightOffset
= (nSliderXOffset
+ nIncDecWidth
)/2;
323 const long nOldZoom
= mpImpl
->mnCurrentZoom
;
326 if ( nXDiff
>= nButtonLeftOffset
&& nXDiff
<= nButtonRightOffset
)
327 mpImpl
->mnCurrentZoom
= basegfx::zoomtools::zoomOut( static_cast<int>(mpImpl
->mnCurrentZoom
) );
329 else if ( nXDiff
>= aControlRect
.GetWidth() - nSliderXOffset
+ nButtonLeftOffset
&&
330 nXDiff
<= aControlRect
.GetWidth() - nSliderXOffset
+ nButtonRightOffset
)
331 mpImpl
->mnCurrentZoom
= basegfx::zoomtools::zoomIn( static_cast<int>(mpImpl
->mnCurrentZoom
) );
333 else if( nXDiff
>= nSliderXOffset
&& nXDiff
<= aControlRect
.GetWidth() - nSliderXOffset
)
334 mpImpl
->mnCurrentZoom
= Offset2Zoom( nXDiff
);
336 if ( mpImpl
->mnCurrentZoom
< mpImpl
->mnMinZoom
)
337 mpImpl
->mnCurrentZoom
= mpImpl
->mnMinZoom
;
338 else if ( mpImpl
->mnCurrentZoom
> mpImpl
->mnMaxZoom
)
339 mpImpl
->mnCurrentZoom
= mpImpl
->mnMaxZoom
;
341 if ( nOldZoom
== mpImpl
->mnCurrentZoom
)
344 if ( GetStatusBar().AreItemsVisible() )
345 GetStatusBar().SetItemData( GetId(), 0 ); // force repaint
347 mpImpl
->mbOmitPaint
= true; // optimization: paint before executing command,
348 // then omit painting which is triggered by the execute function
350 SvxZoomSliderItem
aZoomSliderItem( mpImpl
->mnCurrentZoom
);
352 ::com::sun::star::uno::Any a
;
353 aZoomSliderItem
.QueryValue( a
);
355 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
> aArgs( 1 );
356 aArgs
[0].Name
= OUString( "ZoomSlider" );
361 mpImpl
->mbOmitPaint
= false;
366 // -----------------------------------------------------------------------
368 sal_Bool
SvxZoomSliderControl::MouseMove( const MouseEvent
& rEvt
)
370 if ( !mpImpl
->mbValuesSet
)
373 const short nButtons
= rEvt
.GetButtons();
375 // check mouse move with button pressed
378 const Rectangle aControlRect
= getControlRect();
379 const Point aPoint
= rEvt
.GetPosPixel();
380 const sal_Int32 nXDiff
= aPoint
.X() - aControlRect
.Left();
382 if ( nXDiff
>= nSliderXOffset
&& nXDiff
<= aControlRect
.GetWidth() - nSliderXOffset
)
384 mpImpl
->mnCurrentZoom
= Offset2Zoom( nXDiff
);
386 if ( GetStatusBar().AreItemsVisible() )
387 GetStatusBar().SetItemData( GetId(), 0 ); // force repaint
389 mpImpl
->mbOmitPaint
= true; // optimization: paint before executing command,
390 // then omit painting which is triggered by the execute function
392 // commit state change
393 SvxZoomSliderItem
aZoomSliderItem( mpImpl
->mnCurrentZoom
);
395 ::com::sun::star::uno::Any a
;
396 aZoomSliderItem
.QueryValue( a
);
398 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
> aArgs( 1 );
399 aArgs
[0].Name
= OUString( "ZoomSlider" );
404 mpImpl
->mbOmitPaint
= false;
411 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */