diff options
Diffstat (limited to 'vcl/source/control/scrbar.cxx')
-rw-r--r-- | vcl/source/control/scrbar.cxx | 1648 |
1 files changed, 1648 insertions, 0 deletions
diff --git a/vcl/source/control/scrbar.cxx b/vcl/source/control/scrbar.cxx new file mode 100644 index 000000000000..9c82bb096dec --- /dev/null +++ b/vcl/source/control/scrbar.cxx @@ -0,0 +1,1648 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include "vcl/event.hxx" +#include "vcl/sound.hxx" +#include "vcl/decoview.hxx" +#include "vcl/scrbar.hxx" +#include "vcl/timer.hxx" +#include "vcl/svdata.hxx" + +#include "rtl/string.hxx" +#include "tools/rc.h" + + + +using namespace rtl; + +/* #i77549# + HACK: for scrollbars in case of thumb rect, page up and page down rect we + abuse the HitTestNativeControl interface. All theming engines but aqua + are actually able to draw the thumb according to our internal representation. + However aqua draws a little outside. The canonical way would be to enhance the + HitTestNativeControl passing a ScrollbarValue additionally so all necessary + information is available in the call. + . + However since there is only this one small exception we will deviate a little and + instead pass the respective rect as control region to allow for a small correction. + + So all places using HitTestNativeControl on PART_THUMB_HORZ, PART_THUMB_VERT, + PART_TRACK_HORZ_LEFT, PART_TRACK_HORZ_RIGHT, PART_TRACK_VERT_UPPER, PART_TRACK_VERT_LOWER + do not use the control rectangle as region but the actuall part rectangle, making + only small deviations feasible. +*/ + + +// ======================================================================= + +static long ImplMulDiv( long nNumber, long nNumerator, long nDenominator ) +{ + double n = ((double)nNumber * (double)nNumerator) / (double)nDenominator; + return (long)n; +} + +// ======================================================================= + +#define SCRBAR_DRAW_BTN1 ((USHORT)0x0001) +#define SCRBAR_DRAW_BTN2 ((USHORT)0x0002) +#define SCRBAR_DRAW_PAGE1 ((USHORT)0x0004) +#define SCRBAR_DRAW_PAGE2 ((USHORT)0x0008) +#define SCRBAR_DRAW_THUMB ((USHORT)0x0010) +#define SCRBAR_DRAW_BACKGROUND ((USHORT)0x0020) +#define SCRBAR_DRAW_ALL (SCRBAR_DRAW_BTN1 | SCRBAR_DRAW_BTN2 | \ + SCRBAR_DRAW_PAGE1 | SCRBAR_DRAW_PAGE2 |\ + SCRBAR_DRAW_THUMB | SCRBAR_DRAW_BACKGROUND ) + +#define SCRBAR_STATE_BTN1_DOWN ((USHORT)0x0001) +#define SCRBAR_STATE_BTN1_DISABLE ((USHORT)0x0002) +#define SCRBAR_STATE_BTN2_DOWN ((USHORT)0x0004) +#define SCRBAR_STATE_BTN2_DISABLE ((USHORT)0x0008) +#define SCRBAR_STATE_PAGE1_DOWN ((USHORT)0x0010) +#define SCRBAR_STATE_PAGE2_DOWN ((USHORT)0x0020) +#define SCRBAR_STATE_THUMB_DOWN ((USHORT)0x0040) + +#define SCRBAR_VIEW_STYLE (WB_3DLOOK | WB_HORZ | WB_VERT) + +struct ImplScrollBarData +{ + AutoTimer maTimer; // Timer + BOOL mbHide; + Rectangle maTrackRect; // TODO: move to ScrollBar class when binary incompatibility of ScrollBar class is no longer problematic +}; + +// ======================================================================= + +void ScrollBar::ImplInit( Window* pParent, WinBits nStyle ) +{ + mpData = NULL; + mnThumbPixRange = 0; + mnThumbPixPos = 0; + mnThumbPixSize = 0; + mnMinRange = 0; + mnMaxRange = 100; + mnThumbPos = 0; + mnVisibleSize = 0; + mnLineSize = 1; + mnPageSize = 1; + mnDelta = 0; + mnDragDraw = 0; + mnStateFlags = 0; + meScrollType = SCROLL_DONTKNOW; + meDDScrollType = SCROLL_DONTKNOW; + mbCalcSize = TRUE; + mbFullDrag = 0; + + if( !mpData ) // TODO: remove when maTrackRect is no longer in mpData + { + mpData = new ImplScrollBarData; + mpData->maTimer.SetTimeoutHdl( LINK( this, ScrollBar, ImplAutoTimerHdl ) ); + mpData->mbHide = FALSE; + } + + ImplInitStyle( nStyle ); + Control::ImplInit( pParent, nStyle, NULL ); + + long nScrollSize = GetSettings().GetStyleSettings().GetScrollBarSize(); + SetSizePixel( Size( nScrollSize, nScrollSize ) ); + SetBackground(); +} + +// ----------------------------------------------------------------------- + +void ScrollBar::ImplInitStyle( WinBits nStyle ) +{ + if ( nStyle & WB_DRAG ) + mbFullDrag = TRUE; + else + mbFullDrag = (GetSettings().GetStyleSettings().GetDragFullOptions() & DRAGFULL_OPTION_SCROLL) != 0; +} + +// ----------------------------------------------------------------------- + +ScrollBar::ScrollBar( Window* pParent, WinBits nStyle ) : + Control( WINDOW_SCROLLBAR ) +{ + ImplInit( pParent, nStyle ); +} + +// ----------------------------------------------------------------------- + +ScrollBar::ScrollBar( Window* pParent, const ResId& rResId ) : + Control( WINDOW_SCROLLBAR ) +{ + rResId.SetRT( RSC_SCROLLBAR ); + WinBits nStyle = ImplInitRes( rResId ); + ImplInit( pParent, nStyle ); + ImplLoadRes( rResId ); + + if ( !(nStyle & WB_HIDE) ) + Show(); +} + +// ----------------------------------------------------------------------- + +ScrollBar::~ScrollBar() +{ + if( mpData ) + delete mpData; +} + +// ----------------------------------------------------------------------- + +void ScrollBar::ImplLoadRes( const ResId& rResId ) +{ + Control::ImplLoadRes( rResId ); + + INT16 nMin = ReadShortRes(); + INT16 nMax = ReadShortRes(); + INT16 nThumbPos = ReadShortRes(); + INT16 nPage = ReadShortRes(); + INT16 nStep = ReadShortRes(); + INT16 nVisibleSize = ReadShortRes(); + + SetRange( Range( nMin, nMax ) ); + SetLineSize( nStep ); + SetPageSize( nPage ); + SetVisibleSize( nVisibleSize ); + SetThumbPos( nThumbPos ); +} + +// ----------------------------------------------------------------------- + +void ScrollBar::ImplUpdateRects( BOOL bUpdate ) +{ + USHORT nOldStateFlags = mnStateFlags; + Rectangle aOldPage1Rect = maPage1Rect; + Rectangle aOldPage2Rect = maPage2Rect; + Rectangle aOldThumbRect = maThumbRect; + + mnStateFlags &= ~SCRBAR_STATE_BTN1_DISABLE; + mnStateFlags &= ~SCRBAR_STATE_BTN2_DISABLE; + + Rectangle& maTrackRect = mpData->maTrackRect; // TODO: remove when maTrackRect is no longer in mpData + if ( mnThumbPixRange ) + { + if ( GetStyle() & WB_HORZ ) + { + maThumbRect.Left() = maTrackRect.Left()+mnThumbPixPos; + maThumbRect.Right() = maThumbRect.Left()+mnThumbPixSize-1; + if ( !mnThumbPixPos ) + maPage1Rect.Right() = RECT_EMPTY; + else + maPage1Rect.Right() = maThumbRect.Left()-1; + if ( mnThumbPixPos >= (mnThumbPixRange-mnThumbPixSize) ) + maPage2Rect.Right() = RECT_EMPTY; + else + { + maPage2Rect.Left() = maThumbRect.Right()+1; + maPage2Rect.Right() = maTrackRect.Right(); + } + } + else + { + maThumbRect.Top() = maTrackRect.Top()+mnThumbPixPos; + maThumbRect.Bottom() = maThumbRect.Top()+mnThumbPixSize-1; + if ( !mnThumbPixPos ) + maPage1Rect.Bottom() = RECT_EMPTY; + else + maPage1Rect.Bottom() = maThumbRect.Top()-1; + if ( mnThumbPixPos >= (mnThumbPixRange-mnThumbPixSize) ) + maPage2Rect.Bottom() = RECT_EMPTY; + else + { + maPage2Rect.Top() = maThumbRect.Bottom()+1; + maPage2Rect.Bottom() = maTrackRect.Bottom(); + } + } + } + else + { + Size aScrBarSize = GetOutputSizePixel(); + if ( GetStyle() & WB_HORZ ) + { + const long nSpace = maTrackRect.Right() - maTrackRect.Left(); + if ( nSpace > 0 ) + { + maPage1Rect.Left() = maTrackRect.Left(); + maPage1Rect.Right() = maTrackRect.Left() + (nSpace/2); + maPage2Rect.Left() = maPage1Rect.Right() + 1; + maPage2Rect.Right() = maTrackRect.Right(); + } + } + else + { + const long nSpace = maTrackRect.Bottom() - maTrackRect.Top(); + if ( nSpace > 0 ) + { + maPage1Rect.Top() = maTrackRect.Top(); + maPage1Rect.Bottom() = maTrackRect.Top() + (nSpace/2); + maPage2Rect.Top() = maPage1Rect.Bottom() + 1; + maPage2Rect.Bottom() = maTrackRect.Bottom(); + } + } + } + + if( !IsNativeControlSupported(CTRL_SCROLLBAR, PART_ENTIRE_CONTROL) ) + { + // disable scrollbar buttons only in VCL's own 'theme' + // as it is uncommon on other platforms + if ( mnThumbPos == mnMinRange ) + mnStateFlags |= SCRBAR_STATE_BTN1_DISABLE; + if ( mnThumbPos >= (mnMaxRange-mnVisibleSize) ) + mnStateFlags |= SCRBAR_STATE_BTN2_DISABLE; + } + + if ( bUpdate ) + { + USHORT nDraw = 0; + if ( (nOldStateFlags & SCRBAR_STATE_BTN1_DISABLE) != + (mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) ) + nDraw |= SCRBAR_DRAW_BTN1; + if ( (nOldStateFlags & SCRBAR_STATE_BTN2_DISABLE) != + (mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) ) + nDraw |= SCRBAR_DRAW_BTN2; + if ( aOldPage1Rect != maPage1Rect ) + nDraw |= SCRBAR_DRAW_PAGE1; + if ( aOldPage2Rect != maPage2Rect ) + nDraw |= SCRBAR_DRAW_PAGE2; + if ( aOldThumbRect != maThumbRect ) + nDraw |= SCRBAR_DRAW_THUMB; + ImplDraw( nDraw, this ); + } +} + +// ----------------------------------------------------------------------- + +long ScrollBar::ImplCalcThumbPos( long nPixPos ) +{ + // Position berechnen + long nCalcThumbPos; + nCalcThumbPos = ImplMulDiv( nPixPos, mnMaxRange-mnVisibleSize-mnMinRange, + mnThumbPixRange-mnThumbPixSize ); + nCalcThumbPos += mnMinRange; + return nCalcThumbPos; +} + +// ----------------------------------------------------------------------- + +long ScrollBar::ImplCalcThumbPosPix( long nPos ) +{ + long nCalcThumbPos; + + // Position berechnen + nCalcThumbPos = ImplMulDiv( nPos-mnMinRange, mnThumbPixRange-mnThumbPixSize, + mnMaxRange-mnVisibleSize-mnMinRange ); + + // Am Anfang und Ende des ScrollBars versuchen wir die Anzeige korrekt + // anzuzeigen + if ( !nCalcThumbPos && (mnThumbPos > mnMinRange) ) + nCalcThumbPos = 1; + if ( nCalcThumbPos && + ((nCalcThumbPos+mnThumbPixSize) >= mnThumbPixRange) && + (mnThumbPos < (mnMaxRange-mnVisibleSize)) ) + nCalcThumbPos--; + + return nCalcThumbPos; +} + +// ----------------------------------------------------------------------- + +void ScrollBar::ImplCalc( BOOL bUpdate ) +{ + const Size aSize = GetOutputSizePixel(); + const long nMinThumbSize = GetSettings().GetStyleSettings().GetMinThumbSize();; + + Rectangle& maTrackRect = mpData->maTrackRect; // TODO: remove when maTrackRect is no longer in mpData + if ( mbCalcSize ) + { + const Rectangle aControlRegion( Point(0,0), aSize ); + Rectangle aBtn1Region, aBtn2Region, aTrackRegion, aBoundingRegion; + + if ( GetStyle() & WB_HORZ ) + { + if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_BUTTON_LEFT, + aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aBtn1Region ) && + GetNativeControlRegion( CTRL_SCROLLBAR, PART_BUTTON_RIGHT, + aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aBtn2Region ) ) + { + maBtn1Rect = aBtn1Region; + maBtn2Rect = aBtn2Region; + } + else + { + Size aBtnSize( aSize.Height(), aSize.Height() ); + maBtn2Rect.Top() = maBtn1Rect.Top(); + maBtn2Rect.Left() = aSize.Width()-aSize.Height(); + maBtn1Rect.SetSize( aBtnSize ); + maBtn2Rect.SetSize( aBtnSize ); + } + + if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_TRACK_HORZ_AREA, + aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aTrackRegion ) ) + maTrackRect = aTrackRegion; + else + maTrackRect = Rectangle( maBtn1Rect.TopRight(), maBtn2Rect.BottomLeft() ); + + // Check if available space is big enough for thumb ( min thumb size = ScrBar width/height ) + mnThumbPixRange = maTrackRect.Right() - maTrackRect.Left(); + if( mnThumbPixRange > 0 ) + { + maPage1Rect.Left() = maTrackRect.Left(); + maPage1Rect.Bottom() = + maPage2Rect.Bottom() = + maThumbRect.Bottom() = maTrackRect.Bottom(); + } + else + { + mnThumbPixRange = 0; + maPage1Rect.SetEmpty(); + maPage2Rect.SetEmpty(); + } + } + else + { + if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_BUTTON_UP, + aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aBtn1Region ) && + GetNativeControlRegion( CTRL_SCROLLBAR, PART_BUTTON_DOWN, + aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aBtn2Region ) ) + { + maBtn1Rect = aBtn1Region; + maBtn2Rect = aBtn2Region; + } + else + { + const Size aBtnSize( aSize.Width(), aSize.Width() ); + maBtn2Rect.Left() = maBtn1Rect.Left(); + maBtn2Rect.Top() = aSize.Height()-aSize.Width(); + maBtn1Rect.SetSize( aBtnSize ); + maBtn2Rect.SetSize( aBtnSize ); + } + + if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_TRACK_VERT_AREA, + aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aTrackRegion ) ) + maTrackRect = aTrackRegion; + else + maTrackRect = Rectangle( maBtn1Rect.BottomLeft()+Point(0,1), maBtn2Rect.TopRight() ); + + // Check if available space is big enough for thumb + mnThumbPixRange = maTrackRect.Bottom() - maTrackRect.Top(); + if( mnThumbPixRange > 0 ) + { + maPage1Rect.Top() = maTrackRect.Top(); + maPage1Rect.Right() = + maPage2Rect.Right() = + maThumbRect.Right() = maTrackRect.Right(); + } + else + { + mnThumbPixRange = 0; + maPage1Rect.SetEmpty(); + maPage2Rect.SetEmpty(); + } + } + + if ( !mnThumbPixRange ) + maThumbRect.SetEmpty(); + + mbCalcSize = FALSE; + } + + if ( mnThumbPixRange ) + { + // Werte berechnen + if ( (mnVisibleSize >= (mnMaxRange-mnMinRange)) || + ((mnMaxRange-mnMinRange) <= 0) ) + { + mnThumbPos = mnMinRange; + mnThumbPixPos = 0; + mnThumbPixSize = mnThumbPixRange; + } + else + { + if ( mnVisibleSize ) + mnThumbPixSize = ImplMulDiv( mnThumbPixRange, mnVisibleSize, mnMaxRange-mnMinRange ); + else + { + if ( GetStyle() & WB_HORZ ) + mnThumbPixSize = maThumbRect.GetWidth(); + else + mnThumbPixSize = maThumbRect.GetHeight(); + } + if ( mnThumbPixSize < nMinThumbSize ) + mnThumbPixSize = nMinThumbSize; + if ( mnThumbPixSize > mnThumbPixRange ) + mnThumbPixSize = mnThumbPixRange; + mnThumbPixPos = ImplCalcThumbPosPix( mnThumbPos ); + } + } + + // Wenn neu ausgegeben werden soll und wir schon ueber eine + // Aktion einen Paint-Event ausgeloest bekommen haben, dann + // geben wir nicht direkt aus, sondern invalidieren nur alles + if ( bUpdate && HasPaintEvent() ) + { + Invalidate(); + bUpdate = FALSE; + } + ImplUpdateRects( bUpdate ); +} + +// ----------------------------------------------------------------------- + +void ScrollBar::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags ) +{ + Point aPos = pDev->LogicToPixel( rPos ); + Size aSize = pDev->LogicToPixel( rSize ); + Rectangle aRect( aPos, aSize ); + + pDev->Push(); + pDev->SetMapMode(); + if ( !(nFlags & WINDOW_DRAW_MONO) ) + { + // DecoView uses the FaceColor... + AllSettings aSettings = pDev->GetSettings(); + StyleSettings aStyleSettings = aSettings.GetStyleSettings(); + if ( IsControlBackground() ) + aStyleSettings.SetFaceColor( GetControlBackground() ); + else + aStyleSettings.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() ); + + aSettings.SetStyleSettings( aStyleSettings ); + pDev->SetSettings( aSettings ); + } + + // for printing: + // -calculate the size of the rects + // -because this is zero-based add the correct offset + // -print + // -force recalculate + + if ( mbCalcSize ) + ImplCalc( FALSE ); + + maBtn1Rect+=aPos; + maBtn2Rect+=aPos; + maThumbRect+=aPos; + mpData->maTrackRect+=aPos; // TODO: update when maTrackRect is no longer in mpData + maPage1Rect+=aPos; + maPage2Rect+=aPos; + + ImplDraw( SCRBAR_DRAW_ALL, pDev ); + pDev->Pop(); + + mbCalcSize = TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL ScrollBar::ImplDrawNative( USHORT nDrawFlags ) +{ + ScrollbarValue scrValue; + + BOOL bNativeOK = IsNativeControlSupported(CTRL_SCROLLBAR, PART_ENTIRE_CONTROL); + if( bNativeOK ) + { + BOOL bHorz = (GetStyle() & WB_HORZ ? true : false); + + // Draw the entire background if the control supports it + if( IsNativeControlSupported(CTRL_SCROLLBAR, bHorz ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT) ) + { + ControlState nState = ( IsEnabled() ? CTRL_STATE_ENABLED : 0 ) | ( HasFocus() ? CTRL_STATE_FOCUSED : 0 ); + + scrValue.mnMin = mnMinRange; + scrValue.mnMax = mnMaxRange; + scrValue.mnCur = mnThumbPos; + scrValue.mnVisibleSize = mnVisibleSize; + scrValue.maThumbRect = maThumbRect; + scrValue.maButton1Rect = maBtn1Rect; + scrValue.maButton2Rect = maBtn2Rect; + scrValue.mnButton1State = ((mnStateFlags & SCRBAR_STATE_BTN1_DOWN) ? CTRL_STATE_PRESSED : 0) | + ((!(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE)) ? CTRL_STATE_ENABLED : 0); + scrValue.mnButton2State = ((mnStateFlags & SCRBAR_STATE_BTN2_DOWN) ? CTRL_STATE_PRESSED : 0) | + ((!(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE)) ? CTRL_STATE_ENABLED : 0); + scrValue.mnThumbState = nState | ((mnStateFlags & SCRBAR_STATE_THUMB_DOWN) ? CTRL_STATE_PRESSED : 0); + scrValue.mnPage1State = nState | ((mnStateFlags & SCRBAR_STATE_PAGE1_DOWN) ? CTRL_STATE_PRESSED : 0); + scrValue.mnPage2State = nState | ((mnStateFlags & SCRBAR_STATE_PAGE2_DOWN) ? CTRL_STATE_PRESSED : 0); + + if( IsMouseOver() ) + { + Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() ); + if( pRect ) + { + if( pRect == &maThumbRect ) + scrValue.mnThumbState |= CTRL_STATE_ROLLOVER; + else if( pRect == &maBtn1Rect ) + scrValue.mnButton1State |= CTRL_STATE_ROLLOVER; + else if( pRect == &maBtn2Rect ) + scrValue.mnButton2State |= CTRL_STATE_ROLLOVER; + else if( pRect == &maPage1Rect ) + scrValue.mnPage1State |= CTRL_STATE_ROLLOVER; + else if( pRect == &maPage2Rect ) + scrValue.mnPage2State |= CTRL_STATE_ROLLOVER; + } + } + + Rectangle aCtrlRegion; + aCtrlRegion.Union( maBtn1Rect ); + aCtrlRegion.Union( maBtn2Rect ); + aCtrlRegion.Union( maPage1Rect ); + aCtrlRegion.Union( maPage2Rect ); + aCtrlRegion.Union( maThumbRect ); + bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, (bHorz ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT), + aCtrlRegion, nState, scrValue, rtl::OUString() ); + } + else + { + if ( (nDrawFlags & SCRBAR_DRAW_PAGE1) || (nDrawFlags & SCRBAR_DRAW_PAGE2) ) + { + sal_uInt32 part1 = bHorz ? PART_TRACK_HORZ_LEFT : PART_TRACK_VERT_UPPER; + sal_uInt32 part2 = bHorz ? PART_TRACK_HORZ_RIGHT : PART_TRACK_VERT_LOWER; + Rectangle aCtrlRegion1( maPage1Rect ); + Rectangle aCtrlRegion2( maPage2Rect ); + ControlState nState1 = (IsEnabled() ? CTRL_STATE_ENABLED : 0) | (HasFocus() ? CTRL_STATE_FOCUSED : 0); + ControlState nState2 = nState1; + + nState1 |= ((mnStateFlags & SCRBAR_STATE_PAGE1_DOWN) ? CTRL_STATE_PRESSED : 0); + nState2 |= ((mnStateFlags & SCRBAR_STATE_PAGE2_DOWN) ? CTRL_STATE_PRESSED : 0); + + if( IsMouseOver() ) + { + Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() ); + if( pRect ) + { + if( pRect == &maPage1Rect ) + nState1 |= CTRL_STATE_ROLLOVER; + else if( pRect == &maPage2Rect ) + nState2 |= CTRL_STATE_ROLLOVER; + } + } + + if ( nDrawFlags & SCRBAR_DRAW_PAGE1 ) + bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part1, aCtrlRegion1, nState1, + scrValue, rtl::OUString() ); + + if ( nDrawFlags & SCRBAR_DRAW_PAGE2 ) + bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part2, aCtrlRegion2, nState2, + scrValue, rtl::OUString() ); + } + if ( (nDrawFlags & SCRBAR_DRAW_BTN1) || (nDrawFlags & SCRBAR_DRAW_BTN2) ) + { + sal_uInt32 part1 = bHorz ? PART_BUTTON_LEFT : PART_BUTTON_UP; + sal_uInt32 part2 = bHorz ? PART_BUTTON_RIGHT : PART_BUTTON_DOWN; + Rectangle aCtrlRegion1( maBtn1Rect ); + Rectangle aCtrlRegion2( maBtn2Rect ); + ControlState nState1 = HasFocus() ? CTRL_STATE_FOCUSED : 0; + ControlState nState2 = nState1; + + if ( !Window::IsEnabled() || !IsEnabled() ) + nState1 = (nState2 &= ~CTRL_STATE_ENABLED); + else + nState1 = (nState2 |= CTRL_STATE_ENABLED); + + nState1 |= ((mnStateFlags & SCRBAR_STATE_BTN1_DOWN) ? CTRL_STATE_PRESSED : 0); + nState2 |= ((mnStateFlags & SCRBAR_STATE_BTN2_DOWN) ? CTRL_STATE_PRESSED : 0); + + if(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) + nState1 &= ~CTRL_STATE_ENABLED; + if(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) + nState2 &= ~CTRL_STATE_ENABLED; + + if( IsMouseOver() ) + { + Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() ); + if( pRect ) + { + if( pRect == &maBtn1Rect ) + nState1 |= CTRL_STATE_ROLLOVER; + else if( pRect == &maBtn2Rect ) + nState2 |= CTRL_STATE_ROLLOVER; + } + } + + if ( nDrawFlags & SCRBAR_DRAW_BTN1 ) + bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part1, aCtrlRegion1, nState1, + scrValue, rtl::OUString() ); + + if ( nDrawFlags & SCRBAR_DRAW_BTN2 ) + bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part2, aCtrlRegion2, nState2, + scrValue, rtl::OUString() ); + } + if ( (nDrawFlags & SCRBAR_DRAW_THUMB) && !maThumbRect.IsEmpty() ) + { + ControlState nState = IsEnabled() ? CTRL_STATE_ENABLED : 0; + Rectangle aCtrlRegion( maThumbRect ); + + if ( mnStateFlags & SCRBAR_STATE_THUMB_DOWN ) + nState |= CTRL_STATE_PRESSED; + + if ( HasFocus() ) + nState |= CTRL_STATE_FOCUSED; + + if( IsMouseOver() ) + { + Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() ); + if( pRect ) + { + if( pRect == &maThumbRect ) + nState |= CTRL_STATE_ROLLOVER; + } + } + + bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, (bHorz ? PART_THUMB_HORZ : PART_THUMB_VERT), + aCtrlRegion, nState, scrValue, rtl::OUString() ); + } + } + } + return bNativeOK; +} + +void ScrollBar::ImplDraw( USHORT nDrawFlags, OutputDevice* pOutDev ) +{ + DecorationView aDecoView( pOutDev ); + Rectangle aTempRect; + USHORT nStyle; + const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings(); + SymbolType eSymbolType; + BOOL bEnabled = IsEnabled(); + + // Evt. noch offene Berechnungen nachholen + if ( mbCalcSize ) + ImplCalc( FALSE ); + + Window *pWin = NULL; + if( pOutDev->GetOutDevType() == OUTDEV_WINDOW ) + pWin = (Window*) pOutDev; + + // Draw the entire control if the native theme engine needs it + if ( nDrawFlags && pWin && pWin->IsNativeControlSupported(CTRL_SCROLLBAR, PART_DRAW_BACKGROUND_HORZ) ) + { + ImplDrawNative( SCRBAR_DRAW_BACKGROUND ); + return; + } + + if( (nDrawFlags & SCRBAR_DRAW_BTN1) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_BTN1 ) ) ) + { + nStyle = BUTTON_DRAW_NOLIGHTBORDER; + if ( mnStateFlags & SCRBAR_STATE_BTN1_DOWN ) + nStyle |= BUTTON_DRAW_PRESSED; + aTempRect = aDecoView.DrawButton( maBtn1Rect, nStyle ); + ImplCalcSymbolRect( aTempRect ); + nStyle = 0; + if ( (mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) || !bEnabled ) + nStyle |= SYMBOL_DRAW_DISABLE; + if ( rStyleSettings.GetOptions() & STYLE_OPTION_SCROLLARROW ) + { + if ( GetStyle() & WB_HORZ ) + eSymbolType = SYMBOL_ARROW_LEFT; + else + eSymbolType = SYMBOL_ARROW_UP; + } + else + { + if ( GetStyle() & WB_HORZ ) + eSymbolType = SYMBOL_SPIN_LEFT; + else + eSymbolType = SYMBOL_SPIN_UP; + } + aDecoView.DrawSymbol( aTempRect, eSymbolType, rStyleSettings.GetButtonTextColor(), nStyle ); + } + + if ( (nDrawFlags & SCRBAR_DRAW_BTN2) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_BTN2 ) ) ) + { + nStyle = BUTTON_DRAW_NOLIGHTBORDER; + if ( mnStateFlags & SCRBAR_STATE_BTN2_DOWN ) + nStyle |= BUTTON_DRAW_PRESSED; + aTempRect = aDecoView.DrawButton( maBtn2Rect, nStyle ); + ImplCalcSymbolRect( aTempRect ); + nStyle = 0; + if ( (mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) || !bEnabled ) + nStyle |= SYMBOL_DRAW_DISABLE; + if ( rStyleSettings.GetOptions() & STYLE_OPTION_SCROLLARROW ) + { + if ( GetStyle() & WB_HORZ ) + eSymbolType = SYMBOL_ARROW_RIGHT; + else + eSymbolType = SYMBOL_ARROW_DOWN; + } + else + { + if ( GetStyle() & WB_HORZ ) + eSymbolType = SYMBOL_SPIN_RIGHT; + else + eSymbolType = SYMBOL_SPIN_DOWN; + } + aDecoView.DrawSymbol( aTempRect, eSymbolType, rStyleSettings.GetButtonTextColor(), nStyle ); + } + + pOutDev->SetLineColor(); + + if ( (nDrawFlags & SCRBAR_DRAW_THUMB) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_THUMB ) ) ) + { + if ( !maThumbRect.IsEmpty() ) + { + if ( bEnabled ) + { + nStyle = BUTTON_DRAW_NOLIGHTBORDER; + // pressed thumbs only in OS2 style + if ( rStyleSettings.GetOptions() & STYLE_OPTION_OS2STYLE ) + if ( mnStateFlags & SCRBAR_STATE_THUMB_DOWN ) + nStyle |= BUTTON_DRAW_PRESSED; + aTempRect = aDecoView.DrawButton( maThumbRect, nStyle ); + // OS2 style requires pattern on the thumb + if ( rStyleSettings.GetOptions() & STYLE_OPTION_OS2STYLE ) + { + if ( GetStyle() & WB_HORZ ) + { + if ( aTempRect.GetWidth() > 6 ) + { + long nX = aTempRect.Center().X(); + nX -= 6; + if ( nX < aTempRect.Left() ) + nX = aTempRect.Left(); + for ( int i = 0; i < 6; i++ ) + { + if ( nX > aTempRect.Right()-1 ) + break; + + pOutDev->SetLineColor( rStyleSettings.GetButtonTextColor() ); + pOutDev->DrawLine( Point( nX, aTempRect.Top()+1 ), + Point( nX, aTempRect.Bottom()-1 ) ); + nX++; + pOutDev->SetLineColor( rStyleSettings.GetLightColor() ); + pOutDev->DrawLine( Point( nX, aTempRect.Top()+1 ), + Point( nX, aTempRect.Bottom()-1 ) ); + nX++; + } + } + } + else + { + if ( aTempRect.GetHeight() > 6 ) + { + long nY = aTempRect.Center().Y(); + nY -= 6; + if ( nY < aTempRect.Top() ) + nY = aTempRect.Top(); + for ( int i = 0; i < 6; i++ ) + { + if ( nY > aTempRect.Bottom()-1 ) + break; + + pOutDev->SetLineColor( rStyleSettings.GetButtonTextColor() ); + pOutDev->DrawLine( Point( aTempRect.Left()+1, nY ), + Point( aTempRect.Right()-1, nY ) ); + nY++; + pOutDev->SetLineColor( rStyleSettings.GetLightColor() ); + pOutDev->DrawLine( Point( aTempRect.Left()+1, nY ), + Point( aTempRect.Right()-1, nY ) ); + nY++; + } + } + } + pOutDev->SetLineColor(); + } + } + else + { + pOutDev->SetFillColor( rStyleSettings.GetCheckedColor() ); + pOutDev->DrawRect( maThumbRect ); + } + } + } + + if ( (nDrawFlags & SCRBAR_DRAW_PAGE1) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_PAGE1 ) ) ) + { + if ( mnStateFlags & SCRBAR_STATE_PAGE1_DOWN ) + pOutDev->SetFillColor( rStyleSettings.GetShadowColor() ); + else + pOutDev->SetFillColor( rStyleSettings.GetCheckedColor() ); + pOutDev->DrawRect( maPage1Rect ); + } + if ( (nDrawFlags & SCRBAR_DRAW_PAGE2) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_PAGE2 ) ) ) + { + if ( mnStateFlags & SCRBAR_STATE_PAGE2_DOWN ) + pOutDev->SetFillColor( rStyleSettings.GetShadowColor() ); + else + pOutDev->SetFillColor( rStyleSettings.GetCheckedColor() ); + pOutDev->DrawRect( maPage2Rect ); + } +} + +// ----------------------------------------------------------------------- + +long ScrollBar::ImplScroll( long nNewPos, BOOL bCallEndScroll ) +{ + long nOldPos = mnThumbPos; + SetThumbPos( nNewPos ); + long nDelta = mnThumbPos-nOldPos; + if ( nDelta ) + { + mnDelta = nDelta; + Scroll(); + if ( bCallEndScroll ) + EndScroll(); + mnDelta = 0; + } + return nDelta; +} + +// ----------------------------------------------------------------------- + +long ScrollBar::ImplDoAction( BOOL bCallEndScroll ) +{ + long nDelta = 0; + + switch ( meScrollType ) + { + case SCROLL_LINEUP: + nDelta = ImplScroll( mnThumbPos-mnLineSize, bCallEndScroll ); + break; + + case SCROLL_LINEDOWN: + nDelta = ImplScroll( mnThumbPos+mnLineSize, bCallEndScroll ); + break; + + case SCROLL_PAGEUP: + nDelta = ImplScroll( mnThumbPos-mnPageSize, bCallEndScroll ); + break; + + case SCROLL_PAGEDOWN: + nDelta = ImplScroll( mnThumbPos+mnPageSize, bCallEndScroll ); + break; + default: + ; + } + + return nDelta; +} + +// ----------------------------------------------------------------------- + +void ScrollBar::ImplDoMouseAction( const Point& rMousePos, BOOL bCallAction ) +{ + USHORT nOldStateFlags = mnStateFlags; + BOOL bAction = FALSE; + BOOL bHorizontal = ( GetStyle() & WB_HORZ )? TRUE: FALSE; + BOOL bIsInside = FALSE; + + Point aPoint( 0, 0 ); + Rectangle aControlRegion( aPoint, GetOutputSizePixel() ); + + switch ( meScrollType ) + { + case SCROLL_LINEUP: + if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_LEFT: PART_BUTTON_UP, + aControlRegion, rMousePos, bIsInside )? + bIsInside: + maBtn1Rect.IsInside( rMousePos ) ) + { + bAction = bCallAction; + mnStateFlags |= SCRBAR_STATE_BTN1_DOWN; + } + else + mnStateFlags &= ~SCRBAR_STATE_BTN1_DOWN; + break; + + case SCROLL_LINEDOWN: + if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_RIGHT: PART_BUTTON_DOWN, + aControlRegion, rMousePos, bIsInside )? + bIsInside: + maBtn2Rect.IsInside( rMousePos ) ) + { + bAction = bCallAction; + mnStateFlags |= SCRBAR_STATE_BTN2_DOWN; + } + else + mnStateFlags &= ~SCRBAR_STATE_BTN2_DOWN; + break; + + case SCROLL_PAGEUP: + // HitTestNativeControl, see remark at top of file + if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_LEFT: PART_TRACK_VERT_UPPER, + maPage1Rect, rMousePos, bIsInside )? + bIsInside: + maPage1Rect.IsInside( rMousePos ) ) + { + bAction = bCallAction; + mnStateFlags |= SCRBAR_STATE_PAGE1_DOWN; + } + else + mnStateFlags &= ~SCRBAR_STATE_PAGE1_DOWN; + break; + + case SCROLL_PAGEDOWN: + // HitTestNativeControl, see remark at top of file + if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_RIGHT: PART_TRACK_VERT_LOWER, + maPage2Rect, rMousePos, bIsInside )? + bIsInside: + maPage2Rect.IsInside( rMousePos ) ) + { + bAction = bCallAction; + mnStateFlags |= SCRBAR_STATE_PAGE2_DOWN; + } + else + mnStateFlags &= ~SCRBAR_STATE_PAGE2_DOWN; + break; + default: + ; + } + + if ( nOldStateFlags != mnStateFlags ) + ImplDraw( mnDragDraw, this ); + if ( bAction ) + ImplDoAction( FALSE ); +} + +// ----------------------------------------------------------------------- + +void ScrollBar::ImplDragThumb( const Point& rMousePos ) +{ + long nMovePix; + if ( GetStyle() & WB_HORZ ) + nMovePix = rMousePos.X()-(maThumbRect.Left()+mnMouseOff); + else + nMovePix = rMousePos.Y()-(maThumbRect.Top()+mnMouseOff); + + // move thumb if necessary + if ( nMovePix ) + { + mnThumbPixPos += nMovePix; + if ( mnThumbPixPos < 0 ) + mnThumbPixPos = 0; + if ( mnThumbPixPos > (mnThumbPixRange-mnThumbPixSize) ) + mnThumbPixPos = mnThumbPixRange-mnThumbPixSize; + long nOldPos = mnThumbPos; + mnThumbPos = ImplCalcThumbPos( mnThumbPixPos ); + ImplUpdateRects(); + if ( mbFullDrag && (nOldPos != mnThumbPos) ) + { + mnDelta = mnThumbPos-nOldPos; + Scroll(); + mnDelta = 0; + } + } +} + +// ----------------------------------------------------------------------- + +void ScrollBar::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( rMEvt.IsLeft() || rMEvt.IsMiddle() ) + { + const Point& rMousePos = rMEvt.GetPosPixel(); + USHORT nTrackFlags = 0; + BOOL bHorizontal = ( GetStyle() & WB_HORZ )? TRUE: FALSE; + BOOL bIsInside = FALSE; + BOOL bDragToMouse = FALSE; + + Point aPoint( 0, 0 ); + Rectangle aControlRegion( aPoint, GetOutputSizePixel() ); + + if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_LEFT: PART_BUTTON_UP, + aControlRegion, rMousePos, bIsInside )? + bIsInside: + maBtn1Rect.IsInside( rMousePos ) ) + { + if ( !(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) ) + { + nTrackFlags = STARTTRACK_BUTTONREPEAT; + meScrollType = SCROLL_LINEUP; + mnDragDraw = SCRBAR_DRAW_BTN1; + } + else + Sound::Beep( SOUND_DISABLE, this ); + } + else if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_RIGHT: PART_BUTTON_DOWN, + aControlRegion, rMousePos, bIsInside )? + bIsInside: + maBtn2Rect.IsInside( rMousePos ) ) + { + if ( !(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) ) + { + nTrackFlags = STARTTRACK_BUTTONREPEAT; + meScrollType = SCROLL_LINEDOWN; + mnDragDraw = SCRBAR_DRAW_BTN2; + } + else + Sound::Beep( SOUND_DISABLE, this ); + } + else + { + bool bThumbHit = HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_THUMB_HORZ : PART_THUMB_VERT, + maThumbRect, rMousePos, bIsInside ) + ? bIsInside : maThumbRect.IsInside( rMousePos ); + bool bDragHandling = rMEvt.IsMiddle() || bThumbHit || ImplGetSVData()->maNWFData.mbScrollbarJumpPage; + if( bDragHandling ) + { + if( mpData ) + { + mpData->mbHide = TRUE; // disable focus blinking + if( HasFocus() ) + ImplDraw( SCRBAR_DRAW_THUMB, this ); // paint without focus + } + + if ( mnVisibleSize < mnMaxRange-mnMinRange ) + { + nTrackFlags = 0; + meScrollType = SCROLL_DRAG; + mnDragDraw = SCRBAR_DRAW_THUMB; + + // calculate mouse offset + if( rMEvt.IsMiddle() || (ImplGetSVData()->maNWFData.mbScrollbarJumpPage && !bThumbHit) ) + { + bDragToMouse = TRUE; + if ( GetStyle() & WB_HORZ ) + mnMouseOff = maThumbRect.GetWidth()/2; + else + mnMouseOff = maThumbRect.GetHeight()/2; + } + else + { + if ( GetStyle() & WB_HORZ ) + mnMouseOff = rMousePos.X()-maThumbRect.Left(); + else + mnMouseOff = rMousePos.Y()-maThumbRect.Top(); + } + + mnStateFlags |= SCRBAR_STATE_THUMB_DOWN; + ImplDraw( mnDragDraw, this ); + } + else + Sound::Beep( SOUND_DISABLE, this ); + } + else if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_AREA : PART_TRACK_VERT_AREA, + aControlRegion, rMousePos, bIsInside )? + bIsInside : TRUE ) + { + nTrackFlags = STARTTRACK_BUTTONREPEAT; + + // HitTestNativeControl, see remark at top of file + if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_LEFT : PART_TRACK_VERT_UPPER, + maPage1Rect, rMousePos, bIsInside )? + bIsInside: + maPage1Rect.IsInside( rMousePos ) ) + { + meScrollType = SCROLL_PAGEUP; + mnDragDraw = SCRBAR_DRAW_PAGE1; + } + else + { + meScrollType = SCROLL_PAGEDOWN; + mnDragDraw = SCRBAR_DRAW_PAGE2; + } + } + } + + // Soll Tracking gestartet werden + if ( meScrollType != SCROLL_DONTKNOW ) + { + // remember original position in case of abort or EndScroll-Delta + mnStartPos = mnThumbPos; + // #92906# Call StartTracking() before ImplDoMouseAction(), otherwise + // MouseButtonUp() / EndTracking() may be called if somebody is spending + // a lot of time in the scroll handler + StartTracking( nTrackFlags ); + ImplDoMouseAction( rMousePos ); + + if( bDragToMouse ) + ImplDragThumb( rMousePos ); + } + } +} + +// ----------------------------------------------------------------------- + +void ScrollBar::Tracking( const TrackingEvent& rTEvt ) +{ + if ( rTEvt.IsTrackingEnded() ) + { + // Button und PageRect-Status wieder herstellen + USHORT nOldStateFlags = mnStateFlags; + mnStateFlags &= ~(SCRBAR_STATE_BTN1_DOWN | SCRBAR_STATE_BTN2_DOWN | + SCRBAR_STATE_PAGE1_DOWN | SCRBAR_STATE_PAGE2_DOWN | + SCRBAR_STATE_THUMB_DOWN); + if ( nOldStateFlags != mnStateFlags ) + ImplDraw( mnDragDraw, this ); + mnDragDraw = 0; + + // Bei Abbruch, die alte ThumbPosition wieder herstellen + if ( rTEvt.IsTrackingCanceled() ) + { + long nOldPos = mnThumbPos; + SetThumbPos( mnStartPos ); + mnDelta = mnThumbPos-nOldPos; + Scroll(); + } + + if ( meScrollType == SCROLL_DRAG ) + { + // Wenn gedragt wurde, berechnen wir den Thumb neu, damit + // er wieder auf einer gerundeten ThumbPosition steht + ImplCalc(); + + if ( !mbFullDrag && (mnStartPos != mnThumbPos) ) + { + mnDelta = mnThumbPos-mnStartPos; + Scroll(); + mnDelta = 0; + } + } + + mnDelta = mnThumbPos-mnStartPos; + EndScroll(); + mnDelta = 0; + meScrollType = SCROLL_DONTKNOW; + + if( mpData ) + mpData->mbHide = FALSE; // re-enable focus blinking + } + else + { + const Point rMousePos = rTEvt.GetMouseEvent().GetPosPixel(); + + // Dragging wird speziell behandelt + if ( meScrollType == SCROLL_DRAG ) + ImplDragThumb( rMousePos ); + else + ImplDoMouseAction( rMousePos, rTEvt.IsTrackingRepeat() ); + + // Wenn ScrollBar-Werte so umgesetzt wurden, das es nichts + // mehr zum Tracking gibt, dann berechen wir hier ab + if ( !IsVisible() || (mnVisibleSize >= (mnMaxRange-mnMinRange)) ) + EndTracking(); + } +} + +// ----------------------------------------------------------------------- + +void ScrollBar::KeyInput( const KeyEvent& rKEvt ) +{ + if ( !rKEvt.GetKeyCode().GetModifier() ) + { + switch ( rKEvt.GetKeyCode().GetCode() ) + { + case KEY_HOME: + DoScroll( 0 ); + break; + + case KEY_END: + DoScroll( GetRangeMax() ); + break; + + case KEY_LEFT: + case KEY_UP: + DoScrollAction( SCROLL_LINEUP ); + break; + + case KEY_RIGHT: + case KEY_DOWN: + DoScrollAction( SCROLL_LINEDOWN ); + break; + + case KEY_PAGEUP: + DoScrollAction( SCROLL_PAGEUP ); + break; + + case KEY_PAGEDOWN: + DoScrollAction( SCROLL_PAGEDOWN ); + break; + + default: + Control::KeyInput( rKEvt ); + break; + } + } + else + Control::KeyInput( rKEvt ); +} + +// ----------------------------------------------------------------------- + +void ScrollBar::Paint( const Rectangle& ) +{ + ImplDraw( SCRBAR_DRAW_ALL, this ); +} + +// ----------------------------------------------------------------------- + +void ScrollBar::Resize() +{ + Control::Resize(); + mbCalcSize = TRUE; + if ( IsReallyVisible() ) + ImplCalc( FALSE ); + Invalidate(); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( ScrollBar, ImplAutoTimerHdl, AutoTimer*, EMPTYARG ) +{ + if( mpData && mpData->mbHide ) + return 0; + ImplInvert(); + return 0; +} + +void ScrollBar::ImplInvert() +{ + Rectangle aRect( maThumbRect ); + if( aRect.getWidth() > 4 ) + { + aRect.Left() += 2; + aRect.Right() -= 2; + } + if( aRect.getHeight() > 4 ) + { + aRect.Top() += 2; + aRect.Bottom() -= 2; + } + + Invert( aRect, 0 ); +} + +// ----------------------------------------------------------------------- + +void ScrollBar::GetFocus() +{ + if( !mpData ) + { + mpData = new ImplScrollBarData; + mpData->maTimer.SetTimeoutHdl( LINK( this, ScrollBar, ImplAutoTimerHdl ) ); + mpData->mbHide = FALSE; + } + ImplInvert(); // react immediately + mpData->maTimer.SetTimeout( GetSettings().GetStyleSettings().GetCursorBlinkTime() ); + mpData->maTimer.Start(); + Control::GetFocus(); +} + +// ----------------------------------------------------------------------- + +void ScrollBar::LoseFocus() +{ + if( mpData ) + mpData->maTimer.Stop(); + ImplDraw( SCRBAR_DRAW_THUMB, this ); + + Control::LoseFocus(); +} + +// ----------------------------------------------------------------------- + +void ScrollBar::StateChanged( StateChangedType nType ) +{ + Control::StateChanged( nType ); + + if ( nType == STATE_CHANGE_INITSHOW ) + ImplCalc( FALSE ); + else if ( nType == STATE_CHANGE_DATA ) + { + if ( IsReallyVisible() && IsUpdateMode() ) + ImplCalc( TRUE ); + } + else if ( nType == STATE_CHANGE_UPDATEMODE ) + { + if ( IsReallyVisible() && IsUpdateMode() ) + { + ImplCalc( FALSE ); + Invalidate(); + } + } + else if ( nType == STATE_CHANGE_ENABLE ) + { + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + } + else if ( nType == STATE_CHANGE_STYLE ) + { + ImplInitStyle( GetStyle() ); + if ( IsReallyVisible() && IsUpdateMode() ) + { + if ( (GetPrevStyle() & SCRBAR_VIEW_STYLE) != + (GetStyle() & SCRBAR_VIEW_STYLE) ) + { + mbCalcSize = TRUE; + ImplCalc( FALSE ); + Invalidate(); + } + } + } +} + +// ----------------------------------------------------------------------- + +void ScrollBar::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Control::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + mbCalcSize = TRUE; + ImplCalc( FALSE ); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +Rectangle* ScrollBar::ImplFindPartRect( const Point& rPt ) +{ + BOOL bHorizontal = ( GetStyle() & WB_HORZ )? TRUE: FALSE; + BOOL bIsInside = FALSE; + + Point aPoint( 0, 0 ); + Rectangle aControlRegion( aPoint, GetOutputSizePixel() ); + + if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_LEFT: PART_BUTTON_UP, + aControlRegion, rPt, bIsInside )? + bIsInside: + maBtn1Rect.IsInside( rPt ) ) + return &maBtn1Rect; + else if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_RIGHT: PART_BUTTON_DOWN, + aControlRegion, rPt, bIsInside )? + bIsInside: + maBtn2Rect.IsInside( rPt ) ) + return &maBtn2Rect; + // HitTestNativeControl, see remark at top of file + else if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal ? PART_TRACK_HORZ_LEFT : PART_TRACK_VERT_UPPER, + maPage1Rect, rPt, bIsInside)? + bIsInside: + maPage1Rect.IsInside( rPt ) ) + return &maPage1Rect; + // HitTestNativeControl, see remark at top of file + else if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal ? PART_TRACK_HORZ_RIGHT : PART_TRACK_VERT_LOWER, + maPage2Rect, rPt, bIsInside)? + bIsInside: + maPage2Rect.IsInside( rPt ) ) + return &maPage2Rect; + // HitTestNativeControl, see remark at top of file + else if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal ? PART_THUMB_HORZ : PART_THUMB_VERT, + maThumbRect, rPt, bIsInside)? + bIsInside: + maThumbRect.IsInside( rPt ) ) + return &maThumbRect; + else + return NULL; +} + +long ScrollBar::PreNotify( NotifyEvent& rNEvt ) +{ + long nDone = 0; + const MouseEvent* pMouseEvt = NULL; + + if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL ) + { + if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() ) + { + // trigger redraw if mouse over state has changed + if( IsNativeControlSupported(CTRL_SCROLLBAR, PART_ENTIRE_CONTROL) ) + { + Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() ); + Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() ); + if( pRect != pLastRect || pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow() ) + { + Region aRgn( GetActiveClipRegion() ); + Region aClipRegion; + + if ( pRect ) + aClipRegion.Union( *pRect ); + if ( pLastRect ) + aClipRegion.Union( *pLastRect ); + + // Support for 3-button scroll bars + BOOL bHas3Buttons = IsNativeControlSupported( CTRL_SCROLLBAR, HAS_THREE_BUTTONS ); + if ( bHas3Buttons && ( pRect == &maBtn1Rect || pLastRect == &maBtn1Rect ) ) + { + aClipRegion.Union( maBtn2Rect ); + } + + SetClipRegion( aClipRegion ); + Paint( aClipRegion.GetBoundRect() ); + + SetClipRegion( aRgn ); + } + } + } + } + + return nDone ? nDone : Control::PreNotify(rNEvt); +} + +// ----------------------------------------------------------------------- + +void ScrollBar::Scroll() +{ + ImplCallEventListenersAndHandler( VCLEVENT_SCROLLBAR_SCROLL, maScrollHdl, this ); +} + +// ----------------------------------------------------------------------- + +void ScrollBar::EndScroll() +{ + ImplCallEventListenersAndHandler( VCLEVENT_SCROLLBAR_ENDSCROLL, maEndScrollHdl, this ); +} + +// ----------------------------------------------------------------------- + +long ScrollBar::DoScroll( long nNewPos ) +{ + if ( meScrollType != SCROLL_DONTKNOW ) + return 0; + + meScrollType = SCROLL_DRAG; + long nDelta = ImplScroll( nNewPos, TRUE ); + meScrollType = SCROLL_DONTKNOW; + return nDelta; +} + +// ----------------------------------------------------------------------- + +long ScrollBar::DoScrollAction( ScrollType eScrollType ) +{ + if ( (meScrollType != SCROLL_DONTKNOW) || + (eScrollType == SCROLL_DONTKNOW) || + (eScrollType == SCROLL_DRAG) ) + return 0; + + meScrollType = eScrollType; + long nDelta = ImplDoAction( TRUE ); + meScrollType = SCROLL_DONTKNOW; + return nDelta; +} + +// ----------------------------------------------------------------------- + +void ScrollBar::SetRangeMin( long nNewRange ) +{ + SetRange( Range( nNewRange, GetRangeMax() ) ); +} + +// ----------------------------------------------------------------------- + +void ScrollBar::SetRangeMax( long nNewRange ) +{ + SetRange( Range( GetRangeMin(), nNewRange ) ); +} + +// ----------------------------------------------------------------------- + +void ScrollBar::SetRange( const Range& rRange ) +{ + // Range einpassen + Range aRange = rRange; + aRange.Justify(); + long nNewMinRange = aRange.Min(); + long nNewMaxRange = aRange.Max(); + + // Wenn Range sich unterscheidet, dann neuen setzen + if ( (mnMinRange != nNewMinRange) || + (mnMaxRange != nNewMaxRange) ) + { + mnMinRange = nNewMinRange; + mnMaxRange = nNewMaxRange; + + // Thumb einpassen + if ( mnThumbPos > mnMaxRange-mnVisibleSize ) + mnThumbPos = mnMaxRange-mnVisibleSize; + if ( mnThumbPos < mnMinRange ) + mnThumbPos = mnMinRange; + + StateChanged( STATE_CHANGE_DATA ); + } +} + +// ----------------------------------------------------------------------- + +void ScrollBar::SetThumbPos( long nNewThumbPos ) +{ + if ( nNewThumbPos > mnMaxRange-mnVisibleSize ) + nNewThumbPos = mnMaxRange-mnVisibleSize; + if ( nNewThumbPos < mnMinRange ) + nNewThumbPos = mnMinRange; + + if ( mnThumbPos != nNewThumbPos ) + { + mnThumbPos = nNewThumbPos; + StateChanged( STATE_CHANGE_DATA ); + } +} + +// ----------------------------------------------------------------------- + +void ScrollBar::SetVisibleSize( long nNewSize ) +{ + if ( mnVisibleSize != nNewSize ) + { + mnVisibleSize = nNewSize; + + // Thumb einpassen + if ( mnThumbPos > mnMaxRange-mnVisibleSize ) + mnThumbPos = mnMaxRange-mnVisibleSize; + if ( mnThumbPos < mnMinRange ) + mnThumbPos = mnMinRange; + StateChanged( STATE_CHANGE_DATA ); + } +} + +// ======================================================================= + +void ScrollBarBox::ImplInit( Window* pParent, WinBits nStyle ) +{ + Window::ImplInit( pParent, nStyle, NULL ); + + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + long nScrollSize = rStyleSettings.GetScrollBarSize(); + SetSizePixel( Size( nScrollSize, nScrollSize ) ); + ImplInitSettings(); +} + +// ----------------------------------------------------------------------- + +ScrollBarBox::ScrollBarBox( Window* pParent, WinBits nStyle ) : + Window( WINDOW_SCROLLBARBOX ) +{ + ImplInit( pParent, nStyle ); +} + +// ----------------------------------------------------------------------- + +ScrollBarBox::ScrollBarBox( Window* pParent, const ResId& rResId ) : + Window( WINDOW_SCROLLBARBOX ) +{ + rResId.SetRT( RSC_SCROLLBAR ); + ImplInit( pParent, ImplInitRes( rResId ) ); + ImplLoadRes( rResId ); +} + +// ----------------------------------------------------------------------- + +void ScrollBarBox::ImplInitSettings() +{ + // Hack, damit man auch DockingWindows ohne Hintergrund bauen kann + // und noch nicht alles umgestellt ist + if ( IsBackground() ) + { + Color aColor; + if ( IsControlBackground() ) + aColor = GetControlBackground(); + else + aColor = GetSettings().GetStyleSettings().GetFaceColor(); + SetBackground( aColor ); + } +} + +// ----------------------------------------------------------------------- + +void ScrollBarBox::StateChanged( StateChangedType nType ) +{ + Window::StateChanged( nType ); + + if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings(); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void ScrollBarBox::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + ImplInitSettings(); + Invalidate(); + } +} |