Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / ui / cctrl / tbzoomsliderctrl.cxx
blob7ad70b24d60dff455f336ae54f1edb688f589f5a
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 .
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>
31 #include <set>
32 #include "docsh.hxx"
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(
48 sal_uInt16 nSlotId,
49 sal_uInt16 nId,
50 ToolBox& rTbx )
51 :SfxToolBoxControl( nSlotId, nId, rTbx )
53 rTbx.Invalidate();
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 );
76 pBox->Disable();
77 pBox->UpdateFromItem( &aZoomSliderItem );
79 else
81 pBox->Enable();
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!" );
86 if( pZoomSliderItem )
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 );
100 return pSlider;
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;
116 bool mbValuesSet;
117 bool mbOmitPaint;
119 ScZoomSliderWnd_Impl( sal_uInt16 nCurrentZoom ) :
120 mnCurrentZoom( nCurrentZoom ),
121 mnMinZoom( 10 ),
122 mnMaxZoom( 400 ),
123 mnSliderCenter( 100 ),
124 maSnappingPointOffsets(),
125 maSnappingPointZooms(),
126 maSliderButton(),
127 maIncreaseButton(),
128 maDecreaseButton(),
129 mbValuesSet( true ),
130 mbOmitPaint( false )
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();
156 sal_uInt16 nRet = 0;
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 )
173 nOffset = nCurrent;
174 nRet = mpImpl->maSnappingPointZooms[ nCount ];
175 break;
177 ++nCount;
180 if( 0 == nRet )
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 );
191 else
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;
208 return nRet;
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;
226 nRect += nOffset;
228 else
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;
236 return nRect;
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 ):
244 Window( pParent ),
245 mpImpl( new ScZoomSliderWnd_Impl( nCurrentZoom ) ),
246 aLogicalSize( 115, 40 ),
247 m_xDispatchProvider( rDispatchProvider ),
248 m_xFrame( _xFrame )
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()
261 delete mpImpl;
264 // -----------------------------------------------------------------------
266 void ScZoomSliderWnd::MouseButtonDown( const MouseEvent& rMEvt )
268 if ( !mpImpl->mbValuesSet )
269 return ;
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;
279 // click to - button
280 if ( aPoint.X() >= nButtonLeftOffset && aPoint.X() <= nButtonRightOffset )
282 mpImpl->mnCurrentZoom = mpImpl->mnCurrentZoom - 5;
284 // click to + button
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 )
301 return ;
303 Rectangle aRect( Point( 0, 0 ), aSliderWindowSize );
305 Paint( aRect );
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";
315 aArgs[0].Value = a;
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 )
327 return ;
329 Size aSliderWindowSize = GetOutputSizePixel();
330 const long nControlWidth = aSliderWindowSize.Width();
331 const short nButtons = rMEvt.GetButtons();
333 // check mouse move with button pressed
334 if ( 1 == nButtons )
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 );
343 Paint( aRect );
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";
355 aArgs[0].Value = a;
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 )
413 Paint(aRect);
416 // -----------------------------------------------------------------------
418 void ScZoomSliderWnd::Paint( const Rectangle& rRect )
420 DoPaint( rRect );
423 // -----------------------------------------------------------------------
425 void ScZoomSliderWnd::DoPaint( const Rectangle& /*rRect*/ )
427 if( mpImpl->mbOmitPaint )
428 return;
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;
462 Gradient g;
463 g.SetAngle( 0 );
464 g.SetStyle( GradientStyle_LINEAR );
466 g.SetStartColor( aStartColor );
467 g.SetEndColor( aEndColor );
468 pVDev->DrawGradient( aRect, g );
470 // draw slider
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 );
517 delete pVDev;
521 // -----------------------------------------------------------------------
523 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */