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 .
19 #include "tbzoomsliderctrl.hxx"
20 #include <vcl/image.hxx>
21 #include <vcl/toolbox.hxx>
22 #include <vcl/virdev.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/gradient.hxx>
25 #include <vcl/settings.hxx>
26 #include <svl/itemset.hxx>
27 #include <sfx2/viewfrm.hxx>
28 #include <sfx2/objsh.hxx>
29 #include <svx/zoomslideritem.hxx>
30 #include <svx/dialmgr.hxx>
31 #include <svx/dialogs.hrc>
34 #include "stlpool.hxx"
35 #include "scitems.hxx"
36 #include "printfun.hxx"
38 // class ScZoomSliderControl ---------------------------------------
40 SFX_IMPL_TOOLBOX_CONTROL( ScZoomSliderControl
, SvxZoomSliderItem
);
42 ScZoomSliderControl::ScZoomSliderControl(
46 :SfxToolBoxControl( nSlotId
, nId
, rTbx
)
51 ScZoomSliderControl::~ScZoomSliderControl()
56 void ScZoomSliderControl::StateChanged( sal_uInt16
/*nSID*/, SfxItemState eState
,
57 const SfxPoolItem
* pState
)
59 sal_uInt16 nId
= GetId();
60 ToolBox
& rTbx
= GetToolBox();
61 ScZoomSliderWnd
* pBox
= static_cast<ScZoomSliderWnd
*>(rTbx
.GetItemWindow( nId
));
62 OSL_ENSURE( pBox
,"Control not found!" );
64 if ( SfxItemState::DEFAULT
!= eState
|| pState
->ISA( SfxVoidItem
) )
66 SvxZoomSliderItem
aZoomSliderItem( 100 );
68 pBox
->UpdateFromItem( &aZoomSliderItem
);
73 OSL_ENSURE( pState
->ISA( SvxZoomSliderItem
), "invalid item type" );
74 const SvxZoomSliderItem
* pZoomSliderItem
= dynamic_cast< const SvxZoomSliderItem
* >( pState
);
76 OSL_ENSURE( pZoomSliderItem
, "Sc::ScZoomSliderControl::StateChanged(), wrong item type!" );
78 pBox
->UpdateFromItem( pZoomSliderItem
);
82 VclPtr
<vcl::Window
> ScZoomSliderControl::CreateItemWindow( vcl::Window
*pParent
)
84 // #i98000# Don't try to get a value via SfxViewFrame::Current here.
85 // The view's value is always notified via StateChanged later.
86 VclPtrInstance
<ScZoomSliderWnd
> pSlider( pParent
,
87 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchProvider
>( m_xFrame
->getController(),
88 ::com::sun::star::uno::UNO_QUERY
), m_xFrame
, 100 );
92 struct ScZoomSliderWnd::ScZoomSliderWnd_Impl
94 sal_uInt16 mnCurrentZoom
;
97 sal_uInt16 mnSliderCenter
;
98 std::vector
< long > maSnappingPointOffsets
;
99 std::vector
< sal_uInt16
> maSnappingPointZooms
;
100 Image maSliderButton
;
101 Image maIncreaseButton
;
102 Image maDecreaseButton
;
106 ScZoomSliderWnd_Impl( sal_uInt16 nCurrentZoom
) :
107 mnCurrentZoom( nCurrentZoom
),
110 mnSliderCenter( 100 ),
111 maSnappingPointOffsets(),
112 maSnappingPointZooms(),
123 const long nButtonWidth
= 10;
124 const long nButtonHeight
= 10;
125 const long nIncDecWidth
= 11;
126 const long nIncDecHeight
= 11;
127 const long nSliderHeight
= 2;
128 const long nSliderWidth
= 4;
129 const long nSnappingHeight
= 4;
130 const long nSliderXOffset
= 20;
131 const long nSnappingEpsilon
= 5; // snapping epsilon in pixels
132 const long nSnappingPointsMinDist
= nSnappingEpsilon
; // minimum distance of two adjacent snapping points
134 sal_uInt16
ScZoomSliderWnd::Offset2Zoom( long nOffset
) const
136 Size aSliderWindowSize
= GetOutputSizePixel();
137 const long nControlWidth
= aSliderWindowSize
.Width();
140 if( nOffset
< nSliderXOffset
)
141 return mpImpl
->mnMinZoom
;
142 if( nOffset
> nControlWidth
- nSliderXOffset
)
143 return mpImpl
->mnMaxZoom
;
145 // check for snapping points:
146 sal_uInt16 nCount
= 0;
147 std::vector
< long >::iterator aSnappingPointIter
;
148 for ( aSnappingPointIter
= mpImpl
->maSnappingPointOffsets
.begin();
149 aSnappingPointIter
!= mpImpl
->maSnappingPointOffsets
.end();
150 ++aSnappingPointIter
)
152 const long nCurrent
= *aSnappingPointIter
;
153 if ( std::abs(nCurrent
- nOffset
) < nSnappingEpsilon
)
156 nRet
= mpImpl
->maSnappingPointZooms
[ nCount
];
164 if( nOffset
< nControlWidth
/ 2 )
166 // first half of slider
167 const long nFirstHalfRange
= mpImpl
->mnSliderCenter
- mpImpl
->mnMinZoom
;
168 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
169 const long nZoomPerSliderPixel
= (1000 * nFirstHalfRange
) / nHalfSliderWidth
;
170 const long nOffsetToSliderLeft
= nOffset
- nSliderXOffset
;
171 nRet
= mpImpl
->mnMinZoom
+ sal_uInt16( nOffsetToSliderLeft
* nZoomPerSliderPixel
/ 1000 );
175 // second half of slider
176 const long nSecondHalfRange
= mpImpl
->mnMaxZoom
- mpImpl
->mnSliderCenter
;
177 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
178 const long nZoomPerSliderPixel
= 1000 * nSecondHalfRange
/ nHalfSliderWidth
;
179 const long nOffsetToSliderCenter
= nOffset
- nControlWidth
/2;
180 nRet
= mpImpl
->mnSliderCenter
+ sal_uInt16( nOffsetToSliderCenter
* nZoomPerSliderPixel
/ 1000 );
184 if( nRet
< mpImpl
->mnMinZoom
)
185 return mpImpl
->mnMinZoom
;
187 else if( nRet
> mpImpl
->mnMaxZoom
)
188 return mpImpl
->mnMaxZoom
;
193 long ScZoomSliderWnd::Zoom2Offset( sal_uInt16 nCurrentZoom
) const
195 Size aSliderWindowSize
= GetOutputSizePixel();
196 const long nControlWidth
= aSliderWindowSize
.Width();
197 long nRect
= nSliderXOffset
;
199 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
200 if( nCurrentZoom
<= mpImpl
->mnSliderCenter
)
202 nCurrentZoom
= nCurrentZoom
- mpImpl
->mnMinZoom
;
203 const long nFirstHalfRange
= mpImpl
->mnSliderCenter
- mpImpl
->mnMinZoom
;
204 const long nSliderPixelPerZoomPercent
= 1000 * nHalfSliderWidth
/ nFirstHalfRange
;
205 const long nOffset
= (nSliderPixelPerZoomPercent
* nCurrentZoom
) / 1000;
210 nCurrentZoom
= nCurrentZoom
- mpImpl
->mnSliderCenter
;
211 const long nSecondHalfRange
= mpImpl
->mnMaxZoom
- mpImpl
->mnSliderCenter
;
212 const long nSliderPixelPerZoomPercent
= 1000 * nHalfSliderWidth
/ nSecondHalfRange
;
213 const long nOffset
= (nSliderPixelPerZoomPercent
* nCurrentZoom
) / 1000;
214 nRect
+= nHalfSliderWidth
+ nOffset
;
219 ScZoomSliderWnd::ScZoomSliderWnd( vcl::Window
* pParent
, const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchProvider
>& rDispatchProvider
,
220 const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XFrame
>& _xFrame
, sal_uInt16 nCurrentZoom
):
222 mpImpl( new ScZoomSliderWnd_Impl( nCurrentZoom
) ),
223 aLogicalSize( 115, 40 ),
224 m_xDispatchProvider( rDispatchProvider
),
227 mpImpl
->maSliderButton
= Image( SVX_RES( RID_SVXBMP_SLIDERBUTTON
) );
228 mpImpl
->maIncreaseButton
= Image( SVX_RES( RID_SVXBMP_SLIDERINCREASE
) );
229 mpImpl
->maDecreaseButton
= Image( SVX_RES( RID_SVXBMP_SLIDERDECREASE
) );
230 Size aSliderSize
= LogicToPixel( Size( aLogicalSize
), MapMode( MAP_10TH_MM
) );
231 SetSizePixel( Size( aSliderSize
.Width() * nSliderWidth
-1, aSliderSize
.Height() + nSliderHeight
) );
234 ScZoomSliderWnd::~ScZoomSliderWnd()
239 void ScZoomSliderWnd::dispose()
242 vcl::Window::dispose();
245 void ScZoomSliderWnd::MouseButtonDown( const MouseEvent
& rMEvt
)
247 if ( !mpImpl
->mbValuesSet
)
249 Size aSliderWindowSize
= GetOutputSizePixel();
251 const Point aPoint
= rMEvt
.GetPosPixel();
253 const long nButtonLeftOffset
= ( nSliderXOffset
- nIncDecWidth
)/2;
254 const long nButtonRightOffset
= ( nSliderXOffset
+ nIncDecWidth
)/2;
256 const long nOldZoom
= mpImpl
->mnCurrentZoom
;
259 if ( aPoint
.X() >= nButtonLeftOffset
&& aPoint
.X() <= nButtonRightOffset
)
261 mpImpl
->mnCurrentZoom
= mpImpl
->mnCurrentZoom
- 5;
264 else if ( aPoint
.X() >= aSliderWindowSize
.Width() - nSliderXOffset
+ nButtonLeftOffset
&&
265 aPoint
.X() <= aSliderWindowSize
.Width() - nSliderXOffset
+ nButtonRightOffset
)
267 mpImpl
->mnCurrentZoom
= mpImpl
->mnCurrentZoom
+ 5;
269 else if( aPoint
.X() >= nSliderXOffset
&& aPoint
.X() <= aSliderWindowSize
.Width() - nSliderXOffset
)
271 mpImpl
->mnCurrentZoom
= Offset2Zoom( aPoint
.X() );
274 if( mpImpl
->mnCurrentZoom
< mpImpl
->mnMinZoom
)
275 mpImpl
->mnCurrentZoom
= mpImpl
->mnMinZoom
;
276 else if( mpImpl
->mnCurrentZoom
> mpImpl
->mnMaxZoom
)
277 mpImpl
->mnCurrentZoom
= mpImpl
->mnMaxZoom
;
279 if( nOldZoom
== mpImpl
->mnCurrentZoom
)
282 Rectangle
aRect( Point( 0, 0 ), aSliderWindowSize
);
285 mpImpl
->mbOmitPaint
= true;
287 SvxZoomSliderItem
aZoomSliderItem( mpImpl
->mnCurrentZoom
);
289 ::com::sun::star::uno::Any a
;
290 aZoomSliderItem
.QueryValue( a
);
292 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
> aArgs( 1 );
293 aArgs
[0].Name
= "ScalingFactor";
296 SfxToolBoxControl::Dispatch( m_xDispatchProvider
, OUString(".uno:ScalingFactor"), aArgs
);
298 mpImpl
->mbOmitPaint
= false;
301 void ScZoomSliderWnd::MouseMove( const MouseEvent
& rMEvt
)
303 if ( !mpImpl
->mbValuesSet
)
306 Size aSliderWindowSize
= GetOutputSizePixel();
307 const long nControlWidth
= aSliderWindowSize
.Width();
308 const short nButtons
= rMEvt
.GetButtons();
310 // check mouse move with button pressed
313 const Point aPoint
= rMEvt
.GetPosPixel();
315 if ( aPoint
.X() >= nSliderXOffset
&& aPoint
.X() <= nControlWidth
- nSliderXOffset
)
317 mpImpl
->mnCurrentZoom
= Offset2Zoom( aPoint
.X() );
319 Rectangle
aRect(Point(0, 0), aSliderWindowSize
);
322 mpImpl
->mbOmitPaint
= true; // optimization: paint before executing command,
324 // commit state change
325 SvxZoomSliderItem
aZoomSliderItem( mpImpl
->mnCurrentZoom
);
327 ::com::sun::star::uno::Any a
;
328 aZoomSliderItem
.QueryValue( a
);
330 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
> aArgs( 1 );
331 aArgs
[0].Name
= "ScalingFactor";
334 SfxToolBoxControl::Dispatch( m_xDispatchProvider
, OUString(".uno:ScalingFactor"), aArgs
);
336 mpImpl
->mbOmitPaint
= false;
341 void ScZoomSliderWnd::UpdateFromItem( const SvxZoomSliderItem
* pZoomSliderItem
)
343 if( pZoomSliderItem
)
345 mpImpl
->mnCurrentZoom
= pZoomSliderItem
->GetValue();
346 mpImpl
->mnMinZoom
= pZoomSliderItem
->GetMinZoom();
347 mpImpl
->mnMaxZoom
= pZoomSliderItem
->GetMaxZoom();
349 OSL_ENSURE( mpImpl
->mnMinZoom
<= mpImpl
->mnCurrentZoom
&&
350 mpImpl
->mnMinZoom
< mpImpl
->mnSliderCenter
&&
351 mpImpl
->mnMaxZoom
>= mpImpl
->mnCurrentZoom
&&
352 mpImpl
->mnMaxZoom
> mpImpl
->mnSliderCenter
,
353 "Looks like the zoom slider item is corrupted" );
354 const com::sun::star::uno::Sequence
< sal_Int32
> rSnappingPoints
= pZoomSliderItem
->GetSnappingPoints();
355 mpImpl
->maSnappingPointOffsets
.clear();
356 mpImpl
->maSnappingPointZooms
.clear();
358 // get all snapping points:
359 std::set
< sal_uInt16
> aTmpSnappingPoints
;
360 for ( sal_uInt16 j
= 0; j
< rSnappingPoints
.getLength(); ++j
)
362 const sal_Int32 nSnappingPoint
= rSnappingPoints
[j
];
363 aTmpSnappingPoints
.insert( (sal_uInt16
)nSnappingPoint
);
366 // remove snapping points that are to close to each other:
367 std::set
< sal_uInt16
>::iterator aSnappingPointIter
;
368 long nLastOffset
= 0;
370 for ( aSnappingPointIter
= aTmpSnappingPoints
.begin(); aSnappingPointIter
!= aTmpSnappingPoints
.end(); ++aSnappingPointIter
)
372 const sal_uInt16 nCurrent
= *aSnappingPointIter
;
373 const long nCurrentOffset
= Zoom2Offset( nCurrent
);
375 if ( nCurrentOffset
- nLastOffset
>= nSnappingPointsMinDist
)
377 mpImpl
->maSnappingPointOffsets
.push_back( nCurrentOffset
);
378 mpImpl
->maSnappingPointZooms
.push_back( nCurrent
);
379 nLastOffset
= nCurrentOffset
;
384 Size aSliderWindowSize
= GetOutputSizePixel();
385 Rectangle
aRect(Point(0, 0), aSliderWindowSize
);
387 if ( !mpImpl
->mbOmitPaint
)
391 void ScZoomSliderWnd::Paint(vcl::RenderContext
& rRenderContext
, const Rectangle
& rRect
)
393 DoPaint(rRenderContext
, rRect
);
396 void ScZoomSliderWnd::DoPaint(vcl::RenderContext
& rRenderContext
, const Rectangle
& /*rRect*/)
398 if (mpImpl
->mbOmitPaint
)
401 Size
aSliderWindowSize(GetOutputSizePixel());
402 Rectangle
aRect(Point(0, 0), aSliderWindowSize
);
404 ScopedVclPtrInstance
< VirtualDevice
> pVDev(rRenderContext
);
405 pVDev
->SetOutputSizePixel(aSliderWindowSize
);
407 Rectangle aSlider
= aRect
;
409 aSlider
.Top() += (aSliderWindowSize
.Height() - nSliderHeight
) / 2 - 1;
410 aSlider
.Bottom() = aSlider
.Top() + nSliderHeight
;
411 aSlider
.Left() += nSliderXOffset
;
412 aSlider
.Right() -= nSliderXOffset
;
414 Rectangle
aFirstLine(aSlider
);
415 aFirstLine
.Bottom() = aFirstLine
.Top();
417 Rectangle
aSecondLine(aSlider
);
418 aSecondLine
.Top() = aSecondLine
.Bottom();
420 Rectangle
aLeft(aSlider
);
421 aLeft
.Right() = aLeft
.Left();
423 Rectangle
aRight(aSlider
);
424 aRight
.Left() = aRight
.Right();
426 // draw VirtualDevice's background color
427 Color aStartColor
= rRenderContext
.GetSettings().GetStyleSettings().GetFaceColor();
428 Color aEndColor
= rRenderContext
.GetSettings().GetStyleSettings().GetFaceColor();
430 if (aEndColor
.IsDark())
431 aStartColor
= aEndColor
;
434 aGradient
.SetAngle(0);
435 aGradient
.SetStyle(GradientStyle_LINEAR
);
437 aGradient
.SetStartColor(aStartColor
);
438 aGradient
.SetEndColor(aEndColor
);
439 pVDev
->DrawGradient(aRect
, aGradient
);
442 pVDev
->SetLineColor(Color(COL_WHITE
));
443 pVDev
->DrawRect(aSecondLine
);
444 pVDev
->DrawRect(aRight
);
446 pVDev
->SetLineColor(Color(COL_GRAY
));
447 pVDev
->DrawRect(aFirstLine
);
448 pVDev
->DrawRect(aLeft
);
450 // draw snapping points:
451 std::vector
<long>::iterator aSnappingPointIter
;
452 for (aSnappingPointIter
= mpImpl
->maSnappingPointOffsets
.begin();
453 aSnappingPointIter
!= mpImpl
->maSnappingPointOffsets
.end();
454 ++aSnappingPointIter
)
456 pVDev
->SetLineColor(Color(COL_GRAY
));
457 Rectangle
aSnapping(aRect
);
458 aSnapping
.Bottom() = aSlider
.Top();
459 aSnapping
.Top() = aSnapping
.Bottom() - nSnappingHeight
;
460 aSnapping
.Left() += *aSnappingPointIter
;
461 aSnapping
.Right() = aSnapping
.Left();
462 pVDev
->DrawRect(aSnapping
);
464 aSnapping
.Top() += nSnappingHeight
+ nSliderHeight
;
465 aSnapping
.Bottom() += nSnappingHeight
+ nSliderHeight
;
466 pVDev
->DrawRect(aSnapping
);
469 // draw slider button
470 Point aImagePoint
= aRect
.TopLeft();
471 aImagePoint
.X() += Zoom2Offset(mpImpl
->mnCurrentZoom
);
472 aImagePoint
.X() -= nButtonWidth
/ 2;
473 aImagePoint
.Y() += (aSliderWindowSize
.Height() - nButtonHeight
) / 2;
474 pVDev
->DrawImage(aImagePoint
, mpImpl
->maSliderButton
);
476 // draw decrease button
477 aImagePoint
= aRect
.TopLeft();
478 aImagePoint
.X() += (nSliderXOffset
- nIncDecWidth
) / 2;
479 aImagePoint
.Y() += (aSliderWindowSize
.Height() - nIncDecHeight
) / 2;
480 pVDev
->DrawImage(aImagePoint
, mpImpl
->maDecreaseButton
);
482 // draw increase button
483 aImagePoint
.X() = aRect
.TopLeft().X() + aSliderWindowSize
.Width() - nIncDecWidth
- (nSliderXOffset
- nIncDecWidth
) / 2;
484 pVDev
->DrawImage(aImagePoint
, mpImpl
->maIncreaseButton
);
486 rRenderContext
.DrawOutDev(Point(0, 0), aSliderWindowSize
, Point(0, 0), aSliderWindowSize
, *pVDev
);
489 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */