/* -*- 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 <vcl/event.hxx>
#include <vcl/decoview.hxx>
#include <vcl/timer.hxx>
#include <vcl/settings.hxx>
#include <vcl/toolkit/scrbar.hxx>
#include <vcl/vclevent.hxx>
#include <sal/log.hxx>
/* #i77549#
HACK: for scrollbars in case of thumb rect, page up and page down rect we
abuse the HitTestNativeScrollbar interface. All theming engines but macOS
are actually able to draw the thumb according to our internal representation.
However macOS draws a little outside. The canonical way would be to enhance the
HitTestNativeScrollbar 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 HitTestNativeScrollbar on ControlPart::ThumbHorz, ControlPart::ThumbVert,
ControlPart::TrackHorzLeft, ControlPart::TrackHorzRight, ControlPart::TrackVertUpper, ControlPart::TrackVertLower
do not use the control rectangle as region but the actual part rectangle, making
only small deviations feasible.
*/
#include "thumbpos.hxx"
#define SCRBAR_DRAW_BTN1 (sal_uInt16(0x0001))
#define SCRBAR_DRAW_BTN2 (sal_uInt16(0x0002))
#define SCRBAR_DRAW_PAGE1 (sal_uInt16(0x0004))
#define SCRBAR_DRAW_PAGE2 (sal_uInt16(0x0008))
#define SCRBAR_DRAW_THUMB (sal_uInt16(0x0010))
#define SCRBAR_DRAW_BACKGROUND (sal_uInt16(0x0020))
#define SCRBAR_STATE_BTN1_DOWN (sal_uInt16(0x0001))
#define SCRBAR_STATE_BTN1_DISABLE (sal_uInt16(0x0002))
#define SCRBAR_STATE_BTN2_DOWN (sal_uInt16(0x0004))
#define SCRBAR_STATE_BTN2_DISABLE (sal_uInt16(0x0008))
#define SCRBAR_STATE_PAGE1_DOWN (sal_uInt16(0x0010))
#define SCRBAR_STATE_PAGE2_DOWN (sal_uInt16(0x0020))
#define SCRBAR_STATE_THUMB_DOWN (sal_uInt16(0x0040))
#define SCRBAR_VIEW_STYLE (WB_3DLOOK | WB_HORZ | WB_VERT)
struct ImplScrollBarData
{
AutoTimer maTimer { "vcl::ScrollBar mpData->maTimer" };
bool mbHide;
};
void ScrollBar::ImplInit( vcl::Window* pParent, WinBits nStyle )
{
mpData = nullptr;
mnThumbPixRange = 0;
mnThumbPixPos = 0;
mnThumbPixSize = 0;
mnMinRange = 0;
mnMaxRange = 100;
mnThumbPos = 0;
mnVisibleSize = 0;
mnLineSize = 1;
mnPageSize = 1;
mnDelta = 0;
mnStateFlags = 0;
meScrollType = ScrollType::DontKnow;
mbCalcSize = true;
mbFullDrag = false;
mbSwapArrows = false;
ImplInitStyle( nStyle );
Control::ImplInit( pParent, nStyle, nullptr );
tools::Long nScrollSize = GetSettings().GetStyleSettings().GetScrollBarSize();
SetSizePixel( Size( nScrollSize, nScrollSize ) );
}
void ScrollBar::ImplInitStyle( WinBits nStyle )
{
if ( nStyle & WB_DRAG )
mbFullDrag = true;
else
mbFullDrag = bool(GetSettings().GetStyleSettings().GetDragFullOptions() & DragFullOptions::Scroll);
}
ScrollBar::ScrollBar( vcl::Window* pParent, WinBits nStyle ) :
Control( WindowType::SCROLLBAR )
{
ImplInit( pParent, nStyle );
}
ScrollBar::~ScrollBar()
{
disposeOnce();
}
void ScrollBar::dispose()
{
mpData.reset();
Control::dispose();
}
void ScrollBar::ImplUpdateRects( bool bUpdate )
{
mnStateFlags &= ~SCRBAR_STATE_BTN1_DISABLE;
mnStateFlags &= ~SCRBAR_STATE_BTN2_DISABLE;
if ( mnThumbPixRange )
{
if ( GetStyle() & WB_HORZ )
{
maThumbRect.SetLeft( maTrackRect.Left()+mnThumbPixPos );
maThumbRect.SetRight( maThumbRect.Left()+mnThumbPixSize-1 );
if ( !mnThumbPixPos )
maPage1Rect.SetWidthEmpty();
else
maPage1Rect.SetRight( maThumbRect.Left()-1 );
if ( mnThumbPixPos >= (mnThumbPixRange-mnThumbPixSize) )
maPage2Rect.SetWidthEmpty();
else
{
maPage2Rect.SetLeft( maThumbRect.Right()+1 );
maPage2Rect.SetRight( maTrackRect.Right() );
}
}
else
{
maThumbRect.SetTop( maTrackRect.Top()+mnThumbPixPos );
maThumbRect.SetBottom( maThumbRect.Top()+mnThumbPixSize-1 );
if ( !mnThumbPixPos )
maPage1Rect.SetHeightEmpty();
else
maPage1Rect.SetBottom( maThumbRect.Top()-1 );
if ( mnThumbPixPos >= (mnThumbPixRange-mnThumbPixSize) )
maPage2Rect.SetHeightEmpty();
else
{
maPage2Rect.SetTop( maThumbRect.Bottom()+1 );
maPage2Rect.SetBottom( maTrackRect.Bottom() );
}
}
}
else
{
if ( GetStyle() & WB_HORZ )
{
const tools::Long nSpace = maTrackRect.Right() - maTrackRect.Left();
if ( nSpace > 0 )
{
maPage1Rect.SetLeft( maTrackRect.Left() );
maPage1Rect.SetRight( maTrackRect.Left() + (nSpace/2) );
maPage2Rect.SetLeft( maPage1Rect.Right() + 1 );
maPage2Rect.SetRight( maTrackRect.Right() );
}
}
else
{
const tools::Long nSpace = maTrackRect.Bottom() - maTrackRect.Top();
if ( nSpace > 0 )
{
maPage1Rect.SetTop( maTrackRect.Top() );
maPage1Rect.SetBottom( maTrackRect.Top() + (nSpace/2) );
maPage2Rect.SetTop( maPage1Rect.Bottom() + 1 );
maPage2Rect.SetBottom( maTrackRect.Bottom() );
}
}
}
if( !IsNativeControlSupported(ControlType::Scrollbar, ControlPart::Entire) )
{
// 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 )
{
Invalidate();
}
}
tools::Long ScrollBar::ImplCalcThumbPos( tools::Long nPixPos ) const
{
// Calculate position
tools::Long nCalcThumbPos;
nCalcThumbPos = ImplMulDiv( nPixPos, mnMaxRange-mnVisibleSize-mnMinRange,
mnThumbPixRange-mnThumbPixSize );
nCalcThumbPos += mnMinRange;
return nCalcThumbPos;
}
tools::Long ScrollBar::ImplCalcThumbPosPix( tools::Long nPos ) const
{
tools::Long nCalcThumbPos;
// Calculate position
nCalcThumbPos = ImplMulDiv( nPos-mnMinRange, mnThumbPixRange-mnThumbPixSize,
mnMaxRange-mnVisibleSize-mnMinRange );
// At the start and end of the ScrollBar, we try to show the display correctly
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 tools::Long nMinThumbSize = GetSettings().GetStyleSettings().GetMinThumbSize();
if ( mbCalcSize )
{
Size aOldSize = getCurrentCalcSize();
const tools::Rectangle aControlRegion( Point(0,0), aSize );
tools::Rectangle aBtn1Region, aBtn2Region, aTrackRegion, aBoundingRegion;
const bool bSwapArrows = mbSwapArrows || IsRTLEnabled();
// reset rectangles to empty *and* (0,0) position
maThumbRect = tools::Rectangle();
maPage1Rect = tools::Rectangle();
maPage2Rect = tools::Rectangle();
if ( GetStyle() & WB_HORZ )
{
if ( GetNativeControlRegion( ControlType::Scrollbar, bSwapArrows? ControlPart::ButtonRight: ControlPart::ButtonLeft,
aControlRegion, ControlState::NONE, ImplControlValue(), aBoundingRegion, aBtn1Region ) &&
GetNativeControlRegion( ControlType::Scrollbar, bSwapArrows? ControlPart::ButtonLeft: ControlPart::ButtonRight,
aControlRegion, ControlState::NONE, ImplControlValue(), aBoundingRegion, aBtn2Region ) )
{
maBtn1Rect = aBtn1Region;
maBtn2Rect = aBtn2Region;
}
else
{
Size aBtnSize( aSize.Height(), aSize.Height() );
maBtn2Rect.SetTop( maBtn1Rect.Top() );
maBtn2Rect.SetLeft( aSize.Width()-aSize.Height() );
maBtn1Rect.SetSize( aBtnSize );
maBtn2Rect.SetSize( aBtnSize );
}
if ( GetNativeControlRegion( ControlType::Scrollbar, ControlPart::TrackHorzArea,
aControlRegion, ControlState::NONE, ImplControlValue(), aBoundingRegion, aTrackRegion ) )
maTrackRect = aTrackRegion;
else
maTrackRect = tools::Rectangle::Normalize( 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.SetLeft( maTrackRect.Left() );
maPage1Rect.SetBottom( maTrackRect.Bottom() );
maPage2Rect.SetBottom (maTrackRect.Bottom() );
maThumbRect.SetBottom( maTrackRect.Bottom() );
}
else
mnThumbPixRange = 0;
}
else // WB_VERT
{
if ( GetNativeControlRegion( ControlType::Scrollbar, ControlPart::ButtonUp,
aControlRegion, ControlState::NONE, ImplControlValue(), aBoundingRegion, aBtn1Region ) &&
GetNativeControlRegion( ControlType::Scrollbar, ControlPart::ButtonDown,
aControlRegion, ControlState::NONE, ImplControlValue(), aBoundingRegion, aBtn2Region ) )
{
maBtn1Rect = aBtn1Region;
maBtn2Rect = aBtn2Region;
}
else
{
const Size aBtnSize( aSize.Width(), aSize.Width() );
maBtn2Rect.SetLeft( maBtn1Rect.Left() );
maBtn2Rect.SetTop( aSize.Height()-aSize.Width() );
maBtn1Rect.SetSize( aBtnSize );
maBtn2Rect.SetSize( aBtnSize );
}
if ( GetNativeControlRegion( ControlType::Scrollbar, ControlPart::TrackVertArea,
aControlRegion, ControlState::NONE, ImplControlValue(), aBoundingRegion, aTrackRegion ) )
maTrackRect = aTrackRegion;
else
maTrackRect = tools::Rectangle::Normalize( 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.SetTop( maTrackRect.Top() );
maPage1Rect.SetRight( maTrackRect.Right() );
maPage2Rect.SetRight( maTrackRect.Right() );
maThumbRect.SetRight( maTrackRect.Right() );
}
else
mnThumbPixRange = 0;
}
mbCalcSize = false;
Size aNewSize = getCurrentCalcSize();
if (aOldSize != aNewSize)
{
queue_resize();
}
}
if ( mnThumbPixRange )
{
// Calculate values
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 );
}
}
// If we're ought to output again and we have been triggered
// a Paint event via an Action, we don't output directly,
// but invalidate everything
if ( bUpdate && HasPaintEvent() )
{
Invalidate();
bUpdate = false;
}
ImplUpdateRects( bUpdate );
}
void ScrollBar::Draw( OutputDevice* pDev, const Point& rPos, SystemTextColorFlags nFlags )
{
Point aPos = pDev->LogicToPixel( rPos );
pDev->Push();
pDev->SetMapMode();
if ( !(nFlags & SystemTextColorFlags::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;
maTrackRect+=aPos;
maPage1Rect+=aPos;
maPage2Rect+=aPos;
ImplDraw(*pDev);
pDev->Pop();
mbCalcSize = true;
}
bool ScrollBar::ImplDrawNative(vcl::RenderContext& rRenderContext, sal_uInt16 nSystemTextColorFlags)
{
ScrollbarValue scrValue;
bool bNativeOK = rRenderContext.IsNativeControlSupported(ControlType::Scrollbar, ControlPart::Entire);
if (!bNativeOK)
return false;
bool bHorz = (GetStyle() & WB_HORZ) != 0;
// Draw the entire background if the control supports it
if (rRenderContext.IsNativeControlSupported(ControlType::Scrollbar, bHorz ? ControlPart::DrawBackgroundHorz : ControlPart::DrawBackgroundVert))
{
ControlState nState = (IsEnabled() ? ControlState::ENABLED : ControlState::NONE)
| (HasFocus() ? ControlState::FOCUSED : ControlState::NONE);
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) ? ControlState::PRESSED : ControlState::NONE) |
((!(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE)) ? ControlState::ENABLED : ControlState::NONE);
scrValue.mnButton2State = ((mnStateFlags & SCRBAR_STATE_BTN2_DOWN) ? ControlState::PRESSED : ControlState::NONE) |
((!(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE)) ? ControlState::ENABLED : ControlState::NONE);
scrValue.mnThumbState = nState | ((mnStateFlags & SCRBAR_STATE_THUMB_DOWN) ? ControlState::PRESSED : ControlState::NONE);
if (IsMouseOver())
{
tools::Rectangle* pRect = ImplFindPartRect(GetPointerPosPixel());
if (pRect)
{
if (pRect == &maThumbRect)
scrValue.mnThumbState |= ControlState::ROLLOVER;
else if (pRect == &maBtn1Rect)
scrValue.mnButton1State |= ControlState::ROLLOVER;
else if (pRect == &maBtn2Rect)
scrValue.mnButton2State |= ControlState::ROLLOVER;
}
}
tools::Rectangle aCtrlRegion;
aCtrlRegion.Union(maBtn1Rect);
aCtrlRegion.Union(maBtn2Rect);
aCtrlRegion.Union(maPage1Rect);
aCtrlRegion.Union(maPage2Rect);
aCtrlRegion.Union(maThumbRect);
tools::Rectangle aRequestedRegion(Point(0,0), GetOutputSizePixel());
// if the actual native control region is smaller then the region that
// we requested the control to draw in, then draw a background rectangle
// to avoid drawing artifacts in the uncovered region
if (aCtrlRegion.GetWidth() < aRequestedRegion.GetWidth() ||
aCtrlRegion.GetHeight() < aRequestedRegion.GetHeight())
{
Color aFaceColor = rRenderContext.GetSettings().GetStyleSettings().GetFaceColor();
rRenderContext.SetFillColor(aFaceColor);
rRenderContext.SetLineColor(aFaceColor);
rRenderContext.DrawRect(aRequestedRegion);
}
bNativeOK = rRenderContext.DrawNativeControl(ControlType::Scrollbar, (bHorz ? ControlPart::DrawBackgroundHorz : ControlPart::DrawBackgroundVert),
aCtrlRegion, nState, scrValue, OUString());
}
else
{
if ((nSystemTextColorFlags & SCRBAR_DRAW_PAGE1) || (nSystemTextColorFlags & SCRBAR_DRAW_PAGE2))
{
ControlPart part1 = bHorz ? ControlPart::TrackHorzLeft : ControlPart::TrackVertUpper;
ControlPart part2 = bHorz ? ControlPart::TrackHorzRight : ControlPart::TrackVertLower;
tools::Rectangle aCtrlRegion1(maPage1Rect);
tools::Rectangle aCtrlRegion2(maPage2Rect);
ControlState nState1 = (IsEnabled() ? ControlState::ENABLED : ControlState::NONE)
| (HasFocus() ? ControlState::FOCUSED : ControlState::NONE);
ControlState nState2 = nState1;
nState1 |= ((mnStateFlags & SCRBAR_STATE_PAGE1_DOWN) ? ControlState::PRESSED : ControlState::NONE);
nState2 |= ((mnStateFlags & SCRBAR_STATE_PAGE2_DOWN) ? ControlState::PRESSED : ControlState::NONE);
if (IsMouseOver())
{
tools::Rectangle* pRect = ImplFindPartRect(GetPointerPosPixel());
if (pRect)
{
if (pRect == &maPage1Rect)
nState1 |= ControlState::ROLLOVER;
else if (pRect == &maPage2Rect)
nState2 |= ControlState::ROLLOVER;
}
}
if (nSystemTextColorFlags & SCRBAR_DRAW_PAGE1)
bNativeOK = rRenderContext.DrawNativeControl(ControlType::Scrollbar, part1, aCtrlRegion1, nState1, scrValue, OUString());
if (nSystemTextColorFlags & SCRBAR_DRAW_PAGE2)
bNativeOK = rRenderContext.DrawNativeControl(ControlType::Scrollbar, part2, aCtrlRegion2, nState2, scrValue, OUString());
}
if ((nSystemTextColorFlags & SCRBAR_DRAW_BTN1) || (nSystemTextColorFlags & SCRBAR_DRAW_BTN2))
{
ControlPart part1 = bHorz ? ControlPart::ButtonLeft : ControlPart::ButtonUp;
ControlPart part2 = bHorz ? ControlPart::ButtonRight : ControlPart::ButtonDown;
tools::Rectangle aCtrlRegion1(maBtn1Rect);
tools::Rectangle aCtrlRegion2(maBtn2Rect);
ControlState nState1 = HasFocus() ? ControlState::FOCUSED : ControlState::NONE;
ControlState nState2 = nState1;
if (!Window::IsEnabled() || !IsEnabled())
nState1 = (nState2 &= ~ControlState::ENABLED);
else
nState1 = (nState2 |= ControlState::ENABLED);
nState1 |= ((mnStateFlags & SCRBAR_STATE_BTN1_DOWN) ? ControlState::PRESSED : ControlState::NONE);
nState2 |= ((mnStateFlags & SCRBAR_STATE_BTN2_DOWN) ? ControlState::PRESSED : ControlState::NONE);
if (mnStateFlags & SCRBAR_STATE_BTN1_DISABLE)
nState1 &= ~ControlState::ENABLED;
if (mnStateFlags & SCRBAR_STATE_BTN2_DISABLE)
nState2 &= ~ControlState::ENABLED;
if (IsMouseOver())
{
tools::Rectangle* pRect = ImplFindPartRect(GetPointerPosPixel());
if (pRect)
{
if (pRect == &maBtn1Rect)
nState1 |= ControlState::ROLLOVER;
else if (pRect == &maBtn2Rect)
nState2 |= ControlState::ROLLOVER;
}
}
if (nSystemTextColorFlags & SCRBAR_DRAW_BTN1)
bNativeOK = rRenderContext.DrawNativeControl(ControlType::Scrollbar, part1, aCtrlRegion1, nState1, scrValue, OUString());
if (nSystemTextColorFlags & SCRBAR_DRAW_BTN2)
bNativeOK = rRenderContext.DrawNativeControl(ControlType::Scrollbar, part2, aCtrlRegion2, nState2, scrValue, OUString());
}
if ((nSystemTextColorFlags & SCRBAR_DRAW_THUMB) && !maThumbRect.IsEmpty())
{
ControlState nState = IsEnabled() ? ControlState::ENABLED : ControlState::NONE;
tools::Rectangle aCtrlRegion(maThumbRect);
if (mnStateFlags & SCRBAR_STATE_THUMB_DOWN)
nState |= ControlState::PRESSED;
if (HasFocus())
nState |= ControlState::FOCUSED;
if (IsMouseOver())
{
tools::Rectangle* pRect = ImplFindPartRect(GetPointerPosPixel());
if (pRect && pRect == &maThumbRect)
nState |= ControlState::ROLLOVER;
}
bNativeOK = rRenderContext.DrawNativeControl(ControlType::Scrollbar, (bHorz ? ControlPart::ThumbHorz : ControlPart::ThumbVert),
aCtrlRegion, nState, scrValue, OUString());
}
}
return bNativeOK;
}
void ScrollBar::ImplDraw(vcl::RenderContext& rRenderContext)
{
DecorationView aDecoView(&rRenderContext);
tools::Rectangle aTempRect;
DrawButtonFlags nStyle;
const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
SymbolType eSymbolType;
bool bEnabled = IsEnabled();
// Finish some open calculations (if any)
if (mbCalcSize)
ImplCalc(false);
//vcl::Window *pWin = NULL;
//if (rRenderContext.GetOutDevType() == OUTDEV_WINDOW)
// pWin = static_cast<vcl::Window*>(&rRenderContext);
// Draw the entire control if the native theme engine needs it
if (rRenderContext.IsNativeControlSupported(ControlType::Scrollbar, ControlPart::DrawBackgroundHorz))
{
ImplDrawNative(rRenderContext, SCRBAR_DRAW_BACKGROUND);
return;
}
if (!ImplDrawNative(rRenderContext, SCRBAR_DRAW_BTN1))
{
nStyle = DrawButtonFlags::NoLightBorder;
if (mnStateFlags & SCRBAR_STATE_BTN1_DOWN)
nStyle |= DrawButtonFlags::Pressed;
aTempRect = aDecoView.DrawButton( PixelToLogic(maBtn1Rect), nStyle );
ImplCalcSymbolRect( aTempRect );
DrawSymbolFlags nSymbolStyle = DrawSymbolFlags::NONE;
if ((mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) || !bEnabled)
nSymbolStyle |= DrawSymbolFlags::Disable;
if (GetStyle() & WB_HORZ)
eSymbolType = SymbolType::SPIN_LEFT;
else
eSymbolType = SymbolType::SPIN_UP;
aDecoView.DrawSymbol(aTempRect, eSymbolType, rStyleSettings.GetButtonTextColor(), nSymbolStyle);
}
if (!ImplDrawNative(rRenderContext, SCRBAR_DRAW_BTN2))
{
nStyle = DrawButtonFlags::NoLightBorder;
if (mnStateFlags & SCRBAR_STATE_BTN2_DOWN)
nStyle |= DrawButtonFlags::Pressed;
aTempRect = aDecoView.DrawButton(PixelToLogic(maBtn2Rect), nStyle);
ImplCalcSymbolRect(aTempRect);
DrawSymbolFlags nSymbolStyle = DrawSymbolFlags::NONE;
if ((mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) || !bEnabled)
nSymbolStyle |= DrawSymbolFlags::Disable;
if (GetStyle() & WB_HORZ)
eSymbolType = SymbolType::SPIN_RIGHT;
else
eSymbolType = SymbolType::SPIN_DOWN;
aDecoView.DrawSymbol(aTempRect, eSymbolType, rStyleSettings.GetButtonTextColor(), nSymbolStyle);
}
rRenderContext.SetLineColor();
if (!ImplDrawNative(rRenderContext, SCRBAR_DRAW_THUMB))
{
if (!maThumbRect.IsEmpty())
{
if (bEnabled)
{
nStyle = DrawButtonFlags::NoLightBorder;
aTempRect = aDecoView.DrawButton(PixelToLogic(maThumbRect), nStyle);
}
else
{
rRenderContext.SetFillColor(rStyleSettings.GetCheckedColor());
rRenderContext.DrawRect(PixelToLogic(maThumbRect));
}
}
}
if (!ImplDrawNative(rRenderContext, SCRBAR_DRAW_PAGE1))
{
if (mnStateFlags & SCRBAR_STATE_PAGE1_DOWN)
rRenderContext.SetFillColor(rStyleSettings.GetShadowColor());
else
rRenderContext.SetFillColor(rStyleSettings.GetCheckedColor());
rRenderContext.DrawRect(PixelToLogic(maPage1Rect));
}
if (!ImplDrawNative(rRenderContext, SCRBAR_DRAW_PAGE2))
{
if (mnStateFlags & SCRBAR_STATE_PAGE2_DOWN)
rRenderContext.SetFillColor(rStyleSettings.GetShadowColor());
else
rRenderContext.SetFillColor(rStyleSettings.GetCheckedColor());
rRenderContext.DrawRect(PixelToLogic(maPage2Rect));
}
}
tools::Long ScrollBar::ImplScroll( tools::Long nNewPos, bool bCallEndScroll )
{
tools::Long nOldPos = mnThumbPos;
SetThumbPos( nNewPos );
tools::Long nDelta = mnThumbPos-nOldPos;
if ( nDelta )
{
mnDelta = nDelta;
Scroll();
if ( bCallEndScroll )
EndScroll();
mnDelta = 0;
}
return nDelta;
}
tools::Long ScrollBar::ImplDoAction( bool bCallEndScroll )
{
tools::Long nDelta = 0;
switch ( meScrollType )
{
case ScrollType::LineUp:
nDelta = ImplScroll( mnThumbPos-mnLineSize, bCallEndScroll );
break;
case ScrollType::LineDown:
nDelta = ImplScroll( mnThumbPos+mnLineSize, bCallEndScroll );
break;
case ScrollType::PageUp:
nDelta = ImplScroll( mnThumbPos-mnPageSize, bCallEndScroll );
break;
case ScrollType::PageDown:
nDelta = ImplScroll( mnThumbPos+mnPageSize, bCallEndScroll );
break;
default:
;
}
return nDelta;
}
void ScrollBar::ImplDoMouseAction( const Point& rMousePos, bool bCallAction )
{
sal_uInt16 nOldStateFlags = mnStateFlags;
bool bAction = false;
bool bHorizontal = ( GetStyle() & WB_HORZ ) != 0;
bool bIsInside = false;
Point aPoint( 0, 0 );
tools::Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
switch ( meScrollType )
{
case ScrollType::LineUp:
if ( GetOutDev()->HitTestNativeScrollbar( bHorizontal? (IsRTLEnabled()? ControlPart::ButtonRight: ControlPart::ButtonLeft): ControlPart::ButtonUp,
aControlRegion, rMousePos, bIsInside )?
bIsInside:
maBtn1Rect.Contains( rMousePos ) )
{
bAction = bCallAction;
mnStateFlags |= SCRBAR_STATE_BTN1_DOWN;
}
else
mnStateFlags &= ~SCRBAR_STATE_BTN1_DOWN;
break;
case ScrollType::LineDown:
if ( GetOutDev()->HitTestNativeScrollbar( bHorizontal? (IsRTLEnabled()? ControlPart::ButtonLeft: ControlPart::ButtonRight): ControlPart::ButtonDown,
aControlRegion, rMousePos, bIsInside )?
bIsInside:
maBtn2Rect.Contains( rMousePos ) )
{
bAction = bCallAction;
mnStateFlags |= SCRBAR_STATE_BTN2_DOWN;
}
else
mnStateFlags &= ~SCRBAR_STATE_BTN2_DOWN;
break;
case ScrollType::PageUp:
// HitTestNativeScrollbar, see remark at top of file
if ( GetOutDev()->HitTestNativeScrollbar( bHorizontal? ControlPart::TrackHorzLeft: ControlPart::TrackVertUpper,
maPage1Rect, rMousePos, bIsInside )?
bIsInside:
maPage1Rect.Contains( rMousePos ) )
{
bAction = bCallAction;
mnStateFlags |= SCRBAR_STATE_PAGE1_DOWN;
}
else
mnStateFlags &= ~SCRBAR_STATE_PAGE1_DOWN;
break;
case ScrollType::PageDown:
// HitTestNativeScrollbar, see remark at top of file
if ( GetOutDev()->HitTestNativeScrollbar( bHorizontal? ControlPart::TrackHorzRight: ControlPart::TrackVertLower,
maPage2Rect, rMousePos, bIsInside )?
bIsInside:
maPage2Rect.Contains( rMousePos ) )
{
bAction = bCallAction;
mnStateFlags |= SCRBAR_STATE_PAGE2_DOWN;
}
else
mnStateFlags &= ~SCRBAR_STATE_PAGE2_DOWN;
break;
default:
;
}
if ( nOldStateFlags != mnStateFlags )
Invalidate();
if ( bAction )
ImplDoAction( false );
}
void ScrollBar::ImplDragThumb( const Point& rMousePos )
{
tools::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 )
return;
mnThumbPixPos += nMovePix;
if ( mnThumbPixPos < 0 )
mnThumbPixPos = 0;
if ( mnThumbPixPos > (mnThumbPixRange-mnThumbPixSize) )
mnThumbPixPos = mnThumbPixRange-mnThumbPixSize;
tools::Long nOldPos = mnThumbPos;
mnThumbPos = ImplCalcThumbPos( mnThumbPixPos );
ImplUpdateRects();
if ( !(mbFullDrag && (nOldPos != mnThumbPos)) )
return;
// When dragging in windows the repaint request gets starved so dragging
// the scrollbar feels slower than it actually is. Let's force an immediate
// repaint of the scrollbar.
if (SupportsDoubleBuffering())
{
Invalidate();
PaintImmediately();
}
else
ImplDraw(*GetOutDev());
mnDelta = mnThumbPos-nOldPos;
Scroll();
mnDelta = 0;
}
void ScrollBar::MouseButtonDown( const MouseEvent& rMEvt )
{
bool bPrimaryWarps = GetSettings().GetStyleSettings().GetPrimaryButtonWarpsSlider();
bool bWarp = bPrimaryWarps ? rMEvt.IsLeft() : rMEvt.IsMiddle();
bool bPrimaryWarping = bWarp && rMEvt.IsLeft();
bool bPage = bPrimaryWarps ? rMEvt.IsRight() : rMEvt.IsLeft();
if (!rMEvt.IsLeft() && !rMEvt.IsMiddle() && !rMEvt.IsRight())
return;
Point aPosPixel;
if (!IsMapModeEnabled() && GetMapMode().GetMapUnit() == MapUnit::MapTwip)
{
// rMEvt coordinates are in twips.
GetOutDev()->Push(vcl::PushFlags::MAPMODE);
EnableMapMode();
MapMode aMapMode = GetMapMode();
aMapMode.SetOrigin(Point(0, 0));
SetMapMode(aMapMode);
aPosPixel = LogicToPixel(rMEvt.GetPosPixel());
GetOutDev()->Pop();
}
const Point& rMousePos = (GetMapMode().GetMapUnit() != MapUnit::MapTwip ? rMEvt.GetPosPixel() : aPosPixel);
StartTrackingFlags nTrackFlags = StartTrackingFlags::NONE;
bool bHorizontal = ( GetStyle() & WB_HORZ ) != 0;
bool bIsInside = false;
bool bDragToMouse = false;
Point aPoint( 0, 0 );
tools::Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
if ( GetOutDev()->HitTestNativeScrollbar( bHorizontal? (IsRTLEnabled()? ControlPart::ButtonRight: ControlPart::ButtonLeft): ControlPart::ButtonUp,
aControlRegion, rMousePos, bIsInside )?
bIsInside:
maBtn1Rect.Contains( rMousePos ) )
{
if (rMEvt.IsLeft() && !(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) )
{
nTrackFlags = StartTrackingFlags::ButtonRepeat;
meScrollType = ScrollType::LineUp;
}
}
else if ( GetOutDev()->HitTestNativeScrollbar( bHorizontal? (IsRTLEnabled()? ControlPart::ButtonLeft: ControlPart::ButtonRight): ControlPart::ButtonDown,
aControlRegion, rMousePos, bIsInside )?
bIsInside:
maBtn2Rect.Contains( rMousePos ) )
{
if (rMEvt.IsLeft() && !(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) )
{
nTrackFlags = StartTrackingFlags::ButtonRepeat;
meScrollType = ScrollType::LineDown;
}
}
else
{
bool bThumbHit = GetOutDev()->HitTestNativeScrollbar( bHorizontal? ControlPart::ThumbHorz : ControlPart::ThumbVert,
maThumbRect, rMousePos, bIsInside )
? bIsInside : maThumbRect.Contains( rMousePos );
bool bThumbAction = bWarp || bPage;
bool bDragHandling = bWarp || (bThumbHit && bThumbAction);
if( bDragHandling )
{
if( mpData )
{
mpData->mbHide = true; // disable focus blinking
if (HasFocus())
{
mnStateFlags |= SCRBAR_DRAW_THUMB; // paint without focus
Invalidate();
}
}
if ( mnVisibleSize < mnMaxRange-mnMinRange )
{
nTrackFlags = StartTrackingFlags::NONE;
meScrollType = ScrollType::Drag;
// calculate mouse offset
if (bWarp && (!bThumbHit || !bPrimaryWarping))
{
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;
Invalidate();
}
}
else if(bPage && (!GetOutDev()->HitTestNativeScrollbar( bHorizontal? ControlPart::TrackHorzArea : ControlPart::TrackVertArea,
aControlRegion, rMousePos, bIsInside ) ||
bIsInside) )
{
nTrackFlags = StartTrackingFlags::ButtonRepeat;
// HitTestNativeScrollbar, see remark at top of file
if ( GetOutDev()->HitTestNativeScrollbar( bHorizontal? ControlPart::TrackHorzLeft : ControlPart::TrackVertUpper,
maPage1Rect, rMousePos, bIsInside )?
bIsInside:
maPage1Rect.Contains( rMousePos ) )
{
meScrollType = ScrollType::PageUp;
}
else
{
meScrollType = ScrollType::PageDown;
}
}
}
// Should we start Tracking?
if ( meScrollType == ScrollType::DontKnow )
return;
// store original position for cancel and 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() )
{
// Restore Button and PageRect status
sal_uInt16 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 )
Invalidate();
// Restore the old ThumbPosition when canceled
if ( rTEvt.IsTrackingCanceled() )
{
tools::Long nOldPos = mnThumbPos;
SetThumbPos( mnStartPos );
mnDelta = mnThumbPos-nOldPos;
Scroll();
}
if ( meScrollType == ScrollType::Drag )
{
// On a SCROLLDRAG we recalculate the Thumb, so that it's back to a
// rounded ThumbPosition
ImplCalc();
if ( !mbFullDrag && (mnStartPos != mnThumbPos) )
{
mnDelta = mnThumbPos-mnStartPos;
Scroll();
mnDelta = 0;
}
}
mnDelta = mnThumbPos-mnStartPos;
EndScroll();
mnDelta = 0;
meScrollType = ScrollType::DontKnow;
if( mpData )
mpData->mbHide = false; // re-enable focus blinking
}
else
{
Point aPosPixel;
if (!IsMapModeEnabled() && GetMapMode().GetMapUnit() == MapUnit::MapTwip)
{
// rTEvt coordinates are in twips.
GetOutDev()->Push(vcl::PushFlags::MAPMODE);
EnableMapMode();
MapMode aMapMode = GetMapMode();
aMapMode.SetOrigin(Point(0, 0));
SetMapMode(aMapMode);
aPosPixel = LogicToPixel(rTEvt.GetMouseEvent().GetPosPixel());
GetOutDev()->Pop();
}
const Point rMousePos = (GetMapMode().GetMapUnit() != MapUnit::MapTwip ? rTEvt.GetMouseEvent().GetPosPixel() : aPosPixel);
// Dragging is treated in a special way
if ( meScrollType == ScrollType::Drag )
ImplDragThumb( rMousePos );
else
ImplDoMouseAction( rMousePos, rTEvt.IsTrackingRepeat() );
// If ScrollBar values are translated in a way that there's
// nothing left to track, we cancel here
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( ScrollType::LineUp );
break;
case KEY_RIGHT:
case KEY_DOWN:
DoScrollAction( ScrollType::LineDown );
break;
case KEY_PAGEUP:
DoScrollAction( ScrollType::PageUp );
break;
case KEY_PAGEDOWN:
DoScrollAction( ScrollType::PageDown );
break;
default:
Control::KeyInput( rKEvt );
break;
}
}
else
Control::KeyInput( rKEvt );
}
void ScrollBar::ApplySettings(vcl::RenderContext& rRenderContext)
{
rRenderContext.SetBackground();
}
void ScrollBar::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
{
ImplDraw(rRenderContext);
}
void ScrollBar::Move()
{
Control::Move();
mbCalcSize = true;
if (IsReallyVisible())
ImplCalc(false);
Invalidate();
}
void ScrollBar::Resize()
{
Control::Resize();
mbCalcSize = true;
if ( IsReallyVisible() )
ImplCalc( false );
Invalidate();
}
IMPL_LINK_NOARG(ScrollBar, ImplAutoTimerHdl, Timer *, void)
{
if( mpData && mpData->mbHide )
return;
ImplInvert();
}
void ScrollBar::ImplInvert()
{
tools::Rectangle aRect( maThumbRect );
if( aRect.GetWidth() > 5 )
{
aRect.AdjustLeft(2 );
aRect.AdjustRight( -2 );
}
if( aRect.GetHeight() > 5 )
{
aRect.AdjustTop(2 );
aRect.AdjustBottom( -2 );
}
GetOutDev()->Invert( aRect );
}
void ScrollBar::GetFocus()
{
if( !mpData )
{
mpData.reset(new ImplScrollBarData);
mpData->maTimer.SetInvokeHandler( LINK( this, ScrollBar, ImplAutoTimerHdl ) );
mpData->mbHide = false;
}
ImplInvert(); // react immediately
mpData->maTimer.SetTimeout( GetSettings().GetStyleSettings().GetCursorBlinkTime() );
if (mpData->maTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME)
mpData->maTimer.Start();
Control::GetFocus();
}
void ScrollBar::LoseFocus()
{
if( mpData )
mpData->maTimer.Stop();
Invalidate();
Control::LoseFocus();
}
void ScrollBar::StateChanged( StateChangedType nType )
{
Control::StateChanged( nType );
if ( nType == StateChangedType::InitShow )
ImplCalc( false );
else if ( nType == StateChangedType::Data )
{
if ( IsReallyVisible() && IsUpdateMode() )
ImplCalc();
}
else if ( nType == StateChangedType::UpdateMode )
{
if ( IsReallyVisible() && IsUpdateMode() )
{
ImplCalc( false );
Invalidate();
}
}
else if ( nType == StateChangedType::Enable )
{
if ( IsReallyVisible() && IsUpdateMode() )
Invalidate();
}
else if ( nType == StateChangedType::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() == DataChangedEventType::SETTINGS) &&
(rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
{
mbCalcSize = true;
ImplCalc( false );
Invalidate();
}
}
tools::Rectangle* ScrollBar::ImplFindPartRect( const Point& rPt )
{
bool bHorizontal = ( GetStyle() & WB_HORZ ) != 0;
bool bIsInside = false;
Point aPoint( 0, 0 );
tools::Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
if( GetOutDev()->HitTestNativeScrollbar( bHorizontal? (IsRTLEnabled()? ControlPart::ButtonRight: ControlPart::ButtonLeft): ControlPart::ButtonUp,
aControlRegion, rPt, bIsInside )?
bIsInside:
maBtn1Rect.Contains( rPt ) )
return &maBtn1Rect;
else if( GetOutDev()->HitTestNativeScrollbar( bHorizontal? (IsRTLEnabled()? ControlPart::ButtonLeft: ControlPart::ButtonRight): ControlPart::ButtonDown,
aControlRegion, rPt, bIsInside )?
bIsInside:
maBtn2Rect.Contains( rPt ) )
return &maBtn2Rect;
// HitTestNativeScrollbar, see remark at top of file
else if( GetOutDev()->HitTestNativeScrollbar( bHorizontal ? ControlPart::TrackHorzLeft : ControlPart::TrackVertUpper,
maPage1Rect, rPt, bIsInside)?
bIsInside:
maPage1Rect.Contains( rPt ) )
return &maPage1Rect;
// HitTestNativeScrollbar, see remark at top of file
else if( GetOutDev()->HitTestNativeScrollbar( bHorizontal ? ControlPart::TrackHorzRight : ControlPart::TrackVertLower,
maPage2Rect, rPt, bIsInside)?
bIsInside:
maPage2Rect.Contains( rPt ) )
return &maPage2Rect;
// HitTestNativeScrollbar, see remark at top of file
else if( GetOutDev()->HitTestNativeScrollbar( bHorizontal ? ControlPart::ThumbHorz : ControlPart::ThumbVert,
maThumbRect, rPt, bIsInside)?
bIsInside:
maThumbRect.Contains( rPt ) )
return &maThumbRect;
else
return nullptr;
}
bool ScrollBar::PreNotify( NotifyEvent& rNEvt )
{
if( rNEvt.GetType() == NotifyEventType::MOUSEMOVE )
{
const MouseEvent* pMouseEvt = rNEvt.GetMouseEvent();
if( pMouseEvt && !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
{
// Trigger a redraw if mouse over state has changed
if( IsNativeControlSupported(ControlType::Scrollbar, ControlPart::Entire) )
{
tools::Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
tools::Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
if( pRect != pLastRect || pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow() )
{
vcl::Region aRgn( GetOutDev()->GetActiveClipRegion() );
vcl::Region aClipRegion;
if ( pRect )
aClipRegion.Union( *pRect );
if ( pLastRect )
aClipRegion.Union( *pLastRect );
// Support for 3-button scroll bars
bool bHas3Buttons = IsNativeControlSupported( ControlType::Scrollbar, ControlPart::HasThreeButtons );
if ( bHas3Buttons && ( pRect == &maBtn1Rect || pLastRect == &maBtn1Rect ) )
{
aClipRegion.Union( maBtn2Rect );
}
GetOutDev()->SetClipRegion( aClipRegion );
Invalidate(aClipRegion.GetBoundRect());
GetOutDev()->SetClipRegion( aRgn );
}
}
}
}
return Control::PreNotify(rNEvt);
}
void ScrollBar::Scroll()
{
ImplCallEventListenersAndHandler( VclEventId::ScrollbarScroll, [this] () { maScrollHdl.Call(this); } );
}
void ScrollBar::EndScroll()
{
ImplCallEventListenersAndHandler( VclEventId::ScrollbarEndScroll, [this] () { maEndScrollHdl.Call(this); } );
}
tools::Long ScrollBar::DoScroll( tools::Long nNewPos )
{
if ( meScrollType != ScrollType::DontKnow )
return 0;
SAL_INFO("vcl.scrollbar", "DoScroll(" << nNewPos << ")");
meScrollType = ScrollType::Drag;
tools::Long nDelta = ImplScroll( nNewPos, true );
meScrollType = ScrollType::DontKnow;
return nDelta;
}
tools::Long ScrollBar::DoScrollAction( ScrollType eScrollType )
{
if ( (meScrollType != ScrollType::DontKnow) ||
(eScrollType == ScrollType::DontKnow) ||
(eScrollType == ScrollType::Drag) )
return 0;
meScrollType = eScrollType;
tools::Long nDelta = ImplDoAction( true );
meScrollType = ScrollType::DontKnow;
return nDelta;
}
void ScrollBar::SetRangeMin( tools::Long nNewRange )
{
SetRange( Range( nNewRange, GetRangeMax() ) );
}
void ScrollBar::SetRangeMax( tools::Long nNewRange )
{
SetRange( Range( GetRangeMin(), nNewRange ) );
}
void ScrollBar::SetRange( const Range& rRange )
{
// Adapt Range
Range aRange = rRange;
aRange.Normalize();
tools::Long nNewMinRange = aRange.Min();
tools::Long nNewMaxRange = aRange.Max();
// If Range differs, set a new one
if ( (mnMinRange == nNewMinRange) && (mnMaxRange == nNewMaxRange))
return;
mnMinRange = nNewMinRange;
mnMaxRange = nNewMaxRange;
// Adapt Thumb
if ( mnThumbPos > mnMaxRange-mnVisibleSize )
mnThumbPos = mnMaxRange-mnVisibleSize;
if ( mnThumbPos < mnMinRange )
mnThumbPos = mnMinRange;
CompatStateChanged( StateChangedType::Data );
}
void ScrollBar::SetThumbPos( tools::Long nNewThumbPos )
{
if ( nNewThumbPos > mnMaxRange-mnVisibleSize )
nNewThumbPos = mnMaxRange-mnVisibleSize;
if ( nNewThumbPos < mnMinRange )
nNewThumbPos = mnMinRange;
if ( mnThumbPos != nNewThumbPos )
{
mnThumbPos = nNewThumbPos;
CompatStateChanged( StateChangedType::Data );
}
}
void ScrollBar::SetVisibleSize( tools::Long nNewSize )
{
if ( mnVisibleSize != nNewSize )
{
mnVisibleSize = nNewSize;
// Adapt Thumb
if ( mnThumbPos > mnMaxRange-mnVisibleSize )
mnThumbPos = mnMaxRange-mnVisibleSize;
if ( mnThumbPos < mnMinRange )
mnThumbPos = mnMinRange;
CompatStateChanged( StateChangedType::Data );
}
}
Size ScrollBar::GetOptimalSize() const
{
if (mbCalcSize)
const_cast<ScrollBar*>(this)->ImplCalc(false);
Size aRet = getCurrentCalcSize();
const tools::Long nMinThumbSize = GetSettings().GetStyleSettings().GetMinThumbSize();
if (GetStyle() & WB_HORZ)
{
aRet.setWidth( maBtn1Rect.GetWidth() + nMinThumbSize + maBtn2Rect.GetWidth() );
}
else
{
aRet.setHeight( maBtn1Rect.GetHeight() + nMinThumbSize + maBtn2Rect.GetHeight() );
}
return aRet;
}
Size ScrollBar::getCurrentCalcSize() const
{
tools::Rectangle aCtrlRegion;
aCtrlRegion.Union(maBtn1Rect);
aCtrlRegion.Union(maBtn2Rect);
aCtrlRegion.Union(maPage1Rect);
aCtrlRegion.Union(maPage2Rect);
aCtrlRegion.Union(maThumbRect);
return aCtrlRegion.GetSize();
}
bool ScrollBar::Inactive() const
{
return !IsEnabled() || !IsInputEnabled() || IsInModalMode();
}
void ScrollBarBox::ImplInit(vcl::Window* pParent, WinBits nStyle)
{
Window::ImplInit( pParent, nStyle, nullptr );
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
tools::Long nScrollSize = rStyleSettings.GetScrollBarSize();
SetSizePixel(Size(nScrollSize, nScrollSize));
}
ScrollBarBox::ScrollBarBox( vcl::Window* pParent, WinBits nStyle ) :
Window( WindowType::SCROLLBARBOX )
{
ImplInit( pParent, nStyle );
}
void ScrollBarBox::ApplySettings(vcl::RenderContext& rRenderContext)
{
if (rRenderContext.IsBackground())
{
Color aColor = rRenderContext.GetSettings().GetStyleSettings().GetFaceColor();
ApplyControlBackground(rRenderContext, aColor);
}
}
void ScrollBarBox::StateChanged( StateChangedType nType )
{
Window::StateChanged( nType );
if (nType == StateChangedType::ControlBackground)
{
Invalidate();
}
}
void ScrollBarBox::DataChanged( const DataChangedEvent& rDCEvt )
{
Window::DataChanged( rDCEvt );
if ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
(rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
{
Invalidate();
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'Union' is required to be utilized.
↑ V530 The return value of function 'Union' is required to be utilized.
↑ V530 The return value of function 'Union' is required to be utilized.
↑ V530 The return value of function 'Union' is required to be utilized.
↑ V530 The return value of function 'Union' is required to be utilized.
↑ V530 The return value of function 'Union' is required to be utilized.
↑ V530 The return value of function 'Union' is required to be utilized.
↑ V530 The return value of function 'Union' is required to be utilized.
↑ V530 The return value of function 'Union' is required to be utilized.
↑ V530 The return value of function 'Union' is required to be utilized.
↑ V730 Not all members of a class are initialized inside the compiler generated constructor. Consider inspecting: mbHide.
↑ V730 It is possible that not all members of a class are initialized inside the constructor. Consider inspecting: mnStartPos, mnMouseOff.
↑ V1048 The 'nTrackFlags' variable was assigned the same value.