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