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 <vcl/event.hxx>
27 #include <svx/zoomslideritem.hxx>
28 #include <svx/dialmgr.hxx>
29 #include <svx/strings.hrc>
30 #include <basegfx/utils/zoomtools.hxx>
31 #include <bitmaps.hlst>
32 #include <com/sun/star/beans/PropertyValue.hpp>
36 SFX_IMPL_STATUSBAR_CONTROL( SvxZoomSliderControl
, SvxZoomSliderItem
);
38 struct SvxZoomSliderControl::SvxZoomSliderControl_Impl
40 sal_uInt16 mnCurrentZoom
;
43 sal_uInt16 mnSliderCenter
;
44 std::vector
< long > maSnappingPointOffsets
;
45 std::vector
< sal_uInt16
> maSnappingPointZooms
;
47 Image maIncreaseButton
;
48 Image maDecreaseButton
;
50 bool mbDraggingStarted
;
52 SvxZoomSliderControl_Impl() :
57 maSnappingPointOffsets(),
58 maSnappingPointZooms(),
63 mbDraggingStarted( false ) {}
66 const long nSliderXOffset
= 20;
67 const long nSnappingEpsilon
= 5; // snapping epsilon in pixels
68 const long nSnappingPointsMinDist
= nSnappingEpsilon
; // minimum distance of two adjacent snapping points
70 // nOffset refers to the origin of the control:
72 sal_uInt16
SvxZoomSliderControl::Offset2Zoom( long nOffset
) const
74 const long nControlWidth
= getControlRect().GetWidth();
77 if ( nOffset
< nSliderXOffset
)
78 return mxImpl
->mnMinZoom
;
80 if ( nOffset
> nControlWidth
- nSliderXOffset
)
81 return mxImpl
->mnMaxZoom
;
83 // check for snapping points:
84 sal_uInt16 nCount
= 0;
85 for ( const long nCurrent
: mxImpl
->maSnappingPointOffsets
)
87 if ( std::abs(nCurrent
- nOffset
) < nSnappingEpsilon
)
90 nRet
= mxImpl
->maSnappingPointZooms
[ nCount
];
98 if ( nOffset
< nControlWidth
/ 2 )
100 // first half of slider
101 const long nFirstHalfRange
= mxImpl
->mnSliderCenter
- mxImpl
->mnMinZoom
;
102 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
103 const long nZoomPerSliderPixel
= (1000 * nFirstHalfRange
) / nHalfSliderWidth
;
104 const long nOffsetToSliderLeft
= nOffset
- nSliderXOffset
;
105 nRet
= mxImpl
->mnMinZoom
+ sal_uInt16( nOffsetToSliderLeft
* nZoomPerSliderPixel
/ 1000 );
109 // second half of slider
110 const long nSecondHalfRange
= mxImpl
->mnMaxZoom
- mxImpl
->mnSliderCenter
;
111 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
112 const long nZoomPerSliderPixel
= 1000 * nSecondHalfRange
/ nHalfSliderWidth
;
113 const long nOffsetToSliderCenter
= nOffset
- nControlWidth
/2;
114 nRet
= mxImpl
->mnSliderCenter
+ sal_uInt16( nOffsetToSliderCenter
* nZoomPerSliderPixel
/ 1000 );
118 if ( nRet
< mxImpl
->mnMinZoom
)
119 nRet
= mxImpl
->mnMinZoom
;
120 else if ( nRet
> mxImpl
->mnMaxZoom
)
121 nRet
= mxImpl
->mnMaxZoom
;
126 // returns the offset to the left control border
127 long SvxZoomSliderControl::Zoom2Offset( sal_uInt16 nCurrentZoom
) const
129 const long nControlWidth
= getControlRect().GetWidth();
130 long nRet
= nSliderXOffset
;
132 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
134 if ( nCurrentZoom
<= mxImpl
->mnSliderCenter
)
136 nCurrentZoom
= nCurrentZoom
- mxImpl
->mnMinZoom
;
137 const long nFirstHalfRange
= mxImpl
->mnSliderCenter
- mxImpl
->mnMinZoom
;
138 const long nSliderPixelPerZoomPercent
= 1000 * nHalfSliderWidth
/ nFirstHalfRange
;
139 const long nOffset
= (nSliderPixelPerZoomPercent
* nCurrentZoom
) / 1000;
144 nCurrentZoom
= nCurrentZoom
- mxImpl
->mnSliderCenter
;
145 const long nSecondHalfRange
= mxImpl
->mnMaxZoom
- mxImpl
->mnSliderCenter
;
146 const long nSliderPixelPerZoomPercent
= 1000 * nHalfSliderWidth
/ nSecondHalfRange
;
147 const long nOffset
= (nSliderPixelPerZoomPercent
* nCurrentZoom
) / 1000;
148 nRet
+= nHalfSliderWidth
+ nOffset
;
154 SvxZoomSliderControl::SvxZoomSliderControl( sal_uInt16 _nSlotId
, sal_uInt16 _nId
, StatusBar
& rStatusBar
) :
155 SfxStatusBarControl( _nSlotId
, _nId
, rStatusBar
),
156 mxImpl( new SvxZoomSliderControl_Impl
)
158 mxImpl
->maSliderButton
= Image(StockImage::Yes
, RID_SVXBMP_SLIDERBUTTON
);
159 mxImpl
->maIncreaseButton
= Image(StockImage::Yes
, RID_SVXBMP_SLIDERINCREASE
);
160 mxImpl
->maDecreaseButton
= Image(StockImage::Yes
, RID_SVXBMP_SLIDERDECREASE
);
163 SvxZoomSliderControl::~SvxZoomSliderControl()
167 void SvxZoomSliderControl::StateChanged( sal_uInt16
/*nSID*/, SfxItemState eState
, const SfxPoolItem
* pState
)
169 if ( (SfxItemState::DEFAULT
!= eState
) || pState
->IsVoidItem() )
171 GetStatusBar().SetItemText( GetId(), "" );
172 mxImpl
->mbValuesSet
= false;
176 OSL_ENSURE( dynamic_cast<const SvxZoomSliderItem
*>( pState
) != nullptr, "invalid item type: should be a SvxZoomSliderItem" );
177 mxImpl
->mnCurrentZoom
= static_cast<const SvxZoomSliderItem
*>( pState
)->GetValue();
178 mxImpl
->mnMinZoom
= static_cast<const SvxZoomSliderItem
*>( pState
)->GetMinZoom();
179 mxImpl
->mnMaxZoom
= static_cast<const SvxZoomSliderItem
*>( pState
)->GetMaxZoom();
180 mxImpl
->mnSliderCenter
= 100;
181 mxImpl
->mbValuesSet
= true;
183 if ( mxImpl
->mnSliderCenter
== mxImpl
->mnMaxZoom
)
184 mxImpl
->mnSliderCenter
= mxImpl
->mnMinZoom
+ static_cast<sal_uInt16
>((mxImpl
->mnMaxZoom
- mxImpl
->mnMinZoom
) * 0.5);
187 DBG_ASSERT( mxImpl
->mnMinZoom
<= mxImpl
->mnCurrentZoom
&&
188 mxImpl
->mnMinZoom
< mxImpl
->mnSliderCenter
&&
189 mxImpl
->mnMaxZoom
>= mxImpl
->mnCurrentZoom
&&
190 mxImpl
->mnMaxZoom
> mxImpl
->mnSliderCenter
,
191 "Looks like the zoom slider item is corrupted" );
193 const css::uno::Sequence
< sal_Int32
> rSnappingPoints
= static_cast<const SvxZoomSliderItem
*>( pState
)->GetSnappingPoints();
194 mxImpl
->maSnappingPointOffsets
.clear();
195 mxImpl
->maSnappingPointZooms
.clear();
197 // get all snapping points:
198 std::set
< sal_uInt16
> aTmpSnappingPoints
;
199 for ( const sal_Int32 nSnappingPoint
: rSnappingPoints
)
201 aTmpSnappingPoints
.insert( static_cast<sal_uInt16
>(nSnappingPoint
) );
204 // remove snapping points that are too close to each other:
205 long nLastOffset
= 0;
207 for ( const sal_uInt16 nCurrent
: aTmpSnappingPoints
)
209 const long nCurrentOffset
= Zoom2Offset( nCurrent
);
211 if ( nCurrentOffset
- nLastOffset
>= nSnappingPointsMinDist
)
213 mxImpl
->maSnappingPointOffsets
.push_back( nCurrentOffset
);
214 mxImpl
->maSnappingPointZooms
.push_back( nCurrent
);
215 nLastOffset
= nCurrentOffset
;
223 void SvxZoomSliderControl::Paint( const UserDrawEvent
& rUsrEvt
)
225 if ( !mxImpl
->mbValuesSet
)
228 const tools::Rectangle aControlRect
= getControlRect();
229 vcl::RenderContext
* pDev
= rUsrEvt
.GetRenderContext();
230 tools::Rectangle aRect
= rUsrEvt
.GetRect();
231 tools::Rectangle aSlider
= aRect
;
233 long nSliderHeight
= 1 * pDev
->GetDPIScaleFactor();
234 long nSnappingHeight
= 2 * pDev
->GetDPIScaleFactor();
236 aSlider
.AdjustTop((aControlRect
.GetHeight() - nSliderHeight
)/2 );
237 aSlider
.SetBottom( aSlider
.Top() + nSliderHeight
- 1 );
238 aSlider
.AdjustLeft(nSliderXOffset
);
239 aSlider
.AdjustRight( -nSliderXOffset
);
241 Color aOldLineColor
= pDev
->GetLineColor();
242 Color aOldFillColor
= pDev
->GetFillColor();
244 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
245 pDev
->SetLineColor( rStyleSettings
.GetDarkShadowColor() );
246 pDev
->SetFillColor( rStyleSettings
.GetDarkShadowColor() );
249 pDev
->DrawRect( aSlider
);
251 pDev
->SetLineColor( rStyleSettings
.GetShadowColor() );
252 pDev
->DrawLine(Point(aSlider
.Left()+1,aSlider
.Bottom()+1), Point(aSlider
.Right()+1,aSlider
.Bottom()+1));
253 pDev
->SetLineColor( rStyleSettings
.GetDarkShadowColor() );
255 // draw snapping points:
256 for ( const auto& rSnappingPoint
: mxImpl
->maSnappingPointOffsets
)
258 long nSnapPosX
= aRect
.Left() + rSnappingPoint
;
260 pDev
->DrawRect( tools::Rectangle( nSnapPosX
- 1, aSlider
.Top() - nSnappingHeight
,
261 nSnapPosX
, aSlider
.Bottom() + nSnappingHeight
) );
264 // draw slider button
265 Point aImagePoint
= aRect
.TopLeft();
266 aImagePoint
.AdjustX(Zoom2Offset( mxImpl
->mnCurrentZoom
) );
267 aImagePoint
.AdjustX( -(mxImpl
->maSliderButton
.GetSizePixel().Width()/2) );
268 aImagePoint
.AdjustY((aControlRect
.GetHeight() - mxImpl
->maSliderButton
.GetSizePixel().Height())/2 );
269 pDev
->DrawImage( aImagePoint
, mxImpl
->maSliderButton
);
271 // draw decrease button
272 aImagePoint
= aRect
.TopLeft();
273 aImagePoint
.AdjustX((nSliderXOffset
- mxImpl
->maDecreaseButton
.GetSizePixel().Width())/2 );
274 aImagePoint
.AdjustY((aControlRect
.GetHeight() - mxImpl
->maDecreaseButton
.GetSizePixel().Height())/2 );
275 pDev
->DrawImage( aImagePoint
, mxImpl
->maDecreaseButton
);
277 // draw increase button
278 aImagePoint
.setX( aRect
.TopLeft().X() + aControlRect
.GetWidth() - mxImpl
->maIncreaseButton
.GetSizePixel().Width() - (nSliderXOffset
- mxImpl
->maIncreaseButton
.GetSizePixel().Height())/2 );
279 pDev
->DrawImage( aImagePoint
, mxImpl
->maIncreaseButton
);
281 pDev
->SetLineColor( aOldLineColor
);
282 pDev
->SetFillColor( aOldFillColor
);
285 bool SvxZoomSliderControl::MouseButtonDown( const MouseEvent
& rEvt
)
287 if ( !mxImpl
->mbValuesSet
)
290 const tools::Rectangle aControlRect
= getControlRect();
291 const Point aPoint
= rEvt
.GetPosPixel();
292 const sal_Int32 nXDiff
= aPoint
.X() - aControlRect
.Left();
294 long nIncDecWidth
= mxImpl
->maIncreaseButton
.GetSizePixel().Width();
296 const long nButtonLeftOffset
= (nSliderXOffset
- nIncDecWidth
)/2;
297 const long nButtonRightOffset
= (nSliderXOffset
+ nIncDecWidth
)/2;
299 const long nOldZoom
= mxImpl
->mnCurrentZoom
;
302 if ( nXDiff
>= nButtonLeftOffset
&& nXDiff
<= nButtonRightOffset
)
303 mxImpl
->mnCurrentZoom
= basegfx::zoomtools::zoomOut( static_cast<int>(mxImpl
->mnCurrentZoom
) );
305 else if ( nXDiff
>= aControlRect
.GetWidth() - nSliderXOffset
+ nButtonLeftOffset
&&
306 nXDiff
<= aControlRect
.GetWidth() - nSliderXOffset
+ nButtonRightOffset
)
307 mxImpl
->mnCurrentZoom
= basegfx::zoomtools::zoomIn( static_cast<int>(mxImpl
->mnCurrentZoom
) );
309 else if( nXDiff
>= nSliderXOffset
&& nXDiff
<= aControlRect
.GetWidth() - nSliderXOffset
)
311 mxImpl
->mnCurrentZoom
= Offset2Zoom( nXDiff
);
312 mxImpl
->mbDraggingStarted
= true;
315 if ( mxImpl
->mnCurrentZoom
< mxImpl
->mnMinZoom
)
316 mxImpl
->mnCurrentZoom
= mxImpl
->mnMinZoom
;
317 else if ( mxImpl
->mnCurrentZoom
> mxImpl
->mnMaxZoom
)
318 mxImpl
->mnCurrentZoom
= mxImpl
->mnMaxZoom
;
320 if ( nOldZoom
== mxImpl
->mnCurrentZoom
)
328 bool SvxZoomSliderControl::MouseButtonUp( const MouseEvent
& )
330 mxImpl
->mbDraggingStarted
= false;
334 bool SvxZoomSliderControl::MouseMove( const MouseEvent
& rEvt
)
336 if ( !mxImpl
->mbValuesSet
)
339 const short nButtons
= rEvt
.GetButtons();
340 const tools::Rectangle aControlRect
= getControlRect();
341 const Point aPoint
= rEvt
.GetPosPixel();
342 const sal_Int32 nXDiff
= aPoint
.X() - aControlRect
.Left();
344 // check mouse move with button pressed
345 if ( 1 == nButtons
&& mxImpl
->mbDraggingStarted
)
347 if ( nXDiff
>= nSliderXOffset
&& nXDiff
<= aControlRect
.GetWidth() - nSliderXOffset
)
349 mxImpl
->mnCurrentZoom
= Offset2Zoom( nXDiff
);
357 long nIncDecWidth
= mxImpl
->maIncreaseButton
.GetSizePixel().Width();
359 const long nButtonLeftOffset
= (nSliderXOffset
- nIncDecWidth
)/2;
360 const long nButtonRightOffset
= (nSliderXOffset
+ nIncDecWidth
)/2;
363 if ( nXDiff
>= nButtonLeftOffset
&& nXDiff
<= nButtonRightOffset
)
364 GetStatusBar().SetQuickHelpText(GetId(), SvxResId(RID_SVXSTR_ZOOM_OUT
));
366 else if ( nXDiff
>= aControlRect
.GetWidth() - nSliderXOffset
+ nButtonLeftOffset
&&
367 nXDiff
<= aControlRect
.GetWidth() - nSliderXOffset
+ nButtonRightOffset
)
368 GetStatusBar().SetQuickHelpText(GetId(), SvxResId(RID_SVXSTR_ZOOM_IN
));
370 // don't hide the slider and its handle with a tooltip during zooming
371 GetStatusBar().SetQuickHelpText(GetId(), "");
376 void SvxZoomSliderControl::forceRepaint() const
378 GetStatusBar().SetItemData(GetId(), nullptr);
381 void SvxZoomSliderControl::repaintAndExecute()
385 // commit state change
386 SvxZoomSliderItem
aZoomSliderItem(mxImpl
->mnCurrentZoom
);
389 aZoomSliderItem
.QueryValue(any
);
391 css::uno::Sequence
<css::beans::PropertyValue
> aArgs(1);
392 aArgs
[0].Name
= "ZoomSlider";
393 aArgs
[0].Value
= any
;
398 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */