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