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 referes 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