/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_svtools.hxx" #define _SVT_SCRWIN_CXX #include //=================================================================== void ScrollableWindow::ImpInitialize( ScrollableWindowFlags nFlags ) { bHandleDragging = (sal_Bool) ( nFlags & SCRWIN_THUMBDRAGGING ); bVCenter = (nFlags & SCRWIN_VCENTER) == SCRWIN_VCENTER; bHCenter = (nFlags & SCRWIN_HCENTER) == SCRWIN_HCENTER; bScrolling = sal_False; // set the handlers for the scrollbars aVScroll.SetScrollHdl( LINK(this, ScrollableWindow, ScrollHdl) ); aHScroll.SetScrollHdl( LINK(this, ScrollableWindow, ScrollHdl) ); aVScroll.SetEndScrollHdl( LINK(this, ScrollableWindow, EndScrollHdl) ); aHScroll.SetEndScrollHdl( LINK(this, ScrollableWindow, EndScrollHdl) ); nColumnPixW = nLinePixH = GetSettings().GetStyleSettings().GetScrollBarSize(); } //------------------------------------------------------------------- ScrollableWindow::ScrollableWindow( Window* pParent, WinBits nBits, ScrollableWindowFlags nFlags ) : Window( pParent, WinBits(nBits|WB_CLIPCHILDREN) ), aVScroll( this, WinBits(WB_VSCROLL | WB_DRAG) ), aHScroll( this, WinBits(WB_HSCROLL | WB_DRAG) ), aCornerWin( this ) { ImpInitialize( nFlags ); } //------------------------------------------------------------------- ScrollableWindow::ScrollableWindow( Window* pParent, const ResId& rId, ScrollableWindowFlags nFlags ) : Window( pParent, rId ), aVScroll( this, WinBits(WB_VSCROLL | WB_DRAG) ), aHScroll( this, WinBits(WB_HSCROLL | WB_DRAG) ), aCornerWin( this ) { ImpInitialize( nFlags ); } // ----------------------------------------------------------------------- void ScrollableWindow::Command( const CommandEvent& rCEvt ) { if ( (rCEvt.GetCommand() == COMMAND_WHEEL) || (rCEvt.GetCommand() == COMMAND_STARTAUTOSCROLL) || (rCEvt.GetCommand() == COMMAND_AUTOSCROLL) ) { ScrollBar* pHScrBar; ScrollBar* pVScrBar; if ( aHScroll.IsVisible() ) pHScrBar = &aHScroll; else pHScrBar = NULL; if ( aVScroll.IsVisible() ) pVScrBar = &aVScroll; else pVScrBar = NULL; if ( HandleScrollCommand( rCEvt, pHScrBar, pVScrBar ) ) return; } Window::Command( rCEvt ); } //------------------------------------------------------------------- void ScrollableWindow::DataChanged( const DataChangedEvent& rDCEvt ) { if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_STYLE) ) { Resize(); Invalidate(); } Window::DataChanged( rDCEvt ); } //------------------------------------------------------------------- Size __EXPORT ScrollableWindow::GetOutputSizePixel() const { Size aSz( Window::GetOutputSizePixel() ); long nTmp = GetSettings().GetStyleSettings().GetScrollBarSize(); if ( aHScroll.IsVisible() ) aSz.Height() -= nTmp; if ( aVScroll.IsVisible() ) aSz.Width() -= nTmp; return aSz; } //------------------------------------------------------------------- Size ScrollableWindow::GetOutputSize() const { return PixelToLogic( GetOutputSizePixel() ); } //------------------------------------------------------------------- IMPL_LINK( ScrollableWindow, EndScrollHdl, ScrollBar *, pScroll ) { // notify the start of scrolling, if not already scrolling if ( !bScrolling ) StartScroll(), bScrolling = sal_True; // get the delta in logic coordinates Size aDelta( PixelToLogic( Size( aHScroll.GetDelta(), aVScroll.GetDelta() ) ) ); // scroll the window, if this is not already done if ( !bHandleDragging ) { if ( pScroll == &aHScroll ) Scroll( aDelta.Width(), 0 ); else Scroll( 0, aDelta.Height() ); } // notify the end of scrolling bScrolling = sal_False; EndScroll( aDelta.Width(), aDelta.Height() ); return 0; } //------------------------------------------------------------------- IMPL_LINK( ScrollableWindow, ScrollHdl, ScrollBar *, pScroll ) { // notify the start of scrolling, if not already scrolling if ( !bScrolling ) StartScroll(), bScrolling = sal_True; if ( bHandleDragging ) { // get the delta in logic coordinates Size aDelta( PixelToLogic( Size( aHScroll.GetDelta(), aVScroll.GetDelta() ) ) ); if ( pScroll == &aHScroll ) Scroll( aDelta.Width(), 0 ); else Scroll( 0, aDelta.Height() ); } return 0; } //------------------------------------------------------------------- void __EXPORT ScrollableWindow::Resize() { // get the new output-size in pixel Size aOutPixSz = Window::GetOutputSizePixel(); // determine the size of the output-area and if we need scrollbars const long nScrSize = GetSettings().GetStyleSettings().GetScrollBarSize(); sal_Bool bVVisible = sal_False; // by default no vertical-ScrollBar sal_Bool bHVisible = sal_False; // by default no horizontal-ScrollBar sal_Bool bChanged; // determines if a visiblility was changed do { bChanged = sal_False; // does we need a vertical ScrollBar if ( aOutPixSz.Width() < aTotPixSz.Width() && !bHVisible ) { bHVisible = sal_True; aOutPixSz.Height() -= nScrSize; bChanged = sal_True; } // does we need a horizontal ScrollBar if ( aOutPixSz.Height() < aTotPixSz.Height() && !bVVisible ) { bVVisible = sal_True; aOutPixSz.Width() -= nScrSize; bChanged = sal_True; } } while ( bChanged ); // until no visibility has changed // store the old offset and map-mode MapMode aMap( GetMapMode() ); Point aOldPixOffset( aPixOffset ); // justify (right/bottom borders should never exceed the virtual window) Size aPixDelta; if ( aPixOffset.X() < 0 && aPixOffset.X() + aTotPixSz.Width() < aOutPixSz.Width() ) aPixDelta.Width() = aOutPixSz.Width() - ( aPixOffset.X() + aTotPixSz.Width() ); if ( aPixOffset.Y() < 0 && aPixOffset.Y() + aTotPixSz.Height() < aOutPixSz.Height() ) aPixDelta.Height() = aOutPixSz.Height() - ( aPixOffset.Y() + aTotPixSz.Height() ); if ( aPixDelta.Width() || aPixDelta.Height() ) { aPixOffset.X() += aPixDelta.Width(); aPixOffset.Y() += aPixDelta.Height(); } // for axis without scrollbar restore the origin if ( !bVVisible || !bHVisible ) { aPixOffset = Point( bHVisible ? aPixOffset.X() : ( bHCenter ? (aOutPixSz.Width()-aTotPixSz.Width()) / 2 : 0 ), bVVisible ? aPixOffset.Y() : ( bVCenter ? (aOutPixSz.Height()-aTotPixSz.Height()) / 2 : 0 ) ); } if ( bHVisible && !aHScroll.IsVisible() ) aPixOffset.X() = 0; if ( bVVisible && !aVScroll.IsVisible() ) aPixOffset.Y() = 0; // select the shifted map-mode if ( aPixOffset != aOldPixOffset ) { Window::SetMapMode( MapMode( MAP_PIXEL ) ); Window::Scroll( aPixOffset.X() - aOldPixOffset.X(), aPixOffset.Y() - aOldPixOffset.Y() ); SetMapMode( aMap ); } // show or hide scrollbars aVScroll.Show( bVVisible ); aHScroll.Show( bHVisible ); // disable painting in the corner between the scrollbars if ( bVVisible && bHVisible ) { aCornerWin.SetPosSizePixel(Point(aOutPixSz.Width(), aOutPixSz.Height()), Size(nScrSize, nScrSize) ); aCornerWin.Show(); } else aCornerWin.Hide(); // resize scrollbars and set their ranges if ( bHVisible ) { aHScroll.SetPosSizePixel( Point( 0, aOutPixSz.Height() ), Size( aOutPixSz.Width(), nScrSize ) ); aHScroll.SetRange( Range( 0, aTotPixSz.Width() ) ); aHScroll.SetPageSize( aOutPixSz.Width() ); aHScroll.SetVisibleSize( aOutPixSz.Width() ); aHScroll.SetLineSize( nColumnPixW ); aHScroll.SetThumbPos( -aPixOffset.X() ); } if ( bVVisible ) { aVScroll.SetPosSizePixel( Point( aOutPixSz.Width(), 0 ), Size( nScrSize,aOutPixSz.Height() ) ); aVScroll.SetRange( Range( 0, aTotPixSz.Height() ) ); aVScroll.SetPageSize( aOutPixSz.Height() ); aVScroll.SetVisibleSize( aOutPixSz.Height() ); aVScroll.SetLineSize( nLinePixH ); aVScroll.SetThumbPos( -aPixOffset.Y() ); } } //------------------------------------------------------------------- void __EXPORT ScrollableWindow::StartScroll() { } //------------------------------------------------------------------- void __EXPORT ScrollableWindow::EndScroll( long, long ) { } //------------------------------------------------------------------- void ScrollableWindow::SetMapMode( const MapMode& rNewMapMode ) { MapMode aMap( rNewMapMode ); aMap.SetOrigin( aMap.GetOrigin() + PixelToLogic( aPixOffset, aMap ) ); Window::SetMapMode( aMap ); } //------------------------------------------------------------------- MapMode ScrollableWindow::GetMapMode() const { MapMode aMap( Window::GetMapMode() ); aMap.SetOrigin( aMap.GetOrigin() - PixelToLogic( aPixOffset ) ); return aMap; } //------------------------------------------------------------------- void ScrollableWindow::SetTotalSize( const Size& rNewSize ) { aTotPixSz = LogicToPixel( rNewSize ); ScrollableWindow::Resize(); } //------------------------------------------------------------------- void ScrollableWindow::SetVisibleSize( const Size& rNewSize ) { // get the rectangle, we wish to view Rectangle aWish( Point(0, 0), LogicToPixel(rNewSize) ); // get maximum rectangle for us from our parent-window (subst our border!) Rectangle aMax( Point(0, 0), GetParent()->GetOutputSizePixel() ); aMax.Left() -= ( Window::GetSizePixel().Width() - Window::GetOutputSizePixel().Width() ); aMax.Bottom() -= (Window::GetSizePixel().Height() - Window::GetOutputSizePixel().Height()); Size aWill( aWish.GetIntersection(aMax).GetSize() ); sal_Bool bHScroll = sal_False; const long nScrSize = GetSettings().GetStyleSettings().GetScrollBarSize(); if ( aWill.Width() < aWish.GetSize().Width() ) { bHScroll = sal_True; aWill.Height() = Min( aWill.Height()+nScrSize, aMax.GetSize().Height() ); } if ( aWill.Height() < aWish.GetSize().Height() ) aWill.Width() = Min( aWill.Width()+nScrSize, aMax.GetSize().Width() ); if ( !bHScroll && (aWill.Width() < aWish.GetSize().Width()) ) aWill.Height() = Min( aWill.Height()+nScrSize, aMax.GetSize().Height() ); Window::SetOutputSizePixel( aWill ); } //------------------------------------------------------------------- sal_Bool ScrollableWindow::MakeVisible( const Rectangle& rTarget, sal_Bool bSloppy ) { Rectangle aTarget; Rectangle aTotRect( Point(0, 0), PixelToLogic( aTotPixSz ) ); if ( bSloppy ) { aTarget = rTarget; // at maximum to right border if ( aTarget.Right() > aTotRect.Right() ) { long nDelta = aTarget.Right() - aTotRect.Right(); aTarget.Left() -= nDelta; aTarget.Right() -= nDelta; // too wide? if ( aTarget.Left() < aTotRect.Left() ) aTarget.Left() = aTotRect.Left(); } // at maximum to bottom border if ( aTarget.Bottom() > aTotRect.Bottom() ) { long nDelta = aTarget.Bottom() - aTotRect.Bottom(); aTarget.Top() -= nDelta; aTarget.Bottom() -= nDelta; // too high? if ( aTarget.Top() < aTotRect.Top() ) aTarget.Top() = aTotRect.Top(); } // at maximum to left border if ( aTarget.Left() < aTotRect.Left() ) { long nDelta = aTarget.Left() - aTotRect.Left(); aTarget.Right() -= nDelta; aTarget.Left() -= nDelta; // too wide? if ( aTarget.Right() > aTotRect.Right() ) aTarget.Right() = aTotRect.Right(); } // at maximum to top border if ( aTarget.Top() < aTotRect.Top() ) { long nDelta = aTarget.Top() - aTotRect.Top(); aTarget.Bottom() -= nDelta; aTarget.Top() -= nDelta; // too high? if ( aTarget.Bottom() > aTotRect.Bottom() ) aTarget.Bottom() = aTotRect.Bottom(); } } else aTarget = rTarget.GetIntersection( aTotRect ); // is the area already visible? Rectangle aVisArea( GetVisibleArea() ); if ( aVisArea.IsInside(rTarget) ) return sal_True; // is there somewhat to scroll? if ( aVisArea.TopLeft() != aTarget.TopLeft() ) { Rectangle aBox( aTarget.GetUnion(aVisArea) ); long nDeltaX = ( aBox.Right() - aVisArea.Right() ) + ( aBox.Left() - aVisArea.Left() ); long nDeltaY = ( aBox.Top() - aVisArea.Top() ) + ( aBox.Bottom() - aVisArea.Bottom() ); Scroll( nDeltaX, nDeltaY ); } // determine if the target is completely visible return aVisArea.GetWidth() >= aTarget.GetWidth() && aVisArea.GetHeight() >= aTarget.GetHeight(); } //------------------------------------------------------------------- Rectangle ScrollableWindow::GetVisibleArea() const { Point aTopLeft( PixelToLogic( Point() ) ); Size aSz( GetOutputSize() ); return Rectangle( aTopLeft, aSz ); } //------------------------------------------------------------------- void ScrollableWindow::SetLineSize( sal_uLong nHorz, sal_uLong nVert ) { Size aPixSz( LogicToPixel( Size(nHorz, nVert) ) ); nColumnPixW = aPixSz.Width(); nLinePixH = aPixSz.Height(); aVScroll.SetLineSize( nLinePixH ); aHScroll.SetLineSize( nColumnPixW ); } //------------------------------------------------------------------- void ScrollableWindow::Scroll( long nDeltaX, long nDeltaY, sal_uInt16 ) { if ( !bScrolling ) StartScroll(); // get the delta in pixel Size aDeltaPix( LogicToPixel( Size(nDeltaX, nDeltaY) ) ); Size aOutPixSz( GetOutputSizePixel() ); MapMode aMap( GetMapMode() ); Point aNewPixOffset( aPixOffset ); // scrolling horizontally? if ( nDeltaX != 0 ) { aNewPixOffset.X() -= aDeltaPix.Width(); if ( ( aOutPixSz.Width() - aNewPixOffset.X() ) > aTotPixSz.Width() ) aNewPixOffset.X() = - ( aTotPixSz.Width() - aOutPixSz.Width() ); else if ( aNewPixOffset.X() > 0 ) aNewPixOffset.X() = 0; } // scrolling vertically? if ( nDeltaY != 0 ) { aNewPixOffset.Y() -= aDeltaPix.Height(); if ( ( aOutPixSz.Height() - aNewPixOffset.Y() ) > aTotPixSz.Height() ) aNewPixOffset.Y() = - ( aTotPixSz.Height() - aOutPixSz.Height() ); else if ( aNewPixOffset.Y() > 0 ) aNewPixOffset.Y() = 0; } // recompute the logical scroll units aDeltaPix.Width() = aPixOffset.X() - aNewPixOffset.X(); aDeltaPix.Height() = aPixOffset.Y() - aNewPixOffset.Y(); Size aDelta( PixelToLogic(aDeltaPix) ); nDeltaX = aDelta.Width(); nDeltaY = aDelta.Height(); aPixOffset = aNewPixOffset; // scrolling? if ( nDeltaX != 0 || nDeltaY != 0 ) { Update(); // does the new area overlap the old one? if ( Abs( (int)aDeltaPix.Height() ) < aOutPixSz.Height() || Abs( (int)aDeltaPix.Width() ) < aOutPixSz.Width() ) { // scroll the overlapping area SetMapMode( aMap ); // never scroll the scrollbars itself! Window::Scroll(-nDeltaX, -nDeltaY, PixelToLogic( Rectangle( Point(0, 0), aOutPixSz ) ) ); } else { // repaint all SetMapMode( aMap ); Invalidate(); } Update(); } if ( !bScrolling ) { EndScroll( nDeltaX, nDeltaY ); if ( nDeltaX ) aHScroll.SetThumbPos( -aPixOffset.X() ); if ( nDeltaY ) aVScroll.SetThumbPos( -aPixOffset.Y() ); } } //------------------------------------------------------------------- void ScrollableWindow::ScrollLines( long nLinesX, long nLinesY ) { Size aDelta( PixelToLogic( Size( nColumnPixW, nLinePixH ) ) ); Scroll( aDelta.Width()*nLinesX, aDelta.Height()*nLinesY ); } //------------------------------------------------------------------- void ScrollableWindow::ScrollPages( long nPagesX, sal_uLong nOverlapX, long nPagesY, sal_uLong nOverlapY ) { Size aOutSz( GetVisibleArea().GetSize() ); Scroll( nPagesX * aOutSz.Width() + (nPagesX>0 ? 1 : -1) * nOverlapX, nPagesY * aOutSz.Height() + (nPagesY>0 ? 1 : -1) * nOverlapY ); }