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 62 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 // + ----------- - 92 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 151 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 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 192 SvxZoomSliderControl::~SvxZoomSliderControl() 193 { 194 delete mpImpl; 195 } 196 197 // ----------------------------------------------------------------------- 198 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 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_WHITE ) ); 314 pDev->SetFillColor( Color ( COL_WHITE ) ); 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 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 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