1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svx.hxx"
26 
27 // include ---------------------------------------------------------------
28 #include <svx/zoomsliderctrl.hxx>
29 #ifndef _STATUS_HXX //autogen
30 #include <vcl/status.hxx>
31 #endif
32 #ifndef _MENU_HXX //autogen
33 #include <vcl/menu.hxx>
34 #endif
35 #include <vcl/image.hxx>
36 #include <svx/zoomslideritem.hxx>
37 #include <svx/dialmgr.hxx>
38 #include <svx/dialogs.hrc>
39 
40 #include <set>
41 
42 // -----------------------------------------------------------------------
43 
44 SFX_IMPL_STATUSBAR_CONTROL( SvxZoomSliderControl, SvxZoomSliderItem );
45 
46 // -----------------------------------------------------------------------
47 
48 struct SvxZoomSliderControl::SvxZoomSliderControl_Impl
49 {
50 	sal_uInt16					mnCurrentZoom;
51 	sal_uInt16					mnMinZoom;
52 	sal_uInt16					mnMaxZoom;
53 	sal_uInt16					mnSliderCenter;
54 	std::vector< long >		maSnappingPointOffsets;
55 	std::vector< sal_uInt16 >	maSnappingPointZooms;
56 	Image					maSliderButton;
57 	Image					maIncreaseButton;
58 	Image					maDecreaseButton;
59 	bool					mbValuesSet;
60 	bool					mbOmitPaint;
61 
SvxZoomSliderControl_ImplSvxZoomSliderControl::SvxZoomSliderControl_Impl62 	SvxZoomSliderControl_Impl() :
63 		mnCurrentZoom( 0 ),
64 		mnMinZoom( 0 ),
65 		mnMaxZoom( 0 ),
66 		mnSliderCenter( 0 ),
67 		maSnappingPointOffsets(),
68 		maSnappingPointZooms(),
69 		maSliderButton(),
70 		maIncreaseButton(),
71 		maDecreaseButton(),
72 		mbValuesSet( false ),
73 		mbOmitPaint( false ) {}
74 };
75 
76 // -----------------------------------------------------------------------
77 
78 const long nButtonWidth   = 10;
79 const long nButtonHeight  = 10;
80 const long nIncDecWidth   = 11;
81 const long nIncDecHeight  = 11;
82 const long nSliderHeight  = 2;
83 const long nSnappingHeight = 4;
84 const long nSliderXOffset = 20;
85 const long nSnappingEpsilon = 5; // snapping epsilon in pixels
86 const long nSnappingPointsMinDist = nSnappingEpsilon; // minimum distance of two adjacent snapping points
87 
88 // -----------------------------------------------------------------------
89 
90 // nOffset refers to the origin of the control:
91 // + ----------- -
Offset2Zoom(long nOffset) const92 sal_uInt16 SvxZoomSliderControl::Offset2Zoom( long nOffset ) const
93 {
94 	const long nControlWidth = getControlRect().GetWidth();
95 	sal_uInt16 nRet = 0;
96 
97 	if ( nOffset < nSliderXOffset )
98 		return mpImpl->mnMinZoom;;
99 
100 	if ( nOffset > nControlWidth - nSliderXOffset )
101 		return mpImpl->mnMaxZoom;
102 
103 	// check for snapping points:
104 	sal_uInt16 nCount = 0;
105 	std::vector< long >::iterator aSnappingPointIter;
106 	for ( aSnappingPointIter = mpImpl->maSnappingPointOffsets.begin();
107 		  aSnappingPointIter != mpImpl->maSnappingPointOffsets.end();
108 		  ++aSnappingPointIter )
109 	{
110 		const long nCurrent = *aSnappingPointIter;
111 		if ( Abs(nCurrent - nOffset) < nSnappingEpsilon )
112 		{
113 			nOffset = nCurrent;
114 			nRet = mpImpl->maSnappingPointZooms[ nCount ];
115 			break;
116 		}
117 		++nCount;
118 	}
119 
120 	if ( 0 == nRet )
121 	{
122 		if ( nOffset < nControlWidth / 2 )
123 		{
124 			// first half of slider
125 			const long nFirstHalfRange = mpImpl->mnSliderCenter - mpImpl->mnMinZoom;
126 			const long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
127 			const long nZoomPerSliderPixel = (1000 * nFirstHalfRange) / nHalfSliderWidth;
128 			const long nOffsetToSliderLeft = nOffset - nSliderXOffset;
129 			nRet = mpImpl->mnMinZoom + sal_uInt16( nOffsetToSliderLeft * nZoomPerSliderPixel / 1000 );
130 		}
131 		else
132 		{
133 			// second half of slider
134 			const long nSecondHalfRange = mpImpl->mnMaxZoom - mpImpl->mnSliderCenter;
135 			const long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
136 			const long nZoomPerSliderPixel = 1000 * nSecondHalfRange / nHalfSliderWidth;
137 			const long nOffsetToSliderCenter = nOffset - nControlWidth/2;
138 			nRet = mpImpl->mnSliderCenter + sal_uInt16( nOffsetToSliderCenter * nZoomPerSliderPixel / 1000 );
139 		}
140 	}
141 
142 	if ( nRet < mpImpl->mnMinZoom )
143 		nRet = mpImpl->mnMinZoom;
144 	else if ( nRet > mpImpl->mnMaxZoom )
145 		nRet = mpImpl->mnMaxZoom;
146 
147 	return nRet;
148 }
149 
150 // returns the offset to the left control border
Zoom2Offset(sal_uInt16 nCurrentZoom) const151 long SvxZoomSliderControl::Zoom2Offset( sal_uInt16 nCurrentZoom ) const
152 {
153 	const long nControlWidth = getControlRect().GetWidth();
154 	long nRet = nSliderXOffset;
155 
156 	const long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
157 
158 	if ( nCurrentZoom <= mpImpl->mnSliderCenter )
159 	{
160 		nCurrentZoom = nCurrentZoom - mpImpl->mnMinZoom;
161 		const long nFirstHalfRange = mpImpl->mnSliderCenter - mpImpl->mnMinZoom;
162 		const long nSliderPixelPerZoomPercent = 1000 * nHalfSliderWidth  / nFirstHalfRange;
163 		const long nOffset = (nSliderPixelPerZoomPercent * nCurrentZoom) / 1000;
164 		nRet += nOffset;
165 	}
166 	else
167 	{
168 		nCurrentZoom = nCurrentZoom - mpImpl->mnSliderCenter;
169 		const long nSecondHalfRange = mpImpl->mnMaxZoom - mpImpl->mnSliderCenter;
170 		const long nSliderPixelPerZoomPercent = 1000 * nHalfSliderWidth  / nSecondHalfRange;
171 		const long nOffset = (nSliderPixelPerZoomPercent * nCurrentZoom) / 1000;
172 		nRet += nHalfSliderWidth + nOffset;
173 	}
174 
175 	return nRet;
176 }
177 
178 // -----------------------------------------------------------------------
179 
SvxZoomSliderControl(sal_uInt16 _nSlotId,sal_uInt16 _nId,StatusBar & _rStb)180 SvxZoomSliderControl::SvxZoomSliderControl( sal_uInt16 _nSlotId,  sal_uInt16 _nId, StatusBar& _rStb ) :
181 	SfxStatusBarControl( _nSlotId, _nId, _rStb ),
182 	mpImpl( new SvxZoomSliderControl_Impl )
183 {
184 	const sal_Bool bHC = GetStatusBar().GetSettings().GetStyleSettings().GetHighContrastMode();
185 	mpImpl->maSliderButton   = Image( SVX_RES( bHC ? RID_SVXBMP_SLIDERBUTTON_HC : RID_SVXBMP_SLIDERBUTTON ) );
186 	mpImpl->maIncreaseButton = Image( SVX_RES( bHC ? RID_SVXBMP_SLIDERINCREASE_HC : RID_SVXBMP_SLIDERINCREASE ) );
187 	mpImpl->maDecreaseButton = Image( SVX_RES( bHC ? RID_SVXBMP_SLIDERDECREASE_HC : RID_SVXBMP_SLIDERDECREASE ) );
188 }
189 
190 // -----------------------------------------------------------------------
191 
~SvxZoomSliderControl()192 SvxZoomSliderControl::~SvxZoomSliderControl()
193 {
194 	delete mpImpl;
195 }
196 
197 // -----------------------------------------------------------------------
198 
StateChanged(sal_uInt16,SfxItemState eState,const SfxPoolItem * pState)199 void SvxZoomSliderControl::StateChanged( sal_uInt16 /*nSID*/, SfxItemState eState, const SfxPoolItem* pState )
200 {
201 	if ( (SFX_ITEM_AVAILABLE != eState) || pState->ISA( SfxVoidItem ) )
202 	{
203 		GetStatusBar().SetItemText( GetId(), String() );
204 		mpImpl->mbValuesSet   = false;
205 	}
206 	else
207 	{
208 		OSL_ENSURE( pState->ISA( SvxZoomSliderItem ), "invalid item type: should be a SvxZoomSliderItem" );
209 		mpImpl->mnCurrentZoom = static_cast<const SvxZoomSliderItem*>( pState )->GetValue();
210 		mpImpl->mnMinZoom     = static_cast<const SvxZoomSliderItem*>( pState )->GetMinZoom();
211 		mpImpl->mnMaxZoom     = static_cast<const SvxZoomSliderItem*>( pState )->GetMaxZoom();
212 		mpImpl->mnSliderCenter= 100;
213 		mpImpl->mbValuesSet   = true;
214 
215 		if ( mpImpl->mnSliderCenter == mpImpl->mnMaxZoom )
216 			mpImpl->mnSliderCenter = mpImpl->mnMinZoom + (sal_uInt16)((mpImpl->mnMaxZoom - mpImpl->mnMinZoom) * 0.5);
217 
218 
219 		DBG_ASSERT( mpImpl->mnMinZoom <= mpImpl->mnCurrentZoom &&
220 					mpImpl->mnMinZoom <  mpImpl->mnSliderCenter &&
221 					mpImpl->mnMaxZoom >= mpImpl->mnCurrentZoom &&
222 					mpImpl->mnMaxZoom > mpImpl->mnSliderCenter,
223 					"Looks like the zoom slider item is corrupted" );
224 
225 		const com::sun::star::uno::Sequence < sal_Int32 > rSnappingPoints = static_cast<const SvxZoomSliderItem*>( pState )->GetSnappingPoints();
226 		mpImpl->maSnappingPointOffsets.clear();
227 		mpImpl->maSnappingPointZooms.clear();
228 
229 		// get all snapping points:
230 		std::set< sal_uInt16 > aTmpSnappingPoints;
231 		for ( sal_uInt16 j = 0; j < rSnappingPoints.getLength(); ++j )
232 		{
233 			const sal_Int32 nSnappingPoint = rSnappingPoints[j];
234 			aTmpSnappingPoints.insert( (sal_uInt16)nSnappingPoint );
235 		}
236 
237 		// remove snapping points that are to close to each other:
238 		std::set< sal_uInt16 >::iterator aSnappingPointIter;
239 		long nLastOffset = 0;
240 
241 		for ( aSnappingPointIter = aTmpSnappingPoints.begin(); aSnappingPointIter != aTmpSnappingPoints.end(); ++aSnappingPointIter )
242 		{
243 			const sal_uInt16 nCurrent = *aSnappingPointIter;
244 			const long nCurrentOffset = Zoom2Offset( nCurrent );
245 
246 			if ( nCurrentOffset - nLastOffset >= nSnappingPointsMinDist )
247 			{
248 				mpImpl->maSnappingPointOffsets.push_back( nCurrentOffset );
249 				mpImpl->maSnappingPointZooms.push_back( nCurrent );
250 				nLastOffset = nCurrentOffset;
251 			}
252 		}
253 	}
254 
255 	if ( !mpImpl->mbOmitPaint && GetStatusBar().AreItemsVisible() )
256 		GetStatusBar().SetItemData( GetId(), 0 ); // force repaint
257 }
258 
259 // -----------------------------------------------------------------------
260 
Paint(const UserDrawEvent & rUsrEvt)261 void SvxZoomSliderControl::Paint( const UserDrawEvent& rUsrEvt )
262 {
263 	if ( !mpImpl->mbValuesSet || mpImpl->mbOmitPaint )
264 		return;
265 
266 	const Rectangle		aControlRect = getControlRect();
267 	OutputDevice*		pDev =  rUsrEvt.GetDevice();
268 	Rectangle			aRect = rUsrEvt.GetRect();
269 	Rectangle			aSlider = aRect;
270 
271 	aSlider.Top()   += (aControlRect.GetHeight() - nSliderHeight)/2 - 1;
272 	aSlider.Bottom() = aSlider.Top() + nSliderHeight;
273 	aSlider.Left()  += nSliderXOffset;
274 	aSlider.Right() -= nSliderXOffset;
275 
276 	Color				aOldLineColor = pDev->GetLineColor();
277 	Color				aOldFillColor = pDev->GetFillColor();
278 
279 	pDev->SetLineColor( Color( COL_GRAY ) );
280 	pDev->SetFillColor( Color( COL_GRAY ) );
281 
282 	// draw snapping points:
283 	std::vector< long >::iterator aSnappingPointIter;
284 	for ( aSnappingPointIter = mpImpl->maSnappingPointOffsets.begin();
285 		  aSnappingPointIter != mpImpl->maSnappingPointOffsets.end();
286 		  ++aSnappingPointIter )
287 	{
288 		Rectangle aSnapping( aRect );
289 		aSnapping.Bottom()   = aSlider.Top();
290 		aSnapping.Top() = aSnapping.Bottom() - nSnappingHeight;
291 		aSnapping.Left() += *aSnappingPointIter;
292 		aSnapping.Right() = aSnapping.Left();
293 		pDev->DrawRect( aSnapping );
294 
295 		aSnapping.Top() += nSnappingHeight + nSliderHeight;
296 		aSnapping.Bottom() += nSnappingHeight + nSliderHeight;
297 		pDev->DrawRect( aSnapping );
298 	}
299 
300 	// draw slider
301 	Rectangle aFirstLine( aSlider );
302 	aFirstLine.Bottom() = aFirstLine.Top();
303 
304 	Rectangle aSecondLine( aSlider );
305 	aSecondLine.Top() = aSecondLine.Bottom();
306 
307 	Rectangle aLeft( aSlider );
308 	aLeft.Right() = aLeft.Left();
309 
310 	Rectangle aRight( aSlider );
311 	aRight.Left() = aRight.Right();
312 
313 	pDev->SetLineColor( Color ( COL_GRAY ) );
314 	pDev->SetFillColor( Color ( COL_GRAY ) );
315 	pDev->DrawRect( aSecondLine );
316 	pDev->DrawRect( aRight );
317 
318 	pDev->SetLineColor( Color( COL_GRAY ) );
319 	pDev->SetFillColor( Color( COL_GRAY ) );
320 	pDev->DrawRect( aFirstLine );
321 	pDev->DrawRect( aLeft );
322 
323 	// draw slider button
324 	Point aImagePoint = aRect.TopLeft();
325 	aImagePoint.X() += Zoom2Offset( mpImpl->mnCurrentZoom );
326 	aImagePoint.X() -= nButtonWidth/2;
327 	aImagePoint.Y() += (aControlRect.GetHeight() - nButtonHeight)/2;
328 	pDev->DrawImage( aImagePoint, mpImpl->maSliderButton );
329 
330 	// draw decrease button
331 	aImagePoint = aRect.TopLeft();
332 	aImagePoint.X() += (nSliderXOffset - nIncDecWidth)/2;
333 	aImagePoint.Y() += (aControlRect.GetHeight() - nIncDecHeight)/2;
334 	pDev->DrawImage( aImagePoint, mpImpl->maDecreaseButton );
335 
336 	// draw increase button
337 	aImagePoint.X() = aRect.TopLeft().X() + aControlRect.GetWidth() - nIncDecWidth - (nSliderXOffset - nIncDecWidth)/2;
338 	pDev->DrawImage( aImagePoint, mpImpl->maIncreaseButton );
339 
340 	pDev->SetLineColor( aOldLineColor );
341 	pDev->SetFillColor( aOldFillColor );
342 }
343 
344 // -----------------------------------------------------------------------
345 
MouseButtonDown(const MouseEvent & rEvt)346 sal_Bool SvxZoomSliderControl::MouseButtonDown( const MouseEvent & rEvt )
347 {
348 	if ( !mpImpl->mbValuesSet )
349 		return sal_True;;
350 
351 	const Rectangle aControlRect = getControlRect();
352 	const Point aPoint = rEvt.GetPosPixel();
353 	const sal_Int32 nXDiff = aPoint.X() - aControlRect.Left();
354 
355 	const long nButtonLeftOffset = (nSliderXOffset - nIncDecWidth)/2;
356 	const long nButtonRightOffset = (nSliderXOffset + nIncDecWidth)/2;
357 
358 	const long nOldZoom = mpImpl->mnCurrentZoom;
359 
360 	// click to - button
361 	if ( nXDiff >= nButtonLeftOffset && nXDiff <= nButtonRightOffset )
362 		mpImpl->mnCurrentZoom = mpImpl->mnCurrentZoom - 5;
363 	// click to + button
364 	else if ( nXDiff >= aControlRect.GetWidth() - nSliderXOffset + nButtonLeftOffset &&
365 			  nXDiff <= aControlRect.GetWidth() - nSliderXOffset + nButtonRightOffset )
366 		mpImpl->mnCurrentZoom = mpImpl->mnCurrentZoom + 5;
367 	// click to slider
368 	else if( nXDiff >= nSliderXOffset && nXDiff <= aControlRect.GetWidth() - nSliderXOffset )
369 		mpImpl->mnCurrentZoom = Offset2Zoom( nXDiff );
370 
371 	if ( mpImpl->mnCurrentZoom < mpImpl->mnMinZoom )
372 		mpImpl->mnCurrentZoom = mpImpl->mnMinZoom;
373 	else if ( mpImpl->mnCurrentZoom > mpImpl->mnMaxZoom )
374 		mpImpl->mnCurrentZoom = mpImpl->mnMaxZoom;
375 
376 	if ( nOldZoom == mpImpl->mnCurrentZoom )
377 		return sal_True;
378 
379 	if ( GetStatusBar().AreItemsVisible() )
380 		GetStatusBar().SetItemData( GetId(), 0 ); // force repaint
381 
382 	mpImpl->mbOmitPaint = true; // optimization: paint before executing command,
383 								// then omit painting which is triggered by the execute function
384 
385 	SvxZoomSliderItem aZoomSliderItem( mpImpl->mnCurrentZoom );
386 
387 	::com::sun::star::uno::Any a;
388 	aZoomSliderItem.QueryValue( a );
389 
390 	::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aArgs( 1 );
391 	aArgs[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ZoomSlider" ));
392 	aArgs[0].Value = a;
393 
394 	execute( aArgs );
395 
396 	mpImpl->mbOmitPaint = false;
397 
398 	return sal_True;
399 }
400 
401 // -----------------------------------------------------------------------
402 
MouseMove(const MouseEvent & rEvt)403 sal_Bool SvxZoomSliderControl::MouseMove( const MouseEvent & rEvt )
404 {
405 	if ( !mpImpl->mbValuesSet )
406 		return sal_True;;
407 
408 	const short nButtons = rEvt.GetButtons();
409 
410 	// check mouse move with button pressed
411 	if ( 1 == nButtons )
412 	{
413 		const Rectangle aControlRect = getControlRect();
414 		const Point aPoint = rEvt.GetPosPixel();
415 		const sal_Int32 nXDiff = aPoint.X() - aControlRect.Left();
416 
417 		if ( nXDiff >= nSliderXOffset && nXDiff <= aControlRect.GetWidth() - nSliderXOffset )
418 		{
419 			mpImpl->mnCurrentZoom = Offset2Zoom( nXDiff );
420 
421 			if ( GetStatusBar().AreItemsVisible() )
422 				GetStatusBar().SetItemData( GetId(), 0 ); // force repaint
423 
424 			mpImpl->mbOmitPaint = true; // optimization: paint before executing command,
425 										// then omit painting which is triggered by the execute function
426 
427 			// commit state change
428 			SvxZoomSliderItem aZoomSliderItem( mpImpl->mnCurrentZoom );
429 
430 			::com::sun::star::uno::Any a;
431 			aZoomSliderItem.QueryValue( a );
432 
433 			::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aArgs( 1 );
434 			aArgs[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ZoomSlider" ));
435 			aArgs[0].Value = a;
436 
437 			execute( aArgs );
438 
439 			mpImpl->mbOmitPaint = false;
440 		}
441 	}
442 
443 	return sal_True;
444 }
445 
446 /* vim: set noet sw=4 ts=4: */
447