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 <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 #include "bitmaps.hlst"
34 SFX_IMPL_STATUSBAR_CONTROL( SvxZoomSliderControl
, SvxZoomSliderItem
);
36 struct SvxZoomSliderControl::SvxZoomSliderControl_Impl
38 sal_uInt16 mnCurrentZoom
;
41 sal_uInt16 mnSliderCenter
;
42 std::vector
< long > maSnappingPointOffsets
;
43 std::vector
< sal_uInt16
> maSnappingPointZooms
;
45 Image maIncreaseButton
;
46 Image maDecreaseButton
;
48 bool mbDraggingStarted
;
50 SvxZoomSliderControl_Impl() :
55 maSnappingPointOffsets(),
56 maSnappingPointZooms(),
61 mbDraggingStarted( false ) {}
64 const long nSliderXOffset
= 20;
65 const long nSnappingEpsilon
= 5; // snapping epsilon in pixels
66 const long nSnappingPointsMinDist
= nSnappingEpsilon
; // minimum distance of two adjacent snapping points
68 // nOffset referes to the origin of the control:
70 sal_uInt16
SvxZoomSliderControl::Offset2Zoom( long nOffset
) const
72 const long nControlWidth
= getControlRect().GetWidth();
75 if ( nOffset
< nSliderXOffset
)
76 return mxImpl
->mnMinZoom
;
78 if ( nOffset
> nControlWidth
- nSliderXOffset
)
79 return mxImpl
->mnMaxZoom
;
81 // check for snapping points:
82 sal_uInt16 nCount
= 0;
83 for ( std::vector
< long >::const_iterator aSnappingPointIter
= mxImpl
->maSnappingPointOffsets
.begin(),
84 aEnd
= mxImpl
->maSnappingPointOffsets
.end();
85 aSnappingPointIter
!= aEnd
;
86 ++aSnappingPointIter
)
88 const long nCurrent
= *aSnappingPointIter
;
89 if ( std::abs(nCurrent
- nOffset
) < nSnappingEpsilon
)
92 nRet
= mxImpl
->maSnappingPointZooms
[ nCount
];
100 if ( nOffset
< nControlWidth
/ 2 )
102 // first half of slider
103 const long nFirstHalfRange
= mxImpl
->mnSliderCenter
- mxImpl
->mnMinZoom
;
104 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
105 const long nZoomPerSliderPixel
= (1000 * nFirstHalfRange
) / nHalfSliderWidth
;
106 const long nOffsetToSliderLeft
= nOffset
- nSliderXOffset
;
107 nRet
= mxImpl
->mnMinZoom
+ sal_uInt16( nOffsetToSliderLeft
* nZoomPerSliderPixel
/ 1000 );
111 // second half of slider
112 const long nSecondHalfRange
= mxImpl
->mnMaxZoom
- mxImpl
->mnSliderCenter
;
113 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
114 const long nZoomPerSliderPixel
= 1000 * nSecondHalfRange
/ nHalfSliderWidth
;
115 const long nOffsetToSliderCenter
= nOffset
- nControlWidth
/2;
116 nRet
= mxImpl
->mnSliderCenter
+ sal_uInt16( nOffsetToSliderCenter
* nZoomPerSliderPixel
/ 1000 );
120 if ( nRet
< mxImpl
->mnMinZoom
)
121 nRet
= mxImpl
->mnMinZoom
;
122 else if ( nRet
> mxImpl
->mnMaxZoom
)
123 nRet
= mxImpl
->mnMaxZoom
;
128 // returns the offset to the left control border
129 long SvxZoomSliderControl::Zoom2Offset( sal_uInt16 nCurrentZoom
) const
131 const long nControlWidth
= getControlRect().GetWidth();
132 long nRet
= nSliderXOffset
;
134 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
136 if ( nCurrentZoom
<= mxImpl
->mnSliderCenter
)
138 nCurrentZoom
= nCurrentZoom
- mxImpl
->mnMinZoom
;
139 const long nFirstHalfRange
= mxImpl
->mnSliderCenter
- mxImpl
->mnMinZoom
;
140 const long nSliderPixelPerZoomPercent
= 1000 * nHalfSliderWidth
/ nFirstHalfRange
;
141 const long nOffset
= (nSliderPixelPerZoomPercent
* nCurrentZoom
) / 1000;
146 nCurrentZoom
= nCurrentZoom
- mxImpl
->mnSliderCenter
;
147 const long nSecondHalfRange
= mxImpl
->mnMaxZoom
- mxImpl
->mnSliderCenter
;
148 const long nSliderPixelPerZoomPercent
= 1000 * nHalfSliderWidth
/ nSecondHalfRange
;
149 const long nOffset
= (nSliderPixelPerZoomPercent
* nCurrentZoom
) / 1000;
150 nRet
+= nHalfSliderWidth
+ nOffset
;
156 SvxZoomSliderControl::SvxZoomSliderControl( sal_uInt16 _nSlotId
, sal_uInt16 _nId
, StatusBar
& rStatusBar
) :
157 SfxStatusBarControl( _nSlotId
, _nId
, rStatusBar
),
158 mxImpl( new SvxZoomSliderControl_Impl
)
160 mxImpl
->maSliderButton
= Image(BitmapEx(RID_SVXBMP_SLIDERBUTTON
));
161 mxImpl
->maIncreaseButton
= Image(BitmapEx(RID_SVXBMP_SLIDERINCREASE
));
162 mxImpl
->maDecreaseButton
= Image(BitmapEx(RID_SVXBMP_SLIDERDECREASE
));
165 SvxZoomSliderControl::~SvxZoomSliderControl()
169 void SvxZoomSliderControl::StateChanged( sal_uInt16
/*nSID*/, SfxItemState eState
, const SfxPoolItem
* pState
)
171 if ( (SfxItemState::DEFAULT
!= eState
) || pState
->IsVoidItem() )
173 GetStatusBar().SetItemText( GetId(), "" );
174 mxImpl
->mbValuesSet
= false;
178 OSL_ENSURE( dynamic_cast<const SvxZoomSliderItem
*>( pState
) != nullptr, "invalid item type: should be a SvxZoomSliderItem" );
179 mxImpl
->mnCurrentZoom
= static_cast<const SvxZoomSliderItem
*>( pState
)->GetValue();
180 mxImpl
->mnMinZoom
= static_cast<const SvxZoomSliderItem
*>( pState
)->GetMinZoom();
181 mxImpl
->mnMaxZoom
= static_cast<const SvxZoomSliderItem
*>( pState
)->GetMaxZoom();
182 mxImpl
->mnSliderCenter
= 100;
183 mxImpl
->mbValuesSet
= true;
185 if ( mxImpl
->mnSliderCenter
== mxImpl
->mnMaxZoom
)
186 mxImpl
->mnSliderCenter
= mxImpl
->mnMinZoom
+ (sal_uInt16
)((mxImpl
->mnMaxZoom
- mxImpl
->mnMinZoom
) * 0.5);
189 DBG_ASSERT( mxImpl
->mnMinZoom
<= mxImpl
->mnCurrentZoom
&&
190 mxImpl
->mnMinZoom
< mxImpl
->mnSliderCenter
&&
191 mxImpl
->mnMaxZoom
>= mxImpl
->mnCurrentZoom
&&
192 mxImpl
->mnMaxZoom
> mxImpl
->mnSliderCenter
,
193 "Looks like the zoom slider item is corrupted" );
195 const css::uno::Sequence
< sal_Int32
> rSnappingPoints
= static_cast<const SvxZoomSliderItem
*>( pState
)->GetSnappingPoints();
196 mxImpl
->maSnappingPointOffsets
.clear();
197 mxImpl
->maSnappingPointZooms
.clear();
199 // get all snapping points:
200 std::set
< sal_uInt16
> aTmpSnappingPoints
;
201 for ( sal_Int32 j
= 0; j
< rSnappingPoints
.getLength(); ++j
)
203 const sal_Int32 nSnappingPoint
= rSnappingPoints
[j
];
204 aTmpSnappingPoints
.insert( (sal_uInt16
)nSnappingPoint
);
207 // remove snapping points that are to close to each other:
208 long nLastOffset
= 0;
210 for ( std::set
< sal_uInt16
>::const_iterator aSnappingPointIter
= aTmpSnappingPoints
.begin(),
211 aEnd
= aTmpSnappingPoints
.end(); aSnappingPointIter
!= aEnd
; ++aSnappingPointIter
)
213 const sal_uInt16 nCurrent
= *aSnappingPointIter
;
214 const long nCurrentOffset
= Zoom2Offset( nCurrent
);
216 if ( nCurrentOffset
- nLastOffset
>= nSnappingPointsMinDist
)
218 mxImpl
->maSnappingPointOffsets
.push_back( nCurrentOffset
);
219 mxImpl
->maSnappingPointZooms
.push_back( nCurrent
);
220 nLastOffset
= nCurrentOffset
;
228 void SvxZoomSliderControl::Paint( const UserDrawEvent
& rUsrEvt
)
230 if ( !mxImpl
->mbValuesSet
)
233 const tools::Rectangle aControlRect
= getControlRect();
234 vcl::RenderContext
* pDev
= rUsrEvt
.GetRenderContext();
235 tools::Rectangle aRect
= rUsrEvt
.GetRect();
236 tools::Rectangle aSlider
= aRect
;
238 long nSliderHeight
= 2 * pDev
->GetDPIScaleFactor();
239 long nSnappingHeight
= 4 * pDev
->GetDPIScaleFactor();
241 aSlider
.Top() += (aControlRect
.GetHeight() - nSliderHeight
)/2;
242 aSlider
.Bottom() = aSlider
.Top() + nSliderHeight
- 1;
243 aSlider
.Left() += nSliderXOffset
;
244 aSlider
.Right() -= nSliderXOffset
;
246 Color aOldLineColor
= pDev
->GetLineColor();
247 Color aOldFillColor
= pDev
->GetFillColor();
249 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
250 pDev
->SetLineColor( rStyleSettings
.GetShadowColor() );
251 pDev
->SetFillColor( rStyleSettings
.GetShadowColor() );
254 // draw snapping points:
255 for ( std::vector
< long >::const_iterator aSnappingPointIter
= mxImpl
->maSnappingPointOffsets
.begin(),
256 aEnd
= mxImpl
->maSnappingPointOffsets
.end();
257 aSnappingPointIter
!= aEnd
;
258 ++aSnappingPointIter
)
260 long nSnapPosX
= aRect
.Left() + *aSnappingPointIter
;
262 pDev
->DrawRect( tools::Rectangle( nSnapPosX
- 1, aSlider
.Top() - nSnappingHeight
,
263 nSnapPosX
, aSlider
.Bottom() + nSnappingHeight
) );
267 pDev
->DrawRect( aSlider
);
269 // draw slider button
270 Point aImagePoint
= aRect
.TopLeft();
271 aImagePoint
.X() += Zoom2Offset( mxImpl
->mnCurrentZoom
);
272 aImagePoint
.X() -= mxImpl
->maSliderButton
.GetSizePixel().Width()/2;
273 aImagePoint
.Y() += (aControlRect
.GetHeight() - mxImpl
->maSliderButton
.GetSizePixel().Height())/2;
274 pDev
->DrawImage( aImagePoint
, mxImpl
->maSliderButton
);
276 // draw decrease button
277 aImagePoint
= aRect
.TopLeft();
278 aImagePoint
.X() += (nSliderXOffset
- mxImpl
->maDecreaseButton
.GetSizePixel().Width())/2;
279 aImagePoint
.Y() += (aControlRect
.GetHeight() - mxImpl
->maDecreaseButton
.GetSizePixel().Height())/2;
280 pDev
->DrawImage( aImagePoint
, mxImpl
->maDecreaseButton
);
282 // draw increase button
283 aImagePoint
.X() = aRect
.TopLeft().X() + aControlRect
.GetWidth() - mxImpl
->maIncreaseButton
.GetSizePixel().Width() - (nSliderXOffset
- mxImpl
->maIncreaseButton
.GetSizePixel().Height())/2;
284 pDev
->DrawImage( aImagePoint
, mxImpl
->maIncreaseButton
);
286 pDev
->SetLineColor( aOldLineColor
);
287 pDev
->SetFillColor( aOldFillColor
);
290 bool SvxZoomSliderControl::MouseButtonDown( const MouseEvent
& rEvt
)
292 if ( !mxImpl
->mbValuesSet
)
295 const tools::Rectangle aControlRect
= getControlRect();
296 const Point aPoint
= rEvt
.GetPosPixel();
297 const sal_Int32 nXDiff
= aPoint
.X() - aControlRect
.Left();
299 long nIncDecWidth
= mxImpl
->maIncreaseButton
.GetSizePixel().Width();
301 const long nButtonLeftOffset
= (nSliderXOffset
- nIncDecWidth
)/2;
302 const long nButtonRightOffset
= (nSliderXOffset
+ nIncDecWidth
)/2;
304 const long nOldZoom
= mxImpl
->mnCurrentZoom
;
307 if ( nXDiff
>= nButtonLeftOffset
&& nXDiff
<= nButtonRightOffset
)
308 mxImpl
->mnCurrentZoom
= basegfx::zoomtools::zoomOut( static_cast<int>(mxImpl
->mnCurrentZoom
) );
310 else if ( nXDiff
>= aControlRect
.GetWidth() - nSliderXOffset
+ nButtonLeftOffset
&&
311 nXDiff
<= aControlRect
.GetWidth() - nSliderXOffset
+ nButtonRightOffset
)
312 mxImpl
->mnCurrentZoom
= basegfx::zoomtools::zoomIn( static_cast<int>(mxImpl
->mnCurrentZoom
) );
314 else if( nXDiff
>= nSliderXOffset
&& nXDiff
<= aControlRect
.GetWidth() - nSliderXOffset
)
316 mxImpl
->mnCurrentZoom
= Offset2Zoom( nXDiff
);
317 mxImpl
->mbDraggingStarted
= true;
320 if ( mxImpl
->mnCurrentZoom
< mxImpl
->mnMinZoom
)
321 mxImpl
->mnCurrentZoom
= mxImpl
->mnMinZoom
;
322 else if ( mxImpl
->mnCurrentZoom
> mxImpl
->mnMaxZoom
)
323 mxImpl
->mnCurrentZoom
= mxImpl
->mnMaxZoom
;
325 if ( nOldZoom
== mxImpl
->mnCurrentZoom
)
333 bool SvxZoomSliderControl::MouseButtonUp( const MouseEvent
& )
335 mxImpl
->mbDraggingStarted
= false;
339 bool SvxZoomSliderControl::MouseMove( const MouseEvent
& rEvt
)
341 if ( !mxImpl
->mbValuesSet
)
344 const short nButtons
= rEvt
.GetButtons();
345 const tools::Rectangle aControlRect
= getControlRect();
346 const Point aPoint
= rEvt
.GetPosPixel();
347 const sal_Int32 nXDiff
= aPoint
.X() - aControlRect
.Left();
349 // check mouse move with button pressed
350 if ( 1 == nButtons
&& mxImpl
->mbDraggingStarted
)
352 if ( nXDiff
>= nSliderXOffset
&& nXDiff
<= aControlRect
.GetWidth() - nSliderXOffset
)
354 mxImpl
->mnCurrentZoom
= Offset2Zoom( nXDiff
);
362 long nIncDecWidth
= mxImpl
->maIncreaseButton
.GetSizePixel().Width();
364 const long nButtonLeftOffset
= (nSliderXOffset
- nIncDecWidth
)/2;
365 const long nButtonRightOffset
= (nSliderXOffset
+ nIncDecWidth
)/2;
368 if ( nXDiff
>= nButtonLeftOffset
&& nXDiff
<= nButtonRightOffset
)
369 GetStatusBar().SetQuickHelpText(GetId(), SvxResId(RID_SVXSTR_ZOOM_OUT
));
371 else if ( nXDiff
>= aControlRect
.GetWidth() - nSliderXOffset
+ nButtonLeftOffset
&&
372 nXDiff
<= aControlRect
.GetWidth() - nSliderXOffset
+ nButtonRightOffset
)
373 GetStatusBar().SetQuickHelpText(GetId(), SvxResId(RID_SVXSTR_ZOOM_IN
));
375 // don't hide the slider and its handle with a tooltip during zooming
376 GetStatusBar().SetQuickHelpText(GetId(), "");
381 void SvxZoomSliderControl::forceRepaint() const
383 if (GetStatusBar().AreItemsVisible())
384 GetStatusBar().SetItemData(GetId(), nullptr);
387 void SvxZoomSliderControl::repaintAndExecute()
391 // commit state change
392 SvxZoomSliderItem
aZoomSliderItem(mxImpl
->mnCurrentZoom
);
395 aZoomSliderItem
.QueryValue(any
);
397 css::uno::Sequence
<css::beans::PropertyValue
> aArgs(1);
398 aArgs
[0].Name
= "ZoomSlider";
399 aArgs
[0].Value
= any
;
404 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */