/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include "PresenterScrollBar.hxx" #include "PresenterBitmapContainer.hxx" #include "PresenterCanvasHelper.hxx" #include "PresenterGeometryHelper.hxx" #include "PresenterPaintManager.hxx" #include "PresenterTimer.hxx" #include "PresenterUIPainter.hxx" #include #include #include #include #include #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::uno; const double gnScrollBarGap (10); namespace sdext::presenter { //===== PresenterScrollBar::MousePressRepeater ================================ class PresenterScrollBar::MousePressRepeater : public std::enable_shared_from_this { public: explicit MousePressRepeater (const ::rtl::Reference& rpScrollBar); void Dispose(); void Start (const PresenterScrollBar::Area& reArea); void Stop(); void SetMouseArea (const PresenterScrollBar::Area& reArea); private: void Callback (); void Execute(); sal_Int32 mnMousePressRepeaterTaskId; ::rtl::Reference mpScrollBar; PresenterScrollBar::Area meMouseArea; }; //===== PresenterScrollBar ==================================================== std::weak_ptr PresenterScrollBar::mpSharedBitmaps; PresenterScrollBar::PresenterScrollBar ( const Reference& rxComponentContext, const Reference& rxParentWindow, const std::shared_ptr& rpPaintManager, const ::std::function& rThumbMotionListener) : PresenterScrollBarInterfaceBase(m_aMutex), mxComponentContext(rxComponentContext), mpPaintManager(rpPaintManager), mnThumbPosition(0), mnTotalSize(0), mnThumbSize(0), mnLineHeight(10), maDragAnchor(-1,-1), maThumbMotionListener(rThumbMotionListener), meButtonDownArea(None), meMouseMoveArea(None), mbIsNotificationActive(false), mpMousePressRepeater(std::make_shared(this)), mpCanvasHelper(new PresenterCanvasHelper()) { try { Reference xFactory (rxComponentContext->getServiceManager()); if ( ! xFactory.is()) throw RuntimeException(); mxPresenterHelper.set( xFactory->createInstanceWithContext( "com.sun.star.comp.Draw.PresenterHelper", rxComponentContext), UNO_QUERY_THROW); if (mxPresenterHelper.is()) mxWindow = mxPresenterHelper->createWindow(rxParentWindow, false, false, false, false); // Make the background transparent. The slide show paints its own background. Reference xPeer (mxWindow, UNO_QUERY_THROW); xPeer->setBackground(0xff000000); mxWindow->setVisible(true); mxWindow->addWindowListener(this); mxWindow->addPaintListener(this); mxWindow->addMouseListener(this); mxWindow->addMouseMotionListener(this); } catch (RuntimeException&) { } } PresenterScrollBar::~PresenterScrollBar() { } void SAL_CALL PresenterScrollBar::disposing() { mpMousePressRepeater->Dispose(); if (mxWindow.is()) { mxWindow->removeWindowListener(this); mxWindow->removePaintListener(this); mxWindow->removeMouseListener(this); mxWindow->removeMouseMotionListener(this); Reference xComponent = mxWindow; mxWindow = nullptr; if (xComponent.is()) xComponent->dispose(); } mpBitmaps.reset(); } void PresenterScrollBar::SetVisible (const bool bIsVisible) { if (mxWindow.is()) mxWindow->setVisible(bIsVisible); } void PresenterScrollBar::SetPosSize (const css::geometry::RealRectangle2D& rBox) { if (mxWindow.is()) { mxWindow->setPosSize( sal_Int32(floor(rBox.X1)), sal_Int32(ceil(rBox.Y1)), sal_Int32(ceil(rBox.X2-rBox.X1)), sal_Int32(floor(rBox.Y2-rBox.Y1)), awt::PosSize::POSSIZE); UpdateBorders(); } } void PresenterScrollBar::SetThumbPosition ( double nPosition, const bool bAsynchronousUpdate) { nPosition = ValidateThumbPosition(nPosition); if (nPosition == mnThumbPosition || mbIsNotificationActive) return; mnThumbPosition = nPosition; UpdateBorders(); Repaint(GetRectangle(Total), bAsynchronousUpdate); mbIsNotificationActive = true; try { maThumbMotionListener(mnThumbPosition); } catch (Exception&) { } mbIsNotificationActive = false; } void PresenterScrollBar::SetTotalSize (const double nTotalSize) { if (mnTotalSize != nTotalSize) { mnTotalSize = nTotalSize + 1; UpdateBorders(); Repaint(GetRectangle(Total), false); } } void PresenterScrollBar::SetThumbSize (const double nThumbSize) { OSL_ASSERT(nThumbSize>=0); if (mnThumbSize != nThumbSize) { mnThumbSize = nThumbSize; UpdateBorders(); Repaint(GetRectangle(Total), false); } } void PresenterScrollBar::SetLineHeight (const double nLineHeight) { mnLineHeight = nLineHeight; } void PresenterScrollBar::SetCanvas (const Reference& rxCanvas) { if (mxCanvas == rxCanvas) return; mxCanvas = rxCanvas; if (!mxCanvas.is()) return; if (mpBitmaps == nullptr) { mpBitmaps = mpSharedBitmaps.lock(); if (!mpBitmaps) { try { mpBitmaps = std::make_shared( "PresenterScreenSettings/ScrollBar/Bitmaps", std::shared_ptr(), mxComponentContext, mxCanvas); mpSharedBitmaps = mpBitmaps; } catch(Exception&) { OSL_ASSERT(false); } } UpdateBitmaps(); UpdateBorders(); } Repaint(GetRectangle(Total), false); } void PresenterScrollBar::SetBackground (const SharedBitmapDescriptor& rpBackgroundBitmap) { mpBackgroundBitmap = rpBackgroundBitmap; } void PresenterScrollBar::CheckValues() { mnThumbPosition = ValidateThumbPosition(mnThumbPosition); } double PresenterScrollBar::ValidateThumbPosition (double nPosition) { if (nPosition + mnThumbSize > mnTotalSize) nPosition = mnTotalSize - mnThumbSize; if (nPosition < 0) nPosition = 0; return nPosition; } void PresenterScrollBar::Paint ( const awt::Rectangle& rUpdateBox) { if ( ! mxCanvas.is() || ! mxWindow.is()) { OSL_ASSERT(mxCanvas.is()); OSL_ASSERT(mxWindow.is()); return; } if (PresenterGeometryHelper::AreRectanglesDisjoint (rUpdateBox, mxWindow->getPosSize())) return; PaintBackground(rUpdateBox); PaintComposite(rUpdateBox, PagerUp, mpPagerStartDescriptor, mpPagerCenterDescriptor, SharedBitmapDescriptor()); PaintComposite(rUpdateBox, PagerDown, SharedBitmapDescriptor(), mpPagerCenterDescriptor, mpPagerEndDescriptor); PaintComposite(rUpdateBox, Thumb, mpThumbStartDescriptor, mpThumbCenterDescriptor, mpThumbEndDescriptor); PaintBitmap(rUpdateBox, PrevButton, mpPrevButtonDescriptor); PaintBitmap(rUpdateBox, NextButton, mpNextButtonDescriptor); Reference xSpriteCanvas (mxCanvas, UNO_QUERY); if (xSpriteCanvas.is()) xSpriteCanvas->updateScreen(false); } //----- XWindowListener ------------------------------------------------------- void SAL_CALL PresenterScrollBar::windowResized (const css::awt::WindowEvent&) {} void SAL_CALL PresenterScrollBar::windowMoved (const css::awt::WindowEvent&) {} void SAL_CALL PresenterScrollBar::windowShown (const css::lang::EventObject&) {} void SAL_CALL PresenterScrollBar::windowHidden (const css::lang::EventObject&) {} //----- XPaintListener -------------------------------------------------------- void SAL_CALL PresenterScrollBar::windowPaint (const css::awt::PaintEvent& rEvent) { if (mxWindow.is()) { awt::Rectangle aRepaintBox (rEvent.UpdateRect); const awt::Rectangle aWindowBox (mxWindow->getPosSize()); aRepaintBox.X += aWindowBox.X; aRepaintBox.Y += aWindowBox.Y; Paint(aRepaintBox); Reference xSpriteCanvas (mxCanvas, UNO_QUERY); if (xSpriteCanvas.is()) xSpriteCanvas->updateScreen(false); } } //----- XMouseListener -------------------------------------------------------- void SAL_CALL PresenterScrollBar::mousePressed (const css::awt::MouseEvent& rEvent) { maDragAnchor.X = rEvent.X; maDragAnchor.Y = rEvent.Y; meButtonDownArea = GetArea(rEvent.X, rEvent.Y); mpMousePressRepeater->Start(meButtonDownArea); } void SAL_CALL PresenterScrollBar::mouseReleased (const css::awt::MouseEvent&) { mpMousePressRepeater->Stop(); if (mxPresenterHelper.is()) mxPresenterHelper->releaseMouse(mxWindow); } void SAL_CALL PresenterScrollBar::mouseEntered (const css::awt::MouseEvent&) {} void SAL_CALL PresenterScrollBar::mouseExited (const css::awt::MouseEvent&) { if (meMouseMoveArea != None) { const Area eOldMouseMoveArea (meMouseMoveArea); meMouseMoveArea = None; Repaint(GetRectangle(eOldMouseMoveArea), true); } meButtonDownArea = None; meMouseMoveArea = None; mpMousePressRepeater->Stop(); } //----- XMouseMotionListener -------------------------------------------------- void SAL_CALL PresenterScrollBar::mouseMoved (const css::awt::MouseEvent& rEvent) { const Area eArea (GetArea(rEvent.X, rEvent.Y)); if (eArea != meMouseMoveArea) { const Area eOldMouseMoveArea (meMouseMoveArea); meMouseMoveArea = eArea; if (eOldMouseMoveArea != None) Repaint(GetRectangle(eOldMouseMoveArea), meMouseMoveArea==None); if (meMouseMoveArea != None) Repaint(GetRectangle(meMouseMoveArea), true); } mpMousePressRepeater->SetMouseArea(eArea); } void SAL_CALL PresenterScrollBar::mouseDragged (const css::awt::MouseEvent& rEvent) { if (meButtonDownArea != Thumb) return; mpMousePressRepeater->Stop(); if (mxPresenterHelper.is()) mxPresenterHelper->captureMouse(mxWindow); const double nDragDistance (GetDragDistance(rEvent.X,rEvent.Y)); UpdateDragAnchor(nDragDistance); if (nDragDistance != 0) { SetThumbPosition(mnThumbPosition + nDragDistance, false); } } //----- lang::XEventListener -------------------------------------------------- void SAL_CALL PresenterScrollBar::disposing (const css::lang::EventObject& rEvent) { if (rEvent.Source == mxWindow) mxWindow = nullptr; } geometry::RealRectangle2D const & PresenterScrollBar::GetRectangle (const Area eArea) const { OSL_ASSERT(eArea>=0 && eAreaInvalidate( mxWindow, PresenterGeometryHelper::ConvertRectangle(rBox), bAsynchronousUpdate); } void PresenterScrollBar::PaintBackground( const css::awt::Rectangle& rUpdateBox) { if (!mpBackgroundBitmap) return; const awt::Rectangle aWindowBox (mxWindow->getPosSize()); mpCanvasHelper->Paint( mpBackgroundBitmap, mxCanvas, rUpdateBox, aWindowBox, awt::Rectangle()); } void PresenterScrollBar::PaintBitmap( const css::awt::Rectangle& rUpdateBox, const Area eArea, const SharedBitmapDescriptor& rpBitmaps) { const geometry::RealRectangle2D aLocalBox (GetRectangle(eArea)); const awt::Rectangle aWindowBox (mxWindow->getPosSize()); geometry::RealRectangle2D aBox (aLocalBox); aBox.X1 += aWindowBox.X; aBox.Y1 += aWindowBox.Y; aBox.X2 += aWindowBox.X; aBox.Y2 += aWindowBox.Y; Reference xBitmap (GetBitmap(eArea,rpBitmaps)); if (!xBitmap.is()) return; Reference xClipPolygon ( PresenterGeometryHelper::CreatePolygon( PresenterGeometryHelper::Intersection(rUpdateBox, PresenterGeometryHelper::ConvertRectangle(aBox)), mxCanvas->getDevice())); const rendering::ViewState aViewState ( geometry::AffineMatrix2D(1,0,0, 0,1,0), xClipPolygon); const geometry::IntegerSize2D aBitmapSize (xBitmap->getSize()); rendering::RenderState aRenderState ( geometry::AffineMatrix2D( 1,0,aBox.X1 + (aBox.X2-aBox.X1 - aBitmapSize.Width)/2, 0,1,aBox.Y1 + (aBox.Y2-aBox.Y1 - aBitmapSize.Height)/2), nullptr, Sequence(4), rendering::CompositeOperation::SOURCE); mxCanvas->drawBitmap( xBitmap, aViewState, aRenderState); } PresenterScrollBar::Area PresenterScrollBar::GetArea (const double nX, const double nY) const { const geometry::RealPoint2D aPoint(nX, nY); if (PresenterGeometryHelper::IsInside(GetRectangle(Pager), aPoint)) { if (PresenterGeometryHelper::IsInside(GetRectangle(Thumb), aPoint)) return Thumb; else if (PresenterGeometryHelper::IsInside(GetRectangle(PagerUp), aPoint)) return PagerUp; else if (PresenterGeometryHelper::IsInside(GetRectangle(PagerDown), aPoint)) return PagerDown; } else if (PresenterGeometryHelper::IsInside(GetRectangle(PrevButton), aPoint)) return PrevButton; else if (PresenterGeometryHelper::IsInside(GetRectangle(NextButton), aPoint)) return NextButton; return None; } void PresenterScrollBar::UpdateWidthOrHeight ( sal_Int32& rSize, const SharedBitmapDescriptor& rpDescriptor) { if (rpDescriptor) { Reference xBitmap (rpDescriptor->GetNormalBitmap()); if (xBitmap.is()) { const geometry::IntegerSize2D aBitmapSize (xBitmap->getSize()); const sal_Int32 nBitmapSize = static_cast(GetMinor(aBitmapSize.Width, aBitmapSize.Height)); if (nBitmapSize > rSize) rSize = nBitmapSize; } } } css::uno::Reference PresenterScrollBar::GetBitmap ( const Area eArea, const SharedBitmapDescriptor& rpBitmaps) const { if (!rpBitmaps) return nullptr; else return rpBitmaps->GetBitmap(GetBitmapMode(eArea)); } PresenterBitmapContainer::BitmapDescriptor::Mode PresenterScrollBar::GetBitmapMode ( const Area eArea) const { if (IsDisabled(eArea)) return PresenterBitmapContainer::BitmapDescriptor::Disabled; else if (eArea == meMouseMoveArea) return PresenterBitmapContainer::BitmapDescriptor::MouseOver; else return PresenterBitmapContainer::BitmapDescriptor::Normal; } bool PresenterScrollBar::IsDisabled (const Area eArea) const { OSL_ASSERT(eArea>=0 && eArea& rxComponentContext, const Reference& rxParentWindow, const std::shared_ptr& rpPaintManager, const ::std::function& rThumbMotionListener) : PresenterScrollBar(rxComponentContext, rxParentWindow, rpPaintManager, rThumbMotionListener), mnScrollBarWidth(0) { } PresenterVerticalScrollBar::~PresenterVerticalScrollBar() { } double PresenterVerticalScrollBar::GetDragDistance (const sal_Int32, const sal_Int32 nY) const { const double nDistance (nY - maDragAnchor.Y); if (nDistance == 0) return 0; else { const awt::Rectangle aWindowBox (mxWindow->getPosSize()); const double nBarWidth (aWindowBox.Width); const double nPagerHeight (aWindowBox.Height - 2*nBarWidth); const double nDragDistance (mnTotalSize / nPagerHeight * nDistance); if (nDragDistance + mnThumbPosition < 0) return -mnThumbPosition; else if (mnThumbPosition + nDragDistance > mnTotalSize-mnThumbSize) return mnTotalSize-mnThumbSize-mnThumbPosition; else return nDragDistance; } } void PresenterVerticalScrollBar::UpdateDragAnchor (const double nDragDistance) { const awt::Rectangle aWindowBox (mxWindow->getPosSize()); const double nBarWidth (aWindowBox.Width); const double nPagerHeight (aWindowBox.Height - 2*nBarWidth); maDragAnchor.Y += nDragDistance * nPagerHeight / mnTotalSize; } sal_Int32 PresenterVerticalScrollBar::GetSize() const { return mnScrollBarWidth; } double PresenterVerticalScrollBar::GetMinor (const double nX, const double) const { return nX; } void PresenterVerticalScrollBar::UpdateBorders() { const awt::Rectangle aWindowBox (mxWindow->getPosSize()); double nBottom = aWindowBox.Height; if (mpNextButtonDescriptor) { Reference xBitmap (mpNextButtonDescriptor->GetNormalBitmap()); if (xBitmap.is()) { geometry::IntegerSize2D aSize (xBitmap->getSize()); maBox[NextButton] = geometry::RealRectangle2D( 0, nBottom - aSize.Height, aWindowBox.Width, nBottom); nBottom -= aSize.Height + gnScrollBarGap; } } if (mpPrevButtonDescriptor) { Reference xBitmap (mpPrevButtonDescriptor->GetNormalBitmap()); if (xBitmap.is()) { geometry::IntegerSize2D aSize (xBitmap->getSize()); maBox[PrevButton] = geometry::RealRectangle2D( 0, nBottom - aSize.Height, aWindowBox.Width, nBottom); nBottom -= aSize.Height + gnScrollBarGap; } } const double nPagerHeight (nBottom); maBox[Pager] = geometry::RealRectangle2D( 0,0, aWindowBox.Width, nBottom); if (mnTotalSize < 1) { maBox[Thumb] = maBox[Pager]; // Set up the enabled/disabled states. maEnabledState[PrevButton] = false; maEnabledState[PagerUp] = false; maEnabledState[NextButton] = false; maEnabledState[PagerDown] = false; maEnabledState[Thumb] = false; } else { const double nThumbSize = ::std::min(mnThumbSize,mnTotalSize); const double nThumbPosition = ::std::clamp(mnThumbPosition, 0.0, mnTotalSize - nThumbSize); maBox[Thumb] = geometry::RealRectangle2D( 0, nThumbPosition / mnTotalSize * nPagerHeight, aWindowBox.Width, (nThumbPosition+nThumbSize) / mnTotalSize * nPagerHeight); // Set up the enabled/disabled states. maEnabledState[PrevButton] = nThumbPosition>0; maEnabledState[PagerUp] = nThumbPosition>0; maEnabledState[NextButton] = nThumbPosition+nThumbSize < mnTotalSize; maEnabledState[PagerDown] = nThumbPosition+nThumbSize < mnTotalSize; maEnabledState[Thumb] = nThumbSize < mnTotalSize; } maBox[PagerUp] = geometry::RealRectangle2D( maBox[Pager].X1, maBox[Pager].Y1, maBox[Pager].X2, maBox[Thumb].Y1-1); maBox[PagerDown] = geometry::RealRectangle2D( maBox[Pager].X1, maBox[Thumb].Y2+1, maBox[Pager].X2, maBox[Pager].Y2); maBox[Total] = PresenterGeometryHelper::Union( PresenterGeometryHelper::Union(maBox[PrevButton], maBox[NextButton]), maBox[Pager]); } void PresenterVerticalScrollBar::UpdateBitmaps() { if (mpBitmaps == nullptr) return; mpPrevButtonDescriptor = mpBitmaps->GetBitmap("Up"); mpNextButtonDescriptor = mpBitmaps->GetBitmap("Down"); mpPagerStartDescriptor = mpBitmaps->GetBitmap("PagerTop"); mpPagerCenterDescriptor = mpBitmaps->GetBitmap("PagerVertical"); mpPagerEndDescriptor = mpBitmaps->GetBitmap("PagerBottom"); mpThumbStartDescriptor = mpBitmaps->GetBitmap("ThumbTop"); mpThumbCenterDescriptor = mpBitmaps->GetBitmap("ThumbVertical"); mpThumbEndDescriptor = mpBitmaps->GetBitmap("ThumbBottom"); mnScrollBarWidth = 0; UpdateWidthOrHeight(mnScrollBarWidth, mpPrevButtonDescriptor); UpdateWidthOrHeight(mnScrollBarWidth, mpNextButtonDescriptor); UpdateWidthOrHeight(mnScrollBarWidth, mpPagerStartDescriptor); UpdateWidthOrHeight(mnScrollBarWidth, mpPagerCenterDescriptor); UpdateWidthOrHeight(mnScrollBarWidth, mpPagerEndDescriptor); UpdateWidthOrHeight(mnScrollBarWidth, mpThumbStartDescriptor); UpdateWidthOrHeight(mnScrollBarWidth, mpThumbCenterDescriptor); UpdateWidthOrHeight(mnScrollBarWidth, mpThumbEndDescriptor); if (mnScrollBarWidth == 0) mnScrollBarWidth = 20; } void PresenterVerticalScrollBar::PaintComposite( const css::awt::Rectangle& rUpdateBox, const Area eArea, const SharedBitmapDescriptor& rpStartBitmaps, const SharedBitmapDescriptor& rpCenterBitmaps, const SharedBitmapDescriptor& rpEndBitmaps) { const awt::Rectangle aWindowBox (mxWindow->getPosSize()); geometry::RealRectangle2D aBox (GetRectangle(eArea)); aBox.X1 += aWindowBox.X; aBox.Y1 += aWindowBox.Y; aBox.X2 += aWindowBox.X; aBox.Y2 += aWindowBox.Y; // Get bitmaps and sizes. PresenterUIPainter::PaintVerticalBitmapComposite( mxCanvas, rUpdateBox, (eArea == Thumb ? PresenterGeometryHelper::ConvertRectangleWithConstantSize(aBox) : PresenterGeometryHelper::ConvertRectangle(aBox)), GetBitmap(eArea, rpStartBitmaps), GetBitmap(eArea, rpCenterBitmaps), GetBitmap(eArea, rpEndBitmaps)); } //===== PresenterScrollBar::MousePressRepeater ================================ PresenterScrollBar::MousePressRepeater::MousePressRepeater ( const ::rtl::Reference& rpScrollBar) : mnMousePressRepeaterTaskId(PresenterTimer::NotAValidTaskId), mpScrollBar(rpScrollBar), meMouseArea(PresenterScrollBar::None) { } void PresenterScrollBar::MousePressRepeater::Dispose() { Stop(); mpScrollBar = nullptr; } void PresenterScrollBar::MousePressRepeater::Start (const PresenterScrollBar::Area& reArea) { meMouseArea = reArea; if (mnMousePressRepeaterTaskId == PresenterTimer::NotAValidTaskId) { // Execute key press operation at least this one time. Execute(); // Schedule repeated executions. auto pThis(shared_from_this()); mnMousePressRepeaterTaskId = PresenterTimer::ScheduleRepeatedTask ( mpScrollBar->GetComponentContext(), [pThis] (TimeValue const&) { return pThis->Callback(); }, 500000000, 250000000); } else { // There is already an active repeating task. } } void PresenterScrollBar::MousePressRepeater::Stop() { if (mnMousePressRepeaterTaskId != PresenterTimer::NotAValidTaskId) { const sal_Int32 nTaskId (mnMousePressRepeaterTaskId); mnMousePressRepeaterTaskId = PresenterTimer::NotAValidTaskId; PresenterTimer::CancelTask(nTaskId); } } void PresenterScrollBar::MousePressRepeater::SetMouseArea(const PresenterScrollBar::Area& reArea) { if (meMouseArea != reArea) { if (mnMousePressRepeaterTaskId != PresenterTimer::NotAValidTaskId) { Stop(); } } } void PresenterScrollBar::MousePressRepeater::Callback () { if (!mpScrollBar) { Stop(); return; } Execute(); } void PresenterScrollBar::MousePressRepeater::Execute() { const double nThumbPosition (mpScrollBar->GetThumbPosition()); switch (meMouseArea) { case PrevButton: mpScrollBar->SetThumbPosition(nThumbPosition - mpScrollBar->GetLineHeight(), true); break; case NextButton: mpScrollBar->SetThumbPosition(nThumbPosition + mpScrollBar->GetLineHeight(), true); break; case PagerUp: mpScrollBar->SetThumbPosition(nThumbPosition - mpScrollBar->GetThumbSize()*0.8, true); break; case PagerDown: mpScrollBar->SetThumbPosition(nThumbPosition + mpScrollBar->GetThumbSize()*0.8, true); break; default: break; } } } // end of namespace ::sdext::presenter /* vim:set shiftwidth=4 softtabstop=4 expandtab: */