Adjust includes
[LibreOffice.git] / svx / source / stbctrls / zoomsliderctrl.cxx
blob53ad2619b4b4326fb52e750f7fdb76fc955bd811
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/strings.hrc>
29 #include <basegfx/utils/zoomtools.hxx>
30 #include <bitmaps.hlst>
32 #include <set>
34 SFX_IMPL_STATUSBAR_CONTROL( SvxZoomSliderControl, SvxZoomSliderItem );
36 struct SvxZoomSliderControl::SvxZoomSliderControl_Impl
38 sal_uInt16 mnCurrentZoom;
39 sal_uInt16 mnMinZoom;
40 sal_uInt16 mnMaxZoom;
41 sal_uInt16 mnSliderCenter;
42 std::vector< long > maSnappingPointOffsets;
43 std::vector< sal_uInt16 > maSnappingPointZooms;
44 Image maSliderButton;
45 Image maIncreaseButton;
46 Image maDecreaseButton;
47 bool mbValuesSet;
48 bool mbDraggingStarted;
50 SvxZoomSliderControl_Impl() :
51 mnCurrentZoom( 0 ),
52 mnMinZoom( 0 ),
53 mnMaxZoom( 0 ),
54 mnSliderCenter( 0 ),
55 maSnappingPointOffsets(),
56 maSnappingPointZooms(),
57 maSliderButton(),
58 maIncreaseButton(),
59 maDecreaseButton(),
60 mbValuesSet( false ),
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:
69 // + ----------- -
70 sal_uInt16 SvxZoomSliderControl::Offset2Zoom( long nOffset ) const
72 const long nControlWidth = getControlRect().GetWidth();
73 sal_uInt16 nRet = 0;
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 )
91 nOffset = nCurrent;
92 nRet = mxImpl->maSnappingPointZooms[ nCount ];
93 break;
95 ++nCount;
98 if ( 0 == nRet )
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 );
109 else
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;
125 return nRet;
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;
142 nRet += nOffset;
144 else
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;
153 return nRet;
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;
176 else
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;
225 forceRepaint();
228 void SvxZoomSliderControl::Paint( const UserDrawEvent& rUsrEvt )
230 if ( !mxImpl->mbValuesSet )
231 return;
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 ) );
266 // draw slider
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 )
293 return true;
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;
306 // click to - button
307 if ( nXDiff >= nButtonLeftOffset && nXDiff <= nButtonRightOffset )
308 mxImpl->mnCurrentZoom = basegfx::zoomtools::zoomOut( static_cast<int>(mxImpl->mnCurrentZoom) );
309 // click to + button
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) );
313 // click to slider
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 )
326 return true;
328 repaintAndExecute();
330 return true;
333 bool SvxZoomSliderControl::MouseButtonUp( const MouseEvent & )
335 mxImpl->mbDraggingStarted = false;
336 return true;
339 bool SvxZoomSliderControl::MouseMove( const MouseEvent & rEvt )
341 if ( !mxImpl->mbValuesSet )
342 return true;
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 );
356 repaintAndExecute();
360 // Tooltips
362 long nIncDecWidth = mxImpl->maIncreaseButton.GetSizePixel().Width();
364 const long nButtonLeftOffset = (nSliderXOffset - nIncDecWidth)/2;
365 const long nButtonRightOffset = (nSliderXOffset + nIncDecWidth)/2;
367 // click to - button
368 if ( nXDiff >= nButtonLeftOffset && nXDiff <= nButtonRightOffset )
369 GetStatusBar().SetQuickHelpText(GetId(), SvxResId(RID_SVXSTR_ZOOM_OUT));
370 // click to + button
371 else if ( nXDiff >= aControlRect.GetWidth() - nSliderXOffset + nButtonLeftOffset &&
372 nXDiff <= aControlRect.GetWidth() - nSliderXOffset + nButtonRightOffset )
373 GetStatusBar().SetQuickHelpText(GetId(), SvxResId(RID_SVXSTR_ZOOM_IN));
374 else
375 // don't hide the slider and its handle with a tooltip during zooming
376 GetStatusBar().SetQuickHelpText(GetId(), "");
378 return true;
381 void SvxZoomSliderControl::forceRepaint() const
383 if (GetStatusBar().AreItemsVisible())
384 GetStatusBar().SetItemData(GetId(), nullptr);
387 void SvxZoomSliderControl::repaintAndExecute()
389 forceRepaint();
391 // commit state change
392 SvxZoomSliderItem aZoomSliderItem(mxImpl->mnCurrentZoom);
394 css::uno::Any any;
395 aZoomSliderItem.QueryValue(any);
397 css::uno::Sequence<css::beans::PropertyValue> aArgs(1);
398 aArgs[0].Name = "ZoomSlider";
399 aArgs[0].Value = any;
401 execute(aArgs);
404 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */