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 <svl/itemset.hxx>
26 #include <sfx2/viewfrm.hxx>
27 #include <sfx2/objsh.hxx>
28 #include <svx/zoomslideritem.hxx>
29 #include <svx/dialmgr.hxx>
30 #include <svx/dialogs.hrc>
33 #include "stlpool.hxx"
34 #include "scitems.hxx"
35 #include "printfun.hxx"
37 //========================================================================
38 // class ScZoomSliderControl ---------------------------------------
39 //========================================================================
41 // -----------------------------------------------------------------------
43 SFX_IMPL_TOOLBOX_CONTROL( ScZoomSliderControl
, SvxZoomSliderItem
);
45 // -----------------------------------------------------------------------
47 ScZoomSliderControl::ScZoomSliderControl(
51 :SfxToolBoxControl( nSlotId
, nId
, rTbx
)
56 // -----------------------------------------------------------------------
58 ScZoomSliderControl::~ScZoomSliderControl()
63 // -----------------------------------------------------------------------
65 void ScZoomSliderControl::StateChanged( sal_uInt16
/*nSID*/, SfxItemState eState
,
66 const SfxPoolItem
* pState
)
68 sal_uInt16 nId
= GetId();
69 ToolBox
& rTbx
= GetToolBox();
70 ScZoomSliderWnd
* pBox
= (ScZoomSliderWnd
*)(rTbx
.GetItemWindow( nId
));
71 OSL_ENSURE( pBox
,"Control not found!" );
73 if ( SFX_ITEM_AVAILABLE
!= eState
|| pState
->ISA( SfxVoidItem
) )
75 SvxZoomSliderItem
aZoomSliderItem( 100 );
77 pBox
->UpdateFromItem( &aZoomSliderItem
);
82 OSL_ENSURE( pState
->ISA( SvxZoomSliderItem
), "invalid item type" );
83 const SvxZoomSliderItem
* pZoomSliderItem
= dynamic_cast< const SvxZoomSliderItem
* >( pState
);
85 OSL_ENSURE( pZoomSliderItem
, "Sc::ScZoomSliderControl::StateChanged(), wrong item type!" );
87 pBox
->UpdateFromItem( pZoomSliderItem
);
91 // -----------------------------------------------------------------------
93 Window
* ScZoomSliderControl::CreateItemWindow( Window
*pParent
)
95 // #i98000# Don't try to get a value via SfxViewFrame::Current here.
96 // The view's value is always notified via StateChanged later.
97 ScZoomSliderWnd
* pSlider
= new ScZoomSliderWnd( pParent
,
98 ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchProvider
>( m_xFrame
->getController(),
99 ::com::sun::star::uno::UNO_QUERY
), m_xFrame
, 100 );
103 // -----------------------------------------------------------------------
105 struct ScZoomSliderWnd::ScZoomSliderWnd_Impl
107 sal_uInt16 mnCurrentZoom
;
108 sal_uInt16 mnMinZoom
;
109 sal_uInt16 mnMaxZoom
;
110 sal_uInt16 mnSliderCenter
;
111 std::vector
< long > maSnappingPointOffsets
;
112 std::vector
< sal_uInt16
> maSnappingPointZooms
;
113 Image maSliderButton
;
114 Image maIncreaseButton
;
115 Image maDecreaseButton
;
119 ScZoomSliderWnd_Impl( sal_uInt16 nCurrentZoom
) :
120 mnCurrentZoom( nCurrentZoom
),
123 mnSliderCenter( 100 ),
124 maSnappingPointOffsets(),
125 maSnappingPointZooms(),
136 // -----------------------------------------------------------------------
138 const long nButtonWidth
= 10;
139 const long nButtonHeight
= 10;
140 const long nIncDecWidth
= 11;
141 const long nIncDecHeight
= 11;
142 const long nSliderHeight
= 2; //
143 const long nSliderWidth
= 4; //
144 const long nSnappingHeight
= 4;
145 const long nSliderXOffset
= 20;
146 const long nSnappingEpsilon
= 5; // snapping epsilon in pixels
147 const long nSnappingPointsMinDist
= nSnappingEpsilon
; // minimum distance of two adjacent snapping points
150 // -----------------------------------------------------------------------
152 sal_uInt16
ScZoomSliderWnd::Offset2Zoom( long nOffset
) const
154 Size aSliderWindowSize
= GetOutputSizePixel();
155 const long nControlWidth
= aSliderWindowSize
.Width();
158 if( nOffset
< nSliderXOffset
)
159 return mpImpl
->mnMinZoom
;
160 if( nOffset
> nControlWidth
- nSliderXOffset
)
161 return mpImpl
->mnMaxZoom
;
163 // check for snapping points:
164 sal_uInt16 nCount
= 0;
165 std::vector
< long >::iterator aSnappingPointIter
;
166 for ( aSnappingPointIter
= mpImpl
->maSnappingPointOffsets
.begin();
167 aSnappingPointIter
!= mpImpl
->maSnappingPointOffsets
.end();
168 ++aSnappingPointIter
)
170 const long nCurrent
= *aSnappingPointIter
;
171 if ( std::abs(nCurrent
- nOffset
) < nSnappingEpsilon
)
174 nRet
= mpImpl
->maSnappingPointZooms
[ nCount
];
182 if( nOffset
< nControlWidth
/ 2 )
184 // first half of slider
185 const long nFirstHalfRange
= mpImpl
->mnSliderCenter
- mpImpl
->mnMinZoom
;
186 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
187 const long nZoomPerSliderPixel
= (1000 * nFirstHalfRange
) / nHalfSliderWidth
;
188 const long nOffsetToSliderLeft
= nOffset
- nSliderXOffset
;
189 nRet
= mpImpl
->mnMinZoom
+ sal_uInt16( nOffsetToSliderLeft
* nZoomPerSliderPixel
/ 1000 );
193 // second half of slider
194 const long nSecondHalfRange
= mpImpl
->mnMaxZoom
- mpImpl
->mnSliderCenter
;
195 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
196 const long nZoomPerSliderPixel
= 1000 * nSecondHalfRange
/ nHalfSliderWidth
;
197 const long nOffsetToSliderCenter
= nOffset
- nControlWidth
/2;
198 nRet
= mpImpl
->mnSliderCenter
+ sal_uInt16( nOffsetToSliderCenter
* nZoomPerSliderPixel
/ 1000 );
202 if( nRet
< mpImpl
->mnMinZoom
)
203 return mpImpl
->mnMinZoom
;
205 else if( nRet
> mpImpl
->mnMaxZoom
)
206 return mpImpl
->mnMaxZoom
;
211 // -----------------------------------------------------------------------
213 long ScZoomSliderWnd::Zoom2Offset( sal_uInt16 nCurrentZoom
) const
215 Size aSliderWindowSize
= GetOutputSizePixel();
216 const long nControlWidth
= aSliderWindowSize
.Width();
217 long nRect
= nSliderXOffset
;
219 const long nHalfSliderWidth
= nControlWidth
/2 - nSliderXOffset
;
220 if( nCurrentZoom
<= mpImpl
->mnSliderCenter
)
222 nCurrentZoom
= nCurrentZoom
- mpImpl
->mnMinZoom
;
223 const long nFirstHalfRange
= mpImpl
->mnSliderCenter
- mpImpl
->mnMinZoom
;
224 const long nSliderPixelPerZoomPercent
= 1000 * nHalfSliderWidth
/ nFirstHalfRange
;
225 const long nOffset
= (nSliderPixelPerZoomPercent
* nCurrentZoom
) / 1000;
230 nCurrentZoom
= nCurrentZoom
- mpImpl
->mnSliderCenter
;
231 const long nSecondHalfRange
= mpImpl
->mnMaxZoom
- mpImpl
->mnSliderCenter
;
232 const long nSliderPixelPerZoomPercent
= 1000 * nHalfSliderWidth
/ nSecondHalfRange
;
233 const long nOffset
= (nSliderPixelPerZoomPercent
* nCurrentZoom
) / 1000;
234 nRect
+= nHalfSliderWidth
+ nOffset
;
239 // -----------------------------------------------------------------------
242 ScZoomSliderWnd::ScZoomSliderWnd( Window
* pParent
, const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XDispatchProvider
>& rDispatchProvider
,
243 const ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XFrame
>& _xFrame
, sal_uInt16 nCurrentZoom
):
245 mpImpl( new ScZoomSliderWnd_Impl( nCurrentZoom
) ),
246 aLogicalSize( 115, 40 ),
247 m_xDispatchProvider( rDispatchProvider
),
250 mpImpl
->maSliderButton
= Image( SVX_RES( RID_SVXBMP_SLIDERBUTTON
) );
251 mpImpl
->maIncreaseButton
= Image( SVX_RES( RID_SVXBMP_SLIDERINCREASE
) );
252 mpImpl
->maDecreaseButton
= Image( SVX_RES( RID_SVXBMP_SLIDERDECREASE
) );
253 Size aSliderSize
= LogicToPixel( Size( aLogicalSize
), MapMode( MAP_10TH_MM
) );
254 SetSizePixel( Size( aSliderSize
.Width() * nSliderWidth
-1, aSliderSize
.Height() + nSliderHeight
) );
257 // -----------------------------------------------------------------------
259 ScZoomSliderWnd::~ScZoomSliderWnd()
264 // -----------------------------------------------------------------------
266 void ScZoomSliderWnd::MouseButtonDown( const MouseEvent
& rMEvt
)
268 if ( !mpImpl
->mbValuesSet
)
270 Size aSliderWindowSize
= GetOutputSizePixel();
272 const Point aPoint
= rMEvt
.GetPosPixel();
274 const long nButtonLeftOffset
= ( nSliderXOffset
- nIncDecWidth
)/2;
275 const long nButtonRightOffset
= ( nSliderXOffset
+ nIncDecWidth
)/2;
277 const long nOldZoom
= mpImpl
->mnCurrentZoom
;
280 if ( aPoint
.X() >= nButtonLeftOffset
&& aPoint
.X() <= nButtonRightOffset
)
282 mpImpl
->mnCurrentZoom
= mpImpl
->mnCurrentZoom
- 5;
285 else if ( aPoint
.X() >= aSliderWindowSize
.Width() - nSliderXOffset
+ nButtonLeftOffset
&&
286 aPoint
.X() <= aSliderWindowSize
.Width() - nSliderXOffset
+ nButtonRightOffset
)
288 mpImpl
->mnCurrentZoom
= mpImpl
->mnCurrentZoom
+ 5;
290 else if( aPoint
.X() >= nSliderXOffset
&& aPoint
.X() <= aSliderWindowSize
.Width() - nSliderXOffset
)
292 mpImpl
->mnCurrentZoom
= Offset2Zoom( aPoint
.X() );
295 if( mpImpl
->mnCurrentZoom
< mpImpl
->mnMinZoom
)
296 mpImpl
->mnCurrentZoom
= mpImpl
->mnMinZoom
;
297 else if( mpImpl
->mnCurrentZoom
> mpImpl
->mnMaxZoom
)
298 mpImpl
->mnCurrentZoom
= mpImpl
->mnMaxZoom
;
300 if( nOldZoom
== mpImpl
->mnCurrentZoom
)
303 Rectangle
aRect( Point( 0, 0 ), aSliderWindowSize
);
306 mpImpl
->mbOmitPaint
= true;
308 SvxZoomSliderItem
aZoomSliderItem( mpImpl
->mnCurrentZoom
);
310 ::com::sun::star::uno::Any a
;
311 aZoomSliderItem
.QueryValue( a
);
313 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
> aArgs( 1 );
314 aArgs
[0].Name
= "ScalingFactor";
317 SfxToolBoxControl::Dispatch( m_xDispatchProvider
, OUString(".uno:ScalingFactor"), aArgs
);
319 mpImpl
->mbOmitPaint
= false;
322 // -----------------------------------------------------------------------
324 void ScZoomSliderWnd::MouseMove( const MouseEvent
& rMEvt
)
326 if ( !mpImpl
->mbValuesSet
)
329 Size aSliderWindowSize
= GetOutputSizePixel();
330 const long nControlWidth
= aSliderWindowSize
.Width();
331 const short nButtons
= rMEvt
.GetButtons();
333 // check mouse move with button pressed
336 const Point aPoint
= rMEvt
.GetPosPixel();
338 if ( aPoint
.X() >= nSliderXOffset
&& aPoint
.X() <= nControlWidth
- nSliderXOffset
)
340 mpImpl
->mnCurrentZoom
= Offset2Zoom( aPoint
.X() );
342 Rectangle
aRect( Point( 0, 0 ), aSliderWindowSize
);
345 mpImpl
->mbOmitPaint
= true; // optimization: paint before executing command,
347 // commit state change
348 SvxZoomSliderItem
aZoomSliderItem( mpImpl
->mnCurrentZoom
);
350 ::com::sun::star::uno::Any a
;
351 aZoomSliderItem
.QueryValue( a
);
353 ::com::sun::star::uno::Sequence
< ::com::sun::star::beans::PropertyValue
> aArgs( 1 );
354 aArgs
[0].Name
= "ScalingFactor";
357 SfxToolBoxControl::Dispatch( m_xDispatchProvider
, OUString(".uno:ScalingFactor"), aArgs
);
359 mpImpl
->mbOmitPaint
= false;
364 // -----------------------------------------------------------------------
366 void ScZoomSliderWnd::UpdateFromItem( const SvxZoomSliderItem
* pZoomSliderItem
)
368 if( pZoomSliderItem
)
370 mpImpl
->mnCurrentZoom
= pZoomSliderItem
->GetValue();
371 mpImpl
->mnMinZoom
= pZoomSliderItem
->GetMinZoom();
372 mpImpl
->mnMaxZoom
= pZoomSliderItem
->GetMaxZoom();
374 OSL_ENSURE( mpImpl
->mnMinZoom
<= mpImpl
->mnCurrentZoom
&&
375 mpImpl
->mnMinZoom
< mpImpl
->mnSliderCenter
&&
376 mpImpl
->mnMaxZoom
>= mpImpl
->mnCurrentZoom
&&
377 mpImpl
->mnMaxZoom
> mpImpl
->mnSliderCenter
,
378 "Looks like the zoom slider item is corrupted" );
379 const com::sun::star::uno::Sequence
< sal_Int32
> rSnappingPoints
= pZoomSliderItem
->GetSnappingPoints();
380 mpImpl
->maSnappingPointOffsets
.clear();
381 mpImpl
->maSnappingPointZooms
.clear();
383 // get all snapping points:
384 std::set
< sal_uInt16
> aTmpSnappingPoints
;
385 for ( sal_uInt16 j
= 0; j
< rSnappingPoints
.getLength(); ++j
)
387 const sal_Int32 nSnappingPoint
= rSnappingPoints
[j
];
388 aTmpSnappingPoints
.insert( (sal_uInt16
)nSnappingPoint
);
391 // remove snapping points that are to close to each other:
392 std::set
< sal_uInt16
>::iterator aSnappingPointIter
;
393 long nLastOffset
= 0;
395 for ( aSnappingPointIter
= aTmpSnappingPoints
.begin(); aSnappingPointIter
!= aTmpSnappingPoints
.end(); ++aSnappingPointIter
)
397 const sal_uInt16 nCurrent
= *aSnappingPointIter
;
398 const long nCurrentOffset
= Zoom2Offset( nCurrent
);
400 if ( nCurrentOffset
- nLastOffset
>= nSnappingPointsMinDist
)
402 mpImpl
->maSnappingPointOffsets
.push_back( nCurrentOffset
);
403 mpImpl
->maSnappingPointZooms
.push_back( nCurrent
);
404 nLastOffset
= nCurrentOffset
;
409 Size aSliderWindowSize
= GetOutputSizePixel();
410 Rectangle
aRect( Point( 0, 0 ), aSliderWindowSize
);
412 if ( !mpImpl
->mbOmitPaint
)
416 // -----------------------------------------------------------------------
418 void ScZoomSliderWnd::Paint( const Rectangle
& rRect
)
423 // -----------------------------------------------------------------------
425 void ScZoomSliderWnd::DoPaint( const Rectangle
& /*rRect*/ )
427 if( mpImpl
->mbOmitPaint
)
430 Size aSliderWindowSize
= GetOutputSizePixel();
431 Rectangle
aRect( Point( 0, 0 ), aSliderWindowSize
);
433 VirtualDevice
* pVDev
= new VirtualDevice( *this );
434 pVDev
->SetOutputSizePixel( aSliderWindowSize
);
436 Rectangle aSlider
= aRect
;
438 aSlider
.Top() += ( aSliderWindowSize
.Height() - nSliderHeight
)/2 - 1;
439 aSlider
.Bottom() = aSlider
.Top() + nSliderHeight
;
440 aSlider
.Left() += nSliderXOffset
;
441 aSlider
.Right() -= nSliderXOffset
;
443 Rectangle
aFirstLine( aSlider
);
444 aFirstLine
.Bottom() = aFirstLine
.Top();
446 Rectangle
aSecondLine( aSlider
);
447 aSecondLine
.Top() = aSecondLine
.Bottom();
449 Rectangle
aLeft( aSlider
);
450 aLeft
.Right() = aLeft
.Left();
452 Rectangle
aRight( aSlider
);
453 aRight
.Left() = aRight
.Right();
455 // draw VirtualDevice's background color
456 Color aStartColor
,aEndColor
;
457 aStartColor
= GetSettings().GetStyleSettings().GetFaceColor();
458 aEndColor
= GetSettings().GetStyleSettings().GetFaceColor();
459 if( aEndColor
.IsDark() )
460 aStartColor
= aEndColor
;
464 g
.SetStyle( GradientStyle_LINEAR
);
466 g
.SetStartColor( aStartColor
);
467 g
.SetEndColor( aEndColor
);
468 pVDev
->DrawGradient( aRect
, g
);
471 pVDev
->SetLineColor( Color ( COL_WHITE
) );
472 pVDev
->DrawRect( aSecondLine
);
473 pVDev
->DrawRect( aRight
);
475 pVDev
->SetLineColor( Color( COL_GRAY
) );
476 pVDev
->DrawRect( aFirstLine
);
477 pVDev
->DrawRect( aLeft
);
479 // draw snapping points:
480 std::vector
< long >::iterator aSnappingPointIter
;
481 for ( aSnappingPointIter
= mpImpl
->maSnappingPointOffsets
.begin();
482 aSnappingPointIter
!= mpImpl
->maSnappingPointOffsets
.end();
483 ++aSnappingPointIter
)
485 pVDev
->SetLineColor( Color( COL_GRAY
) );
486 Rectangle
aSnapping( aRect
);
487 aSnapping
.Bottom() = aSlider
.Top();
488 aSnapping
.Top() = aSnapping
.Bottom() - nSnappingHeight
;
489 aSnapping
.Left() += *aSnappingPointIter
;
490 aSnapping
.Right() = aSnapping
.Left();
491 pVDev
->DrawRect( aSnapping
);
493 aSnapping
.Top() += nSnappingHeight
+ nSliderHeight
;
494 aSnapping
.Bottom() += nSnappingHeight
+ nSliderHeight
;
495 pVDev
->DrawRect( aSnapping
);
498 // draw slider button
499 Point aImagePoint
= aRect
.TopLeft();
500 aImagePoint
.X() += Zoom2Offset( mpImpl
->mnCurrentZoom
);
501 aImagePoint
.X() -= nButtonWidth
/2;
502 aImagePoint
.Y() += ( aSliderWindowSize
.Height() - nButtonHeight
)/2;
503 pVDev
->DrawImage( aImagePoint
, mpImpl
->maSliderButton
);
505 // draw decrease button
506 aImagePoint
= aRect
.TopLeft();
507 aImagePoint
.X() += (nSliderXOffset
- nIncDecWidth
)/2;
508 aImagePoint
.Y() += ( aSliderWindowSize
.Height() - nIncDecHeight
)/2;
509 pVDev
->DrawImage( aImagePoint
, mpImpl
->maDecreaseButton
);
511 // draw increase button
512 aImagePoint
.X() = aRect
.TopLeft().X() + aSliderWindowSize
.Width() - nIncDecWidth
- (nSliderXOffset
- nIncDecWidth
)/2;
513 pVDev
->DrawImage( aImagePoint
, mpImpl
->maIncreaseButton
);
515 DrawOutDev( Point(0, 0), aSliderWindowSize
, Point(0, 0), aSliderWindowSize
, *pVDev
);
521 // -----------------------------------------------------------------------
523 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */