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 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_svtools.hxx" 30 31 #define _SVT_SCRWIN_CXX 32 #include <svtools/scrwin.hxx> 33 34 //=================================================================== 35 36 void ScrollableWindow::ImpInitialize( ScrollableWindowFlags nFlags ) 37 { 38 bHandleDragging = (sal_Bool) ( nFlags & SCRWIN_THUMBDRAGGING ); 39 bVCenter = (nFlags & SCRWIN_VCENTER) == SCRWIN_VCENTER; 40 bHCenter = (nFlags & SCRWIN_HCENTER) == SCRWIN_HCENTER; 41 bScrolling = sal_False; 42 43 // set the handlers for the scrollbars 44 aVScroll.SetScrollHdl( LINK(this, ScrollableWindow, ScrollHdl) ); 45 aHScroll.SetScrollHdl( LINK(this, ScrollableWindow, ScrollHdl) ); 46 aVScroll.SetEndScrollHdl( LINK(this, ScrollableWindow, EndScrollHdl) ); 47 aHScroll.SetEndScrollHdl( LINK(this, ScrollableWindow, EndScrollHdl) ); 48 49 nColumnPixW = nLinePixH = GetSettings().GetStyleSettings().GetScrollBarSize(); 50 } 51 52 //------------------------------------------------------------------- 53 54 ScrollableWindow::ScrollableWindow( Window* pParent, WinBits nBits, 55 ScrollableWindowFlags nFlags ) : 56 Window( pParent, WinBits(nBits|WB_CLIPCHILDREN) ), 57 aVScroll( this, WinBits(WB_VSCROLL | WB_DRAG) ), 58 aHScroll( this, WinBits(WB_HSCROLL | WB_DRAG) ), 59 aCornerWin( this ) 60 { 61 ImpInitialize( nFlags ); 62 } 63 64 //------------------------------------------------------------------- 65 66 ScrollableWindow::ScrollableWindow( Window* pParent, const ResId& rId, 67 ScrollableWindowFlags nFlags ) : 68 Window( pParent, rId ), 69 aVScroll( this, WinBits(WB_VSCROLL | WB_DRAG) ), 70 aHScroll( this, WinBits(WB_HSCROLL | WB_DRAG) ), 71 aCornerWin( this ) 72 { 73 ImpInitialize( nFlags ); 74 } 75 76 // ----------------------------------------------------------------------- 77 78 void ScrollableWindow::Command( const CommandEvent& rCEvt ) 79 { 80 if ( (rCEvt.GetCommand() == COMMAND_WHEEL) || 81 (rCEvt.GetCommand() == COMMAND_STARTAUTOSCROLL) || 82 (rCEvt.GetCommand() == COMMAND_AUTOSCROLL) ) 83 { 84 ScrollBar* pHScrBar; 85 ScrollBar* pVScrBar; 86 if ( aHScroll.IsVisible() ) 87 pHScrBar = &aHScroll; 88 else 89 pHScrBar = NULL; 90 if ( aVScroll.IsVisible() ) 91 pVScrBar = &aVScroll; 92 else 93 pVScrBar = NULL; 94 if ( HandleScrollCommand( rCEvt, pHScrBar, pVScrBar ) ) 95 return; 96 } 97 98 Window::Command( rCEvt ); 99 } 100 101 //------------------------------------------------------------------- 102 103 void ScrollableWindow::DataChanged( const DataChangedEvent& rDCEvt ) 104 { 105 if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && 106 (rDCEvt.GetFlags() & SETTINGS_STYLE) ) 107 { 108 Resize(); 109 Invalidate(); 110 } 111 112 Window::DataChanged( rDCEvt ); 113 } 114 115 //------------------------------------------------------------------- 116 117 Size __EXPORT ScrollableWindow::GetOutputSizePixel() const 118 { 119 Size aSz( Window::GetOutputSizePixel() ); 120 121 long nTmp = GetSettings().GetStyleSettings().GetScrollBarSize(); 122 if ( aHScroll.IsVisible() ) 123 aSz.Height() -= nTmp; 124 if ( aVScroll.IsVisible() ) 125 aSz.Width() -= nTmp; 126 return aSz; 127 } 128 129 //------------------------------------------------------------------- 130 131 Size ScrollableWindow::GetOutputSize() const 132 { 133 return PixelToLogic( GetOutputSizePixel() ); 134 } 135 136 //------------------------------------------------------------------- 137 138 IMPL_LINK( ScrollableWindow, EndScrollHdl, ScrollBar *, pScroll ) 139 { 140 // notify the start of scrolling, if not already scrolling 141 if ( !bScrolling ) 142 StartScroll(), bScrolling = sal_True; 143 144 // get the delta in logic coordinates 145 Size aDelta( PixelToLogic( Size( aHScroll.GetDelta(), aVScroll.GetDelta() ) ) ); 146 147 // scroll the window, if this is not already done 148 if ( !bHandleDragging ) 149 { 150 if ( pScroll == &aHScroll ) 151 Scroll( aDelta.Width(), 0 ); 152 else 153 Scroll( 0, aDelta.Height() ); 154 } 155 156 // notify the end of scrolling 157 bScrolling = sal_False; 158 EndScroll( aDelta.Width(), aDelta.Height() ); 159 return 0; 160 } 161 162 //------------------------------------------------------------------- 163 164 IMPL_LINK( ScrollableWindow, ScrollHdl, ScrollBar *, pScroll ) 165 { 166 // notify the start of scrolling, if not already scrolling 167 if ( !bScrolling ) 168 StartScroll(), bScrolling = sal_True; 169 170 if ( bHandleDragging ) 171 { 172 // get the delta in logic coordinates 173 Size aDelta( PixelToLogic( 174 Size( aHScroll.GetDelta(), aVScroll.GetDelta() ) ) ); 175 if ( pScroll == &aHScroll ) 176 Scroll( aDelta.Width(), 0 ); 177 else 178 Scroll( 0, aDelta.Height() ); 179 } 180 return 0; 181 } 182 183 //------------------------------------------------------------------- 184 185 void __EXPORT ScrollableWindow::Resize() 186 { 187 // get the new output-size in pixel 188 Size aOutPixSz = Window::GetOutputSizePixel(); 189 190 // determine the size of the output-area and if we need scrollbars 191 const long nScrSize = GetSettings().GetStyleSettings().GetScrollBarSize(); 192 sal_Bool bVVisible = sal_False; // by default no vertical-ScrollBar 193 sal_Bool bHVisible = sal_False; // by default no horizontal-ScrollBar 194 sal_Bool bChanged; // determines if a visiblility was changed 195 do 196 { 197 bChanged = sal_False; 198 199 // does we need a vertical ScrollBar 200 if ( aOutPixSz.Width() < aTotPixSz.Width() && !bHVisible ) 201 { bHVisible = sal_True; 202 aOutPixSz.Height() -= nScrSize; 203 bChanged = sal_True; 204 } 205 206 // does we need a horizontal ScrollBar 207 if ( aOutPixSz.Height() < aTotPixSz.Height() && !bVVisible ) 208 { bVVisible = sal_True; 209 aOutPixSz.Width() -= nScrSize; 210 bChanged = sal_True; 211 } 212 213 } 214 while ( bChanged ); // until no visibility has changed 215 216 // store the old offset and map-mode 217 MapMode aMap( GetMapMode() ); 218 Point aOldPixOffset( aPixOffset ); 219 220 // justify (right/bottom borders should never exceed the virtual window) 221 Size aPixDelta; 222 if ( aPixOffset.X() < 0 && 223 aPixOffset.X() + aTotPixSz.Width() < aOutPixSz.Width() ) 224 aPixDelta.Width() = 225 aOutPixSz.Width() - ( aPixOffset.X() + aTotPixSz.Width() ); 226 if ( aPixOffset.Y() < 0 && 227 aPixOffset.Y() + aTotPixSz.Height() < aOutPixSz.Height() ) 228 aPixDelta.Height() = 229 aOutPixSz.Height() - ( aPixOffset.Y() + aTotPixSz.Height() ); 230 if ( aPixDelta.Width() || aPixDelta.Height() ) 231 { 232 aPixOffset.X() += aPixDelta.Width(); 233 aPixOffset.Y() += aPixDelta.Height(); 234 } 235 236 // for axis without scrollbar restore the origin 237 if ( !bVVisible || !bHVisible ) 238 { 239 aPixOffset = Point( 240 bHVisible 241 ? aPixOffset.X() 242 : ( bHCenter 243 ? (aOutPixSz.Width()-aTotPixSz.Width()) / 2 244 : 0 ), 245 bVVisible 246 ? aPixOffset.Y() 247 : ( bVCenter 248 ? (aOutPixSz.Height()-aTotPixSz.Height()) / 2 249 : 0 ) ); 250 } 251 if ( bHVisible && !aHScroll.IsVisible() ) 252 aPixOffset.X() = 0; 253 if ( bVVisible && !aVScroll.IsVisible() ) 254 aPixOffset.Y() = 0; 255 256 // select the shifted map-mode 257 if ( aPixOffset != aOldPixOffset ) 258 { 259 Window::SetMapMode( MapMode( MAP_PIXEL ) ); 260 Window::Scroll( 261 aPixOffset.X() - aOldPixOffset.X(), 262 aPixOffset.Y() - aOldPixOffset.Y() ); 263 SetMapMode( aMap ); 264 } 265 266 // show or hide scrollbars 267 aVScroll.Show( bVVisible ); 268 aHScroll.Show( bHVisible ); 269 270 // disable painting in the corner between the scrollbars 271 if ( bVVisible && bHVisible ) 272 { 273 aCornerWin.SetPosSizePixel(Point(aOutPixSz.Width(), aOutPixSz.Height()), 274 Size(nScrSize, nScrSize) ); 275 aCornerWin.Show(); 276 } 277 else 278 aCornerWin.Hide(); 279 280 // resize scrollbars and set their ranges 281 if ( bHVisible ) 282 { 283 aHScroll.SetPosSizePixel( 284 Point( 0, aOutPixSz.Height() ), 285 Size( aOutPixSz.Width(), nScrSize ) ); 286 aHScroll.SetRange( Range( 0, aTotPixSz.Width() ) ); 287 aHScroll.SetPageSize( aOutPixSz.Width() ); 288 aHScroll.SetVisibleSize( aOutPixSz.Width() ); 289 aHScroll.SetLineSize( nColumnPixW ); 290 aHScroll.SetThumbPos( -aPixOffset.X() ); 291 } 292 if ( bVVisible ) 293 { 294 aVScroll.SetPosSizePixel( 295 Point( aOutPixSz.Width(), 0 ), 296 Size( nScrSize,aOutPixSz.Height() ) ); 297 aVScroll.SetRange( Range( 0, aTotPixSz.Height() ) ); 298 aVScroll.SetPageSize( aOutPixSz.Height() ); 299 aVScroll.SetVisibleSize( aOutPixSz.Height() ); 300 aVScroll.SetLineSize( nLinePixH ); 301 aVScroll.SetThumbPos( -aPixOffset.Y() ); 302 } 303 } 304 305 //------------------------------------------------------------------- 306 307 void __EXPORT ScrollableWindow::StartScroll() 308 { 309 } 310 311 //------------------------------------------------------------------- 312 313 void __EXPORT ScrollableWindow::EndScroll( long, long ) 314 { 315 } 316 317 //------------------------------------------------------------------- 318 319 void ScrollableWindow::SetMapMode( const MapMode& rNewMapMode ) 320 { 321 MapMode aMap( rNewMapMode ); 322 aMap.SetOrigin( aMap.GetOrigin() + PixelToLogic( aPixOffset, aMap ) ); 323 Window::SetMapMode( aMap ); 324 } 325 326 //------------------------------------------------------------------- 327 328 MapMode ScrollableWindow::GetMapMode() const 329 { 330 MapMode aMap( Window::GetMapMode() ); 331 aMap.SetOrigin( aMap.GetOrigin() - PixelToLogic( aPixOffset ) ); 332 return aMap; 333 } 334 335 //------------------------------------------------------------------- 336 337 void ScrollableWindow::SetTotalSize( const Size& rNewSize ) 338 { 339 aTotPixSz = LogicToPixel( rNewSize ); 340 ScrollableWindow::Resize(); 341 } 342 343 //------------------------------------------------------------------- 344 345 void ScrollableWindow::SetVisibleSize( const Size& rNewSize ) 346 { 347 // get the rectangle, we wish to view 348 Rectangle aWish( Point(0, 0), LogicToPixel(rNewSize) ); 349 350 // get maximum rectangle for us from our parent-window (subst our border!) 351 Rectangle aMax( Point(0, 0), GetParent()->GetOutputSizePixel() ); 352 aMax.Left() -= ( Window::GetSizePixel().Width() - 353 Window::GetOutputSizePixel().Width() ); 354 aMax.Bottom() -= (Window::GetSizePixel().Height() - 355 Window::GetOutputSizePixel().Height()); 356 357 Size aWill( aWish.GetIntersection(aMax).GetSize() ); 358 sal_Bool bHScroll = sal_False; 359 const long nScrSize = GetSettings().GetStyleSettings().GetScrollBarSize(); 360 if ( aWill.Width() < aWish.GetSize().Width() ) 361 { bHScroll = sal_True; 362 aWill.Height() = 363 Min( aWill.Height()+nScrSize, aMax.GetSize().Height() ); 364 } 365 if ( aWill.Height() < aWish.GetSize().Height() ) 366 aWill.Width() = 367 Min( aWill.Width()+nScrSize, aMax.GetSize().Width() ); 368 if ( !bHScroll && (aWill.Width() < aWish.GetSize().Width()) ) 369 aWill.Height() = 370 Min( aWill.Height()+nScrSize, aMax.GetSize().Height() ); 371 Window::SetOutputSizePixel( aWill ); 372 } 373 374 //------------------------------------------------------------------- 375 376 sal_Bool ScrollableWindow::MakeVisible( const Rectangle& rTarget, sal_Bool bSloppy ) 377 { 378 Rectangle aTarget; 379 Rectangle aTotRect( Point(0, 0), PixelToLogic( aTotPixSz ) ); 380 381 if ( bSloppy ) 382 { 383 aTarget = rTarget; 384 385 // at maximum to right border 386 if ( aTarget.Right() > aTotRect.Right() ) 387 { 388 long nDelta = aTarget.Right() - aTotRect.Right(); 389 aTarget.Left() -= nDelta; 390 aTarget.Right() -= nDelta; 391 392 // too wide? 393 if ( aTarget.Left() < aTotRect.Left() ) 394 aTarget.Left() = aTotRect.Left(); 395 } 396 397 // at maximum to bottom border 398 if ( aTarget.Bottom() > aTotRect.Bottom() ) 399 { 400 long nDelta = aTarget.Bottom() - aTotRect.Bottom(); 401 aTarget.Top() -= nDelta; 402 aTarget.Bottom() -= nDelta; 403 404 // too high? 405 if ( aTarget.Top() < aTotRect.Top() ) 406 aTarget.Top() = aTotRect.Top(); 407 } 408 409 // at maximum to left border 410 if ( aTarget.Left() < aTotRect.Left() ) 411 { 412 long nDelta = aTarget.Left() - aTotRect.Left(); 413 aTarget.Right() -= nDelta; 414 aTarget.Left() -= nDelta; 415 416 // too wide? 417 if ( aTarget.Right() > aTotRect.Right() ) 418 aTarget.Right() = aTotRect.Right(); 419 } 420 421 // at maximum to top border 422 if ( aTarget.Top() < aTotRect.Top() ) 423 { 424 long nDelta = aTarget.Top() - aTotRect.Top(); 425 aTarget.Bottom() -= nDelta; 426 aTarget.Top() -= nDelta; 427 428 // too high? 429 if ( aTarget.Bottom() > aTotRect.Bottom() ) 430 aTarget.Bottom() = aTotRect.Bottom(); 431 } 432 } 433 else 434 aTarget = rTarget.GetIntersection( aTotRect ); 435 436 // is the area already visible? 437 Rectangle aVisArea( GetVisibleArea() ); 438 if ( aVisArea.IsInside(rTarget) ) 439 return sal_True; 440 441 // is there somewhat to scroll? 442 if ( aVisArea.TopLeft() != aTarget.TopLeft() ) 443 { 444 Rectangle aBox( aTarget.GetUnion(aVisArea) ); 445 long nDeltaX = ( aBox.Right() - aVisArea.Right() ) + 446 ( aBox.Left() - aVisArea.Left() ); 447 long nDeltaY = ( aBox.Top() - aVisArea.Top() ) + 448 ( aBox.Bottom() - aVisArea.Bottom() ); 449 Scroll( nDeltaX, nDeltaY ); 450 } 451 452 // determine if the target is completely visible 453 return aVisArea.GetWidth() >= aTarget.GetWidth() && 454 aVisArea.GetHeight() >= aTarget.GetHeight(); 455 } 456 457 //------------------------------------------------------------------- 458 459 Rectangle ScrollableWindow::GetVisibleArea() const 460 { 461 Point aTopLeft( PixelToLogic( Point() ) ); 462 Size aSz( GetOutputSize() ); 463 return Rectangle( aTopLeft, aSz ); 464 } 465 466 //------------------------------------------------------------------- 467 468 void ScrollableWindow::SetLineSize( sal_uLong nHorz, sal_uLong nVert ) 469 { 470 Size aPixSz( LogicToPixel( Size(nHorz, nVert) ) ); 471 nColumnPixW = aPixSz.Width(); 472 nLinePixH = aPixSz.Height(); 473 aVScroll.SetLineSize( nLinePixH ); 474 aHScroll.SetLineSize( nColumnPixW ); 475 } 476 477 //------------------------------------------------------------------- 478 479 void ScrollableWindow::Scroll( long nDeltaX, long nDeltaY, sal_uInt16 ) 480 { 481 if ( !bScrolling ) 482 StartScroll(); 483 484 // get the delta in pixel 485 Size aDeltaPix( LogicToPixel( Size(nDeltaX, nDeltaY) ) ); 486 Size aOutPixSz( GetOutputSizePixel() ); 487 MapMode aMap( GetMapMode() ); 488 Point aNewPixOffset( aPixOffset ); 489 490 // scrolling horizontally? 491 if ( nDeltaX != 0 ) 492 { 493 aNewPixOffset.X() -= aDeltaPix.Width(); 494 if ( ( aOutPixSz.Width() - aNewPixOffset.X() ) > aTotPixSz.Width() ) 495 aNewPixOffset.X() = - ( aTotPixSz.Width() - aOutPixSz.Width() ); 496 else if ( aNewPixOffset.X() > 0 ) 497 aNewPixOffset.X() = 0; 498 } 499 500 // scrolling vertically? 501 if ( nDeltaY != 0 ) 502 { 503 aNewPixOffset.Y() -= aDeltaPix.Height(); 504 if ( ( aOutPixSz.Height() - aNewPixOffset.Y() ) > aTotPixSz.Height() ) 505 aNewPixOffset.Y() = - ( aTotPixSz.Height() - aOutPixSz.Height() ); 506 else if ( aNewPixOffset.Y() > 0 ) 507 aNewPixOffset.Y() = 0; 508 } 509 510 // recompute the logical scroll units 511 aDeltaPix.Width() = aPixOffset.X() - aNewPixOffset.X(); 512 aDeltaPix.Height() = aPixOffset.Y() - aNewPixOffset.Y(); 513 Size aDelta( PixelToLogic(aDeltaPix) ); 514 nDeltaX = aDelta.Width(); 515 nDeltaY = aDelta.Height(); 516 aPixOffset = aNewPixOffset; 517 518 // scrolling? 519 if ( nDeltaX != 0 || nDeltaY != 0 ) 520 { 521 Update(); 522 523 // does the new area overlap the old one? 524 if ( Abs( (int)aDeltaPix.Height() ) < aOutPixSz.Height() || 525 Abs( (int)aDeltaPix.Width() ) < aOutPixSz.Width() ) 526 { 527 // scroll the overlapping area 528 SetMapMode( aMap ); 529 530 // never scroll the scrollbars itself! 531 Window::Scroll(-nDeltaX, -nDeltaY, 532 PixelToLogic( Rectangle( Point(0, 0), aOutPixSz ) ) ); 533 } 534 else 535 { 536 // repaint all 537 SetMapMode( aMap ); 538 Invalidate(); 539 } 540 541 Update(); 542 } 543 544 if ( !bScrolling ) 545 { 546 EndScroll( nDeltaX, nDeltaY ); 547 if ( nDeltaX ) 548 aHScroll.SetThumbPos( -aPixOffset.X() ); 549 if ( nDeltaY ) 550 aVScroll.SetThumbPos( -aPixOffset.Y() ); 551 } 552 } 553 554 //------------------------------------------------------------------- 555 556 void ScrollableWindow::ScrollLines( long nLinesX, long nLinesY ) 557 { 558 Size aDelta( PixelToLogic( Size( nColumnPixW, nLinePixH ) ) ); 559 Scroll( aDelta.Width()*nLinesX, aDelta.Height()*nLinesY ); 560 } 561 562 //------------------------------------------------------------------- 563 564 void ScrollableWindow::ScrollPages( long nPagesX, sal_uLong nOverlapX, 565 long nPagesY, sal_uLong nOverlapY ) 566 { 567 Size aOutSz( GetVisibleArea().GetSize() ); 568 Scroll( nPagesX * aOutSz.Width() + (nPagesX>0 ? 1 : -1) * nOverlapX, 569 nPagesY * aOutSz.Height() + (nPagesY>0 ? 1 : -1) * nOverlapY ); 570 } 571 572 573