1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 #include "precompiled_sc.hxx" 28 #ifndef _SC_ZOOMSLIDERTBCONTRL_HXX 29 #include "tbzoomsliderctrl.hxx" 30 #endif 31 #ifndef _SV_IMAGE_HXX 32 #include <vcl/image.hxx> 33 #endif 34 #ifndef _SV_TOOLBOX_HXX 35 #include <vcl/toolbox.hxx> 36 #endif 37 #ifndef _SV_SVAPP_HXX 38 #include <vcl/svapp.hxx> 39 #endif 40 #ifndef _SV_GRADIENT_HXX 41 #include <vcl/gradient.hxx> 42 #endif 43 #include <svl/itemset.hxx> 44 #include <sfx2/viewfrm.hxx> 45 #include <sfx2/objsh.hxx> 46 #include <svx/zoomslideritem.hxx> 47 #include <svx/dialmgr.hxx> 48 #include <svx/dialogs.hrc> 49 #include <set> 50 #include "docsh.hxx" 51 #include "stlpool.hxx" 52 #include "scitems.hxx" 53 #include "printfun.hxx" 54 55 //======================================================================== 56 // class ScZoomSliderControl --------------------------------------- 57 //======================================================================== 58 59 // ----------------------------------------------------------------------- 60 61 SFX_IMPL_TOOLBOX_CONTROL( ScZoomSliderControl, SvxZoomSliderItem ); 62 63 // ----------------------------------------------------------------------- 64 65 ScZoomSliderControl::ScZoomSliderControl( 66 sal_uInt16 nSlotId, 67 sal_uInt16 nId, 68 ToolBox& rTbx ) 69 :SfxToolBoxControl( nSlotId, nId, rTbx ) 70 { 71 rTbx.Invalidate(); 72 } 73 74 // ----------------------------------------------------------------------- 75 76 __EXPORT ScZoomSliderControl::~ScZoomSliderControl() 77 { 78 79 } 80 81 // ----------------------------------------------------------------------- 82 83 void ScZoomSliderControl::StateChanged( sal_uInt16 /*nSID*/, SfxItemState eState, 84 const SfxPoolItem* pState ) 85 { 86 sal_uInt16 nId = GetId(); 87 ToolBox& rTbx = GetToolBox(); 88 ScZoomSliderWnd* pBox = (ScZoomSliderWnd*)(rTbx.GetItemWindow( nId )); 89 DBG_ASSERT( pBox ,"Control not found!" ); 90 91 if ( SFX_ITEM_AVAILABLE != eState || pState->ISA( SfxVoidItem ) ) 92 { 93 SvxZoomSliderItem aZoomSliderItem( 100 ); 94 pBox->Disable(); 95 pBox->UpdateFromItem( &aZoomSliderItem ); 96 } 97 else 98 { 99 pBox->Enable(); 100 DBG_ASSERT( pState->ISA( SvxZoomSliderItem ), "invalid item type" ); 101 const SvxZoomSliderItem* pZoomSliderItem = dynamic_cast< const SvxZoomSliderItem* >( pState ); 102 103 DBG_ASSERT( pZoomSliderItem, "Sc::ScZoomSliderControl::StateChanged(), wrong item type!" ); 104 if( pZoomSliderItem ) 105 pBox->UpdateFromItem( pZoomSliderItem ); 106 } 107 } 108 109 // ----------------------------------------------------------------------- 110 111 Window* ScZoomSliderControl::CreateItemWindow( Window *pParent ) 112 { 113 // #i98000# Don't try to get a value via SfxViewFrame::Current here. 114 // The view's value is always notified via StateChanged later. 115 ScZoomSliderWnd* pSlider = new ScZoomSliderWnd( pParent, 116 ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider >( m_xFrame->getController(), 117 ::com::sun::star::uno::UNO_QUERY ), m_xFrame, 100 ); 118 return pSlider; 119 } 120 121 // ----------------------------------------------------------------------- 122 123 struct ScZoomSliderWnd::ScZoomSliderWnd_Impl 124 { 125 sal_uInt16 mnCurrentZoom; 126 sal_uInt16 mnMinZoom; 127 sal_uInt16 mnMaxZoom; 128 sal_uInt16 mnSliderCenter; 129 std::vector< long > maSnappingPointOffsets; 130 std::vector< sal_uInt16 > maSnappingPointZooms; 131 Image maSliderButton; 132 Image maIncreaseButton; 133 Image maDecreaseButton; 134 bool mbValuesSet; 135 bool mbOmitPaint; 136 137 ScZoomSliderWnd_Impl( sal_uInt16 nCurrentZoom ) : 138 mnCurrentZoom( nCurrentZoom ), 139 mnMinZoom( 10 ), 140 mnMaxZoom( 400 ), 141 mnSliderCenter( 100 ), 142 maSnappingPointOffsets(), 143 maSnappingPointZooms(), 144 maSliderButton(), 145 maIncreaseButton(), 146 maDecreaseButton(), 147 mbValuesSet( true ), 148 mbOmitPaint( false ) 149 { 150 151 } 152 }; 153 154 // ----------------------------------------------------------------------- 155 156 const long nButtonWidth = 10; 157 const long nButtonHeight = 10; 158 const long nIncDecWidth = 11; 159 const long nIncDecHeight = 11; 160 const long nSliderHeight = 2; // 161 const long nSliderWidth = 4; // 162 const long nSnappingHeight = 4; 163 const long nSliderXOffset = 20; 164 const long nSnappingEpsilon = 5; // snapping epsilon in pixels 165 const long nSnappingPointsMinDist = nSnappingEpsilon; // minimum distance of two adjacent snapping points 166 167 168 // ----------------------------------------------------------------------- 169 170 sal_uInt16 ScZoomSliderWnd::Offset2Zoom( long nOffset ) const 171 { 172 Size aSliderWindowSize = GetOutputSizePixel(); 173 const long nControlWidth = aSliderWindowSize.Width(); 174 sal_uInt16 nRet = 0; 175 176 if( nOffset < nSliderXOffset ) 177 return mpImpl->mnMinZoom; 178 if( nOffset > nControlWidth - nSliderXOffset ) 179 return mpImpl->mnMaxZoom; 180 181 // check for snapping points: 182 sal_uInt16 nCount = 0; 183 std::vector< long >::iterator aSnappingPointIter; 184 for ( aSnappingPointIter = mpImpl->maSnappingPointOffsets.begin(); 185 aSnappingPointIter != mpImpl->maSnappingPointOffsets.end(); 186 ++aSnappingPointIter ) 187 { 188 const long nCurrent = *aSnappingPointIter; 189 if ( Abs(nCurrent - nOffset) < nSnappingEpsilon ) 190 { 191 nOffset = nCurrent; 192 nRet = mpImpl->maSnappingPointZooms[ nCount ]; 193 break; 194 } 195 ++nCount; 196 } 197 198 if( 0 == nRet ) 199 { 200 if( nOffset < nControlWidth / 2 ) 201 { 202 // first half of slider 203 const long nFirstHalfRange = mpImpl->mnSliderCenter - mpImpl->mnMinZoom; 204 const long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset; 205 const long nZoomPerSliderPixel = (1000 * nFirstHalfRange) / nHalfSliderWidth; 206 const long nOffsetToSliderLeft = nOffset - nSliderXOffset; 207 nRet = mpImpl->mnMinZoom + sal_uInt16( nOffsetToSliderLeft * nZoomPerSliderPixel / 1000 ); 208 } 209 else 210 { 211 // second half of slider 212 const long nSecondHalfRange = mpImpl->mnMaxZoom - mpImpl->mnSliderCenter; 213 const long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset; 214 const long nZoomPerSliderPixel = 1000 * nSecondHalfRange / nHalfSliderWidth; 215 const long nOffsetToSliderCenter = nOffset - nControlWidth/2; 216 nRet = mpImpl->mnSliderCenter + sal_uInt16( nOffsetToSliderCenter * nZoomPerSliderPixel / 1000 ); 217 } 218 } 219 220 if( nRet < mpImpl->mnMinZoom ) 221 return mpImpl->mnMinZoom; 222 223 else if( nRet > mpImpl->mnMaxZoom ) 224 return mpImpl->mnMaxZoom; 225 226 return nRet; 227 } 228 229 // ----------------------------------------------------------------------- 230 231 long ScZoomSliderWnd::Zoom2Offset( sal_uInt16 nCurrentZoom ) const 232 { 233 Size aSliderWindowSize = GetOutputSizePixel(); 234 const long nControlWidth = aSliderWindowSize.Width(); 235 long nRect = nSliderXOffset; 236 237 const long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset; 238 if( nCurrentZoom <= mpImpl->mnSliderCenter ) 239 { 240 nCurrentZoom = nCurrentZoom - mpImpl->mnMinZoom; 241 const long nFirstHalfRange = mpImpl->mnSliderCenter - mpImpl->mnMinZoom; 242 const long nSliderPixelPerZoomPercent = 1000 * nHalfSliderWidth / nFirstHalfRange; 243 const long nOffset = (nSliderPixelPerZoomPercent * nCurrentZoom) / 1000; 244 nRect += nOffset; 245 } 246 else 247 { 248 nCurrentZoom = nCurrentZoom - mpImpl->mnSliderCenter; 249 const long nSecondHalfRange = mpImpl->mnMaxZoom - mpImpl->mnSliderCenter; 250 const long nSliderPixelPerZoomPercent = 1000 * nHalfSliderWidth / nSecondHalfRange; 251 const long nOffset = (nSliderPixelPerZoomPercent * nCurrentZoom) / 1000; 252 nRect += nHalfSliderWidth + nOffset; 253 } 254 return nRect; 255 } 256 257 // ----------------------------------------------------------------------- 258 259 260 ScZoomSliderWnd::ScZoomSliderWnd( Window* pParent, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider >& rDispatchProvider, 261 const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& _xFrame , sal_uInt16 nCurrentZoom ): 262 Window( pParent ), 263 mpImpl( new ScZoomSliderWnd_Impl( nCurrentZoom ) ), 264 aLogicalSize( 115, 40 ), 265 m_xDispatchProvider( rDispatchProvider ), 266 m_xFrame( _xFrame ) 267 { 268 sal_Bool bIsHC = GetSettings().GetStyleSettings().GetHighContrastMode(); 269 mpImpl->maSliderButton = Image( SVX_RES( bIsHC ? RID_SVXBMP_SLIDERBUTTON_HC : RID_SVXBMP_SLIDERBUTTON ) ); 270 mpImpl->maIncreaseButton = Image( SVX_RES( bIsHC ? RID_SVXBMP_SLIDERINCREASE_HC : RID_SVXBMP_SLIDERINCREASE ) ); 271 mpImpl->maDecreaseButton = Image( SVX_RES( bIsHC ? RID_SVXBMP_SLIDERDECREASE_HC : RID_SVXBMP_SLIDERDECREASE ) ); 272 Size aSliderSize = LogicToPixel( Size( aLogicalSize), MapMode( MAP_10TH_MM ) ); 273 SetSizePixel( Size( aSliderSize.Width() * nSliderWidth-1, aSliderSize.Height() + nSliderHeight ) ); 274 } 275 276 // ----------------------------------------------------------------------- 277 278 ScZoomSliderWnd::~ScZoomSliderWnd() 279 { 280 delete mpImpl; 281 } 282 283 // ----------------------------------------------------------------------- 284 285 void ScZoomSliderWnd::MouseButtonDown( const MouseEvent& rMEvt ) 286 { 287 if ( !mpImpl->mbValuesSet ) 288 return ; 289 Size aSliderWindowSize = GetOutputSizePixel(); 290 291 const Point aPoint = rMEvt.GetPosPixel(); 292 293 const long nButtonLeftOffset = ( nSliderXOffset - nIncDecWidth )/2; 294 const long nButtonRightOffset = ( nSliderXOffset + nIncDecWidth )/2; 295 296 const long nOldZoom = mpImpl->mnCurrentZoom; 297 298 // click to - button 299 if ( aPoint.X() >= nButtonLeftOffset && aPoint.X() <= nButtonRightOffset ) 300 { 301 mpImpl->mnCurrentZoom = mpImpl->mnCurrentZoom - 5; 302 } 303 // click to + button 304 else if ( aPoint.X() >= aSliderWindowSize.Width() - nSliderXOffset + nButtonLeftOffset && 305 aPoint.X() <= aSliderWindowSize.Width() - nSliderXOffset + nButtonRightOffset ) 306 { 307 mpImpl->mnCurrentZoom = mpImpl->mnCurrentZoom + 5; 308 } 309 else if( aPoint.X() >= nSliderXOffset && aPoint.X() <= aSliderWindowSize.Width() - nSliderXOffset ) 310 { 311 mpImpl->mnCurrentZoom = Offset2Zoom( aPoint.X() ); 312 } 313 314 if( mpImpl->mnCurrentZoom < mpImpl->mnMinZoom ) 315 mpImpl->mnCurrentZoom = mpImpl->mnMinZoom; 316 else if( mpImpl->mnCurrentZoom > mpImpl->mnMaxZoom ) 317 mpImpl->mnCurrentZoom = mpImpl->mnMaxZoom; 318 319 if( nOldZoom == mpImpl->mnCurrentZoom ) 320 return ; 321 322 Rectangle aRect( Point( 0, 0 ), aSliderWindowSize ); 323 324 Paint( aRect ); 325 mpImpl->mbOmitPaint = true; 326 327 SvxZoomSliderItem aZoomSliderItem( mpImpl->mnCurrentZoom ); 328 329 ::com::sun::star::uno::Any a; 330 aZoomSliderItem.QueryValue( a ); 331 332 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aArgs( 1 ); 333 aArgs[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ScalingFactor" )); 334 aArgs[0].Value = a; 335 336 SfxToolBoxControl::Dispatch( m_xDispatchProvider, String::CreateFromAscii(".uno:ScalingFactor"), aArgs ); 337 338 mpImpl->mbOmitPaint = false; 339 } 340 341 // ----------------------------------------------------------------------- 342 343 void ScZoomSliderWnd::MouseMove( const MouseEvent& rMEvt ) 344 { 345 if ( !mpImpl->mbValuesSet ) 346 return ; 347 348 Size aSliderWindowSize = GetOutputSizePixel(); 349 const long nControlWidth = aSliderWindowSize.Width(); 350 const short nButtons = rMEvt.GetButtons(); 351 352 // check mouse move with button pressed 353 if ( 1 == nButtons ) 354 { 355 const Point aPoint = rMEvt.GetPosPixel(); 356 357 if ( aPoint.X() >= nSliderXOffset && aPoint.X() <= nControlWidth - nSliderXOffset ) 358 { 359 mpImpl->mnCurrentZoom = Offset2Zoom( aPoint.X() ); 360 361 Rectangle aRect( Point( 0, 0 ), aSliderWindowSize ); 362 Paint( aRect ); 363 364 mpImpl->mbOmitPaint = true; // optimization: paint before executing command, 365 366 // commit state change 367 SvxZoomSliderItem aZoomSliderItem( mpImpl->mnCurrentZoom ); 368 369 ::com::sun::star::uno::Any a; 370 aZoomSliderItem.QueryValue( a ); 371 372 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aArgs( 1 ); 373 aArgs[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ScalingFactor" )); 374 aArgs[0].Value = a; 375 376 SfxToolBoxControl::Dispatch( m_xDispatchProvider, String::CreateFromAscii(".uno:ScalingFactor"), aArgs ); 377 378 mpImpl->mbOmitPaint = false; 379 } 380 } 381 } 382 383 // ----------------------------------------------------------------------- 384 385 void ScZoomSliderWnd::UpdateFromItem( const SvxZoomSliderItem* pZoomSliderItem ) 386 { 387 if( pZoomSliderItem ) 388 { 389 mpImpl->mnCurrentZoom = pZoomSliderItem->GetValue(); 390 mpImpl->mnMinZoom = pZoomSliderItem->GetMinZoom(); 391 mpImpl->mnMaxZoom = pZoomSliderItem->GetMaxZoom(); 392 393 DBG_ASSERT( mpImpl->mnMinZoom <= mpImpl->mnCurrentZoom && 394 mpImpl->mnMinZoom < mpImpl->mnSliderCenter && 395 mpImpl->mnMaxZoom >= mpImpl->mnCurrentZoom && 396 mpImpl->mnMaxZoom > mpImpl->mnSliderCenter, 397 "Looks like the zoom slider item is corrupted" ); 398 const com::sun::star::uno::Sequence < sal_Int32 > rSnappingPoints = pZoomSliderItem->GetSnappingPoints(); 399 mpImpl->maSnappingPointOffsets.clear(); 400 mpImpl->maSnappingPointZooms.clear(); 401 402 // get all snapping points: 403 std::set< sal_uInt16 > aTmpSnappingPoints; 404 for ( sal_uInt16 j = 0; j < rSnappingPoints.getLength(); ++j ) 405 { 406 const sal_Int32 nSnappingPoint = rSnappingPoints[j]; 407 aTmpSnappingPoints.insert( (sal_uInt16)nSnappingPoint ); 408 } 409 410 // remove snapping points that are to close to each other: 411 std::set< sal_uInt16 >::iterator aSnappingPointIter; 412 long nLastOffset = 0; 413 414 for ( aSnappingPointIter = aTmpSnappingPoints.begin(); aSnappingPointIter != aTmpSnappingPoints.end(); ++aSnappingPointIter ) 415 { 416 const sal_uInt16 nCurrent = *aSnappingPointIter; 417 const long nCurrentOffset = Zoom2Offset( nCurrent ); 418 419 if ( nCurrentOffset - nLastOffset >= nSnappingPointsMinDist ) 420 { 421 mpImpl->maSnappingPointOffsets.push_back( nCurrentOffset ); 422 mpImpl->maSnappingPointZooms.push_back( nCurrent ); 423 nLastOffset = nCurrentOffset; 424 } 425 } 426 } 427 428 Size aSliderWindowSize = GetOutputSizePixel(); 429 Rectangle aRect( Point( 0, 0 ), aSliderWindowSize ); 430 431 if ( !mpImpl->mbOmitPaint ) 432 Paint(aRect); 433 } 434 435 // ----------------------------------------------------------------------- 436 437 void ScZoomSliderWnd::Paint( const Rectangle& rRect ) 438 { 439 DoPaint( rRect ); 440 } 441 442 // ----------------------------------------------------------------------- 443 444 void ScZoomSliderWnd::DoPaint( const Rectangle& /*rRect*/ ) 445 { 446 if( mpImpl->mbOmitPaint ) 447 return; 448 449 Size aSliderWindowSize = GetOutputSizePixel(); 450 Rectangle aRect( Point( 0, 0 ), aSliderWindowSize ); 451 452 VirtualDevice* pVDev = new VirtualDevice( *this ); 453 pVDev->SetOutputSizePixel( aSliderWindowSize ); 454 455 Rectangle aSlider = aRect; 456 457 aSlider.Top() += ( aSliderWindowSize.Height() - nSliderHeight )/2 - 1; 458 aSlider.Bottom() = aSlider.Top() + nSliderHeight; 459 aSlider.Left() += nSliderXOffset; 460 aSlider.Right() -= nSliderXOffset; 461 462 Rectangle aFirstLine( aSlider ); 463 aFirstLine.Bottom() = aFirstLine.Top(); 464 465 Rectangle aSecondLine( aSlider ); 466 aSecondLine.Top() = aSecondLine.Bottom(); 467 468 Rectangle aLeft( aSlider ); 469 aLeft.Right() = aLeft.Left(); 470 471 Rectangle aRight( aSlider ); 472 aRight.Left() = aRight.Right(); 473 474 // draw VirtualDevice's background color 475 Color aStartColor,aEndColor; 476 aStartColor = GetSettings().GetStyleSettings().GetFaceColor(); 477 aEndColor = GetSettings().GetStyleSettings().GetFaceColor(); 478 if( aEndColor.IsDark() ) 479 aStartColor = aEndColor; 480 481 Gradient g; 482 g.SetAngle( 0 ); 483 g.SetStyle( GRADIENT_LINEAR ); 484 485 g.SetStartColor( aStartColor ); 486 g.SetEndColor( aEndColor ); 487 pVDev->DrawGradient( aRect, g ); 488 489 // draw slider 490 pVDev->SetLineColor( Color ( COL_WHITE ) ); 491 pVDev->DrawRect( aSecondLine ); 492 pVDev->DrawRect( aRight ); 493 494 pVDev->SetLineColor( Color( COL_GRAY ) ); 495 pVDev->DrawRect( aFirstLine ); 496 pVDev->DrawRect( aLeft ); 497 498 // draw snapping points: 499 std::vector< long >::iterator aSnappingPointIter; 500 for ( aSnappingPointIter = mpImpl->maSnappingPointOffsets.begin(); 501 aSnappingPointIter != mpImpl->maSnappingPointOffsets.end(); 502 ++aSnappingPointIter ) 503 { 504 pVDev->SetLineColor( Color( COL_GRAY ) ); 505 Rectangle aSnapping( aRect ); 506 aSnapping.Bottom() = aSlider.Top(); 507 aSnapping.Top() = aSnapping.Bottom() - nSnappingHeight; 508 aSnapping.Left() += *aSnappingPointIter; 509 aSnapping.Right() = aSnapping.Left(); 510 pVDev->DrawRect( aSnapping ); 511 512 aSnapping.Top() += nSnappingHeight + nSliderHeight; 513 aSnapping.Bottom() += nSnappingHeight + nSliderHeight; 514 pVDev->DrawRect( aSnapping ); 515 } 516 517 // draw slider button 518 Point aImagePoint = aRect.TopLeft(); 519 aImagePoint.X() += Zoom2Offset( mpImpl->mnCurrentZoom ); 520 aImagePoint.X() -= nButtonWidth/2; 521 aImagePoint.Y() += ( aSliderWindowSize.Height() - nButtonHeight)/2; 522 pVDev->DrawImage( aImagePoint, mpImpl->maSliderButton ); 523 524 // draw decrease button 525 aImagePoint = aRect.TopLeft(); 526 aImagePoint.X() += (nSliderXOffset - nIncDecWidth)/2; 527 aImagePoint.Y() += ( aSliderWindowSize.Height() - nIncDecHeight)/2; 528 pVDev->DrawImage( aImagePoint, mpImpl->maDecreaseButton ); 529 530 // draw increase button 531 aImagePoint.X() = aRect.TopLeft().X() + aSliderWindowSize.Width() - nIncDecWidth - (nSliderXOffset - nIncDecWidth)/2; 532 pVDev->DrawImage( aImagePoint, mpImpl->maIncreaseButton ); 533 534 DrawOutDev( Point(0, 0), aSliderWindowSize, Point(0, 0), aSliderWindowSize, *pVDev ); 535 536 delete pVDev; 537 538 } 539 540 // ----------------------------------------------------------------------- 541