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