bump product version to 6.4.0.3
[LibreOffice.git] / vcl / source / control / scrbar.cxx
blob221664f7d9aeba5f8501e0f2bbbe00ffa00181da
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/event.hxx>
21 #include <vcl/decoview.hxx>
22 #include <vcl/scrbar.hxx>
23 #include <vcl/timer.hxx>
24 #include <vcl/settings.hxx>
25 #include <vcl/vclevent.hxx>
27 #include <sal/log.hxx>
29 /* #i77549#
30 HACK: for scrollbars in case of thumb rect, page up and page down rect we
31 abuse the HitTestNativeScrollbar interface. All theming engines but macOS
32 are actually able to draw the thumb according to our internal representation.
33 However macOS draws a little outside. The canonical way would be to enhance the
34 HitTestNativeScrollbar passing a ScrollbarValue additionally so all necessary
35 information is available in the call.
37 However since there is only this one small exception we will deviate a little and
38 instead pass the respective rect as control region to allow for a small correction.
40 So all places using HitTestNativeScrollbar on ControlPart::ThumbHorz, ControlPart::ThumbVert,
41 ControlPart::TrackHorzLeft, ControlPart::TrackHorzRight, ControlPart::TrackVertUpper, ControlPart::TrackVertLower
42 do not use the control rectangle as region but the actual part rectangle, making
43 only small deviations feasible.
46 #include "thumbpos.hxx"
48 #define SCRBAR_DRAW_BTN1 (sal_uInt16(0x0001))
49 #define SCRBAR_DRAW_BTN2 (sal_uInt16(0x0002))
50 #define SCRBAR_DRAW_PAGE1 (sal_uInt16(0x0004))
51 #define SCRBAR_DRAW_PAGE2 (sal_uInt16(0x0008))
52 #define SCRBAR_DRAW_THUMB (sal_uInt16(0x0010))
53 #define SCRBAR_DRAW_BACKGROUND (sal_uInt16(0x0020))
55 #define SCRBAR_STATE_BTN1_DOWN (sal_uInt16(0x0001))
56 #define SCRBAR_STATE_BTN1_DISABLE (sal_uInt16(0x0002))
57 #define SCRBAR_STATE_BTN2_DOWN (sal_uInt16(0x0004))
58 #define SCRBAR_STATE_BTN2_DISABLE (sal_uInt16(0x0008))
59 #define SCRBAR_STATE_PAGE1_DOWN (sal_uInt16(0x0010))
60 #define SCRBAR_STATE_PAGE2_DOWN (sal_uInt16(0x0020))
61 #define SCRBAR_STATE_THUMB_DOWN (sal_uInt16(0x0040))
63 #define SCRBAR_VIEW_STYLE (WB_3DLOOK | WB_HORZ | WB_VERT)
65 struct ImplScrollBarData
67 AutoTimer maTimer; // Timer
68 bool mbHide;
71 void ScrollBar::ImplInit( vcl::Window* pParent, WinBits nStyle )
73 mpData = nullptr;
74 mnThumbPixRange = 0;
75 mnThumbPixPos = 0;
76 mnThumbPixSize = 0;
77 mnMinRange = 0;
78 mnMaxRange = 100;
79 mnThumbPos = 0;
80 mnVisibleSize = 0;
81 mnLineSize = 1;
82 mnPageSize = 1;
83 mnDelta = 0;
84 mnStateFlags = 0;
85 meScrollType = ScrollType::DontKnow;
86 mbCalcSize = true;
87 mbFullDrag = false;
89 ImplInitStyle( nStyle );
90 Control::ImplInit( pParent, nStyle, nullptr );
92 long nScrollSize = GetSettings().GetStyleSettings().GetScrollBarSize();
93 SetSizePixel( Size( nScrollSize, nScrollSize ) );
96 void ScrollBar::ImplInitStyle( WinBits nStyle )
98 if ( nStyle & WB_DRAG )
99 mbFullDrag = true;
100 else
101 mbFullDrag = bool(GetSettings().GetStyleSettings().GetDragFullOptions() & DragFullOptions::Scroll);
104 ScrollBar::ScrollBar( vcl::Window* pParent, WinBits nStyle ) :
105 Control( WindowType::SCROLLBAR )
107 ImplInit( pParent, nStyle );
110 ScrollBar::~ScrollBar()
112 disposeOnce();
115 void ScrollBar::dispose()
117 mpData.reset();
118 Control::dispose();
121 void ScrollBar::ImplUpdateRects( bool bUpdate )
123 mnStateFlags &= ~SCRBAR_STATE_BTN1_DISABLE;
124 mnStateFlags &= ~SCRBAR_STATE_BTN2_DISABLE;
126 if ( mnThumbPixRange )
128 if ( GetStyle() & WB_HORZ )
130 maThumbRect.SetLeft( maTrackRect.Left()+mnThumbPixPos );
131 maThumbRect.SetRight( maThumbRect.Left()+mnThumbPixSize-1 );
132 if ( !mnThumbPixPos )
133 maPage1Rect.SetWidthEmpty();
134 else
135 maPage1Rect.SetRight( maThumbRect.Left()-1 );
136 if ( mnThumbPixPos >= (mnThumbPixRange-mnThumbPixSize) )
137 maPage2Rect.SetWidthEmpty();
138 else
140 maPage2Rect.SetLeft( maThumbRect.Right()+1 );
141 maPage2Rect.SetRight( maTrackRect.Right() );
144 else
146 maThumbRect.SetTop( maTrackRect.Top()+mnThumbPixPos );
147 maThumbRect.SetBottom( maThumbRect.Top()+mnThumbPixSize-1 );
148 if ( !mnThumbPixPos )
149 maPage1Rect.SetHeightEmpty();
150 else
151 maPage1Rect.SetBottom( maThumbRect.Top()-1 );
152 if ( mnThumbPixPos >= (mnThumbPixRange-mnThumbPixSize) )
153 maPage2Rect.SetHeightEmpty();
154 else
156 maPage2Rect.SetTop( maThumbRect.Bottom()+1 );
157 maPage2Rect.SetBottom( maTrackRect.Bottom() );
161 else
163 if ( GetStyle() & WB_HORZ )
165 const long nSpace = maTrackRect.Right() - maTrackRect.Left();
166 if ( nSpace > 0 )
168 maPage1Rect.SetLeft( maTrackRect.Left() );
169 maPage1Rect.SetRight( maTrackRect.Left() + (nSpace/2) );
170 maPage2Rect.SetLeft( maPage1Rect.Right() + 1 );
171 maPage2Rect.SetRight( maTrackRect.Right() );
174 else
176 const long nSpace = maTrackRect.Bottom() - maTrackRect.Top();
177 if ( nSpace > 0 )
179 maPage1Rect.SetTop( maTrackRect.Top() );
180 maPage1Rect.SetBottom( maTrackRect.Top() + (nSpace/2) );
181 maPage2Rect.SetTop( maPage1Rect.Bottom() + 1 );
182 maPage2Rect.SetBottom( maTrackRect.Bottom() );
187 if( !IsNativeControlSupported(ControlType::Scrollbar, ControlPart::Entire) )
189 // disable scrollbar buttons only in VCL's own 'theme'
190 // as it is uncommon on other platforms
191 if ( mnThumbPos == mnMinRange )
192 mnStateFlags |= SCRBAR_STATE_BTN1_DISABLE;
193 if ( mnThumbPos >= (mnMaxRange-mnVisibleSize) )
194 mnStateFlags |= SCRBAR_STATE_BTN2_DISABLE;
197 if ( bUpdate )
199 Invalidate();
203 long ScrollBar::ImplCalcThumbPos( long nPixPos )
205 // Calculate position
206 long nCalcThumbPos;
207 nCalcThumbPos = ImplMulDiv( nPixPos, mnMaxRange-mnVisibleSize-mnMinRange,
208 mnThumbPixRange-mnThumbPixSize );
209 nCalcThumbPos += mnMinRange;
210 return nCalcThumbPos;
213 long ScrollBar::ImplCalcThumbPosPix( long nPos )
215 long nCalcThumbPos;
217 // Calculate position
218 nCalcThumbPos = ImplMulDiv( nPos-mnMinRange, mnThumbPixRange-mnThumbPixSize,
219 mnMaxRange-mnVisibleSize-mnMinRange );
221 // At the start and end of the ScrollBar, we try to show the display correctly
222 if ( !nCalcThumbPos && (mnThumbPos > mnMinRange) )
223 nCalcThumbPos = 1;
224 if ( nCalcThumbPos &&
225 ((nCalcThumbPos+mnThumbPixSize) >= mnThumbPixRange) &&
226 (mnThumbPos < (mnMaxRange-mnVisibleSize)) )
227 nCalcThumbPos--;
229 return nCalcThumbPos;
232 void ScrollBar::ImplCalc( bool bUpdate )
234 const Size aSize = GetOutputSizePixel();
235 const long nMinThumbSize = GetSettings().GetStyleSettings().GetMinThumbSize();
237 if ( mbCalcSize )
239 Size aOldSize = getCurrentCalcSize();
241 const tools::Rectangle aControlRegion( Point(0,0), aSize );
242 tools::Rectangle aBtn1Region, aBtn2Region, aTrackRegion, aBoundingRegion;
244 // reset rectangles to empty *and* (0,0) position
245 maThumbRect = tools::Rectangle();
246 maPage1Rect = tools::Rectangle();
247 maPage2Rect = tools::Rectangle();
249 if ( GetStyle() & WB_HORZ )
251 if ( GetNativeControlRegion( ControlType::Scrollbar, IsRTLEnabled()? ControlPart::ButtonRight: ControlPart::ButtonLeft,
252 aControlRegion, ControlState::NONE, ImplControlValue(), aBoundingRegion, aBtn1Region ) &&
253 GetNativeControlRegion( ControlType::Scrollbar, IsRTLEnabled()? ControlPart::ButtonLeft: ControlPart::ButtonRight,
254 aControlRegion, ControlState::NONE, ImplControlValue(), aBoundingRegion, aBtn2Region ) )
256 maBtn1Rect = aBtn1Region;
257 maBtn2Rect = aBtn2Region;
259 else
261 Size aBtnSize( aSize.Height(), aSize.Height() );
262 maBtn2Rect.SetTop( maBtn1Rect.Top() );
263 maBtn2Rect.SetLeft( aSize.Width()-aSize.Height() );
264 maBtn1Rect.SetSize( aBtnSize );
265 maBtn2Rect.SetSize( aBtnSize );
268 if ( GetNativeControlRegion( ControlType::Scrollbar, ControlPart::TrackHorzArea,
269 aControlRegion, ControlState::NONE, ImplControlValue(), aBoundingRegion, aTrackRegion ) )
270 maTrackRect = aTrackRegion;
271 else
272 maTrackRect = tools::Rectangle( maBtn1Rect.TopRight(), maBtn2Rect.BottomLeft() );
274 // Check if available space is big enough for thumb ( min thumb size = ScrBar width/height )
275 mnThumbPixRange = maTrackRect.Right() - maTrackRect.Left();
276 if( mnThumbPixRange > 0 )
278 maPage1Rect.SetLeft( maTrackRect.Left() );
279 maPage1Rect.SetBottom( maTrackRect.Bottom() );
280 maPage2Rect.SetBottom (maTrackRect.Bottom() );
281 maThumbRect.SetBottom( maTrackRect.Bottom() );
283 else
284 mnThumbPixRange = 0;
286 else // WB_VERT
288 if ( GetNativeControlRegion( ControlType::Scrollbar, ControlPart::ButtonUp,
289 aControlRegion, ControlState::NONE, ImplControlValue(), aBoundingRegion, aBtn1Region ) &&
290 GetNativeControlRegion( ControlType::Scrollbar, ControlPart::ButtonDown,
291 aControlRegion, ControlState::NONE, ImplControlValue(), aBoundingRegion, aBtn2Region ) )
293 maBtn1Rect = aBtn1Region;
294 maBtn2Rect = aBtn2Region;
296 else
298 const Size aBtnSize( aSize.Width(), aSize.Width() );
299 maBtn2Rect.SetLeft( maBtn1Rect.Left() );
300 maBtn2Rect.SetTop( aSize.Height()-aSize.Width() );
301 maBtn1Rect.SetSize( aBtnSize );
302 maBtn2Rect.SetSize( aBtnSize );
305 if ( GetNativeControlRegion( ControlType::Scrollbar, ControlPart::TrackVertArea,
306 aControlRegion, ControlState::NONE, ImplControlValue(), aBoundingRegion, aTrackRegion ) )
307 maTrackRect = aTrackRegion;
308 else
309 maTrackRect = tools::Rectangle( maBtn1Rect.BottomLeft()+Point(0,1), maBtn2Rect.TopRight() );
311 // Check if available space is big enough for thumb
312 mnThumbPixRange = maTrackRect.Bottom() - maTrackRect.Top();
313 if( mnThumbPixRange > 0 )
315 maPage1Rect.SetTop( maTrackRect.Top() );
316 maPage1Rect.SetRight( maTrackRect.Right() );
317 maPage2Rect.SetRight( maTrackRect.Right() );
318 maThumbRect.SetRight( maTrackRect.Right() );
320 else
321 mnThumbPixRange = 0;
324 mbCalcSize = false;
326 Size aNewSize = getCurrentCalcSize();
327 if (aOldSize != aNewSize)
329 queue_resize();
333 if ( mnThumbPixRange )
335 // Calculate values
336 if ( (mnVisibleSize >= (mnMaxRange-mnMinRange)) ||
337 ((mnMaxRange-mnMinRange) <= 0) )
339 mnThumbPos = mnMinRange;
340 mnThumbPixPos = 0;
341 mnThumbPixSize = mnThumbPixRange;
343 else
345 if ( mnVisibleSize )
346 mnThumbPixSize = ImplMulDiv( mnThumbPixRange, mnVisibleSize, mnMaxRange-mnMinRange );
347 else
349 if ( GetStyle() & WB_HORZ )
350 mnThumbPixSize = maThumbRect.GetWidth();
351 else
352 mnThumbPixSize = maThumbRect.GetHeight();
354 if ( mnThumbPixSize < nMinThumbSize )
355 mnThumbPixSize = nMinThumbSize;
356 if ( mnThumbPixSize > mnThumbPixRange )
357 mnThumbPixSize = mnThumbPixRange;
358 mnThumbPixPos = ImplCalcThumbPosPix( mnThumbPos );
362 // If we're ought to output again and we have been triggered
363 // a Paint event via an Action, we don't output directly,
364 // but invalidate everything
365 if ( bUpdate && HasPaintEvent() )
367 Invalidate();
368 bUpdate = false;
370 ImplUpdateRects( bUpdate );
373 void ScrollBar::Draw( OutputDevice* pDev, const Point& rPos, const Size& /* rSize */, DrawFlags nFlags )
375 Point aPos = pDev->LogicToPixel( rPos );
377 pDev->Push();
378 pDev->SetMapMode();
379 if ( !(nFlags & DrawFlags::Mono) )
381 // DecoView uses the FaceColor...
382 AllSettings aSettings = pDev->GetSettings();
383 StyleSettings aStyleSettings = aSettings.GetStyleSettings();
384 if ( IsControlBackground() )
385 aStyleSettings.SetFaceColor( GetControlBackground() );
386 else
387 aStyleSettings.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
389 aSettings.SetStyleSettings( aStyleSettings );
390 pDev->SetSettings( aSettings );
393 // For printing:
394 // - calculate the size of the rects
395 // - because this is zero-based add the correct offset
396 // - print
397 // - force recalculate
399 if ( mbCalcSize )
400 ImplCalc( false );
402 maBtn1Rect+=aPos;
403 maBtn2Rect+=aPos;
404 maThumbRect+=aPos;
405 maTrackRect+=aPos;
406 maPage1Rect+=aPos;
407 maPage2Rect+=aPos;
409 ImplDraw(*pDev);
410 pDev->Pop();
412 mbCalcSize = true;
415 bool ScrollBar::ImplDrawNative(vcl::RenderContext& rRenderContext, sal_uInt16 nDrawFlags)
417 ScrollbarValue scrValue;
419 bool bNativeOK = rRenderContext.IsNativeControlSupported(ControlType::Scrollbar, ControlPart::Entire);
420 if (!bNativeOK)
421 return false;
423 bool bHorz = (GetStyle() & WB_HORZ) != 0;
425 // Draw the entire background if the control supports it
426 if (rRenderContext.IsNativeControlSupported(ControlType::Scrollbar, bHorz ? ControlPart::DrawBackgroundHorz : ControlPart::DrawBackgroundVert))
428 ControlState nState = (IsEnabled() ? ControlState::ENABLED : ControlState::NONE)
429 | (HasFocus() ? ControlState::FOCUSED : ControlState::NONE);
431 scrValue.mnMin = mnMinRange;
432 scrValue.mnMax = mnMaxRange;
433 scrValue.mnCur = mnThumbPos;
434 scrValue.mnVisibleSize = mnVisibleSize;
435 scrValue.maThumbRect = maThumbRect;
436 scrValue.maButton1Rect = maBtn1Rect;
437 scrValue.maButton2Rect = maBtn2Rect;
438 scrValue.mnButton1State = ((mnStateFlags & SCRBAR_STATE_BTN1_DOWN) ? ControlState::PRESSED : ControlState::NONE) |
439 ((!(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE)) ? ControlState::ENABLED : ControlState::NONE);
440 scrValue.mnButton2State = ((mnStateFlags & SCRBAR_STATE_BTN2_DOWN) ? ControlState::PRESSED : ControlState::NONE) |
441 ((!(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE)) ? ControlState::ENABLED : ControlState::NONE);
442 scrValue.mnThumbState = nState | ((mnStateFlags & SCRBAR_STATE_THUMB_DOWN) ? ControlState::PRESSED : ControlState::NONE);
444 if (IsMouseOver())
446 tools::Rectangle* pRect = ImplFindPartRect(GetPointerPosPixel());
447 if (pRect)
449 if (pRect == &maThumbRect)
450 scrValue.mnThumbState |= ControlState::ROLLOVER;
451 else if (pRect == &maBtn1Rect)
452 scrValue.mnButton1State |= ControlState::ROLLOVER;
453 else if (pRect == &maBtn2Rect)
454 scrValue.mnButton2State |= ControlState::ROLLOVER;
458 tools::Rectangle aCtrlRegion;
459 aCtrlRegion.Union(maBtn1Rect);
460 aCtrlRegion.Union(maBtn2Rect);
461 aCtrlRegion.Union(maPage1Rect);
462 aCtrlRegion.Union(maPage2Rect);
463 aCtrlRegion.Union(maThumbRect);
465 tools::Rectangle aRequestedRegion(Point(0,0), GetOutputSizePixel());
466 // if the actual native control region is smaller then the region that
467 // we requested the control to draw in, then draw a background rectangle
468 // to avoid drawing artifacts in the uncovered region
469 if (aCtrlRegion.GetWidth() < aRequestedRegion.GetWidth() ||
470 aCtrlRegion.GetHeight() < aRequestedRegion.GetHeight())
472 Color aFaceColor = rRenderContext.GetSettings().GetStyleSettings().GetFaceColor();
473 rRenderContext.SetFillColor(aFaceColor);
474 rRenderContext.SetLineColor(aFaceColor);
475 rRenderContext.DrawRect(aRequestedRegion);
478 bNativeOK = rRenderContext.DrawNativeControl(ControlType::Scrollbar, (bHorz ? ControlPart::DrawBackgroundHorz : ControlPart::DrawBackgroundVert),
479 aCtrlRegion, nState, scrValue, OUString());
481 else
483 if ((nDrawFlags & SCRBAR_DRAW_PAGE1) || (nDrawFlags & SCRBAR_DRAW_PAGE2))
485 ControlPart part1 = bHorz ? ControlPart::TrackHorzLeft : ControlPart::TrackVertUpper;
486 ControlPart part2 = bHorz ? ControlPart::TrackHorzRight : ControlPart::TrackVertLower;
487 tools::Rectangle aCtrlRegion1(maPage1Rect);
488 tools::Rectangle aCtrlRegion2(maPage2Rect);
489 ControlState nState1 = (IsEnabled() ? ControlState::ENABLED : ControlState::NONE)
490 | (HasFocus() ? ControlState::FOCUSED : ControlState::NONE);
491 ControlState nState2 = nState1;
493 nState1 |= ((mnStateFlags & SCRBAR_STATE_PAGE1_DOWN) ? ControlState::PRESSED : ControlState::NONE);
494 nState2 |= ((mnStateFlags & SCRBAR_STATE_PAGE2_DOWN) ? ControlState::PRESSED : ControlState::NONE);
496 if (IsMouseOver())
498 tools::Rectangle* pRect = ImplFindPartRect(GetPointerPosPixel());
499 if (pRect)
501 if (pRect == &maPage1Rect)
502 nState1 |= ControlState::ROLLOVER;
503 else if (pRect == &maPage2Rect)
504 nState2 |= ControlState::ROLLOVER;
508 if (nDrawFlags & SCRBAR_DRAW_PAGE1)
509 bNativeOK = rRenderContext.DrawNativeControl(ControlType::Scrollbar, part1, aCtrlRegion1, nState1, scrValue, OUString());
511 if (nDrawFlags & SCRBAR_DRAW_PAGE2)
512 bNativeOK = rRenderContext.DrawNativeControl(ControlType::Scrollbar, part2, aCtrlRegion2, nState2, scrValue, OUString());
514 if ((nDrawFlags & SCRBAR_DRAW_BTN1) || (nDrawFlags & SCRBAR_DRAW_BTN2))
516 ControlPart part1 = bHorz ? ControlPart::ButtonLeft : ControlPart::ButtonUp;
517 ControlPart part2 = bHorz ? ControlPart::ButtonRight : ControlPart::ButtonDown;
518 tools::Rectangle aCtrlRegion1(maBtn1Rect);
519 tools::Rectangle aCtrlRegion2(maBtn2Rect);
520 ControlState nState1 = HasFocus() ? ControlState::FOCUSED : ControlState::NONE;
521 ControlState nState2 = nState1;
523 if (!Window::IsEnabled() || !IsEnabled())
524 nState1 = (nState2 &= ~ControlState::ENABLED);
525 else
526 nState1 = (nState2 |= ControlState::ENABLED);
528 nState1 |= ((mnStateFlags & SCRBAR_STATE_BTN1_DOWN) ? ControlState::PRESSED : ControlState::NONE);
529 nState2 |= ((mnStateFlags & SCRBAR_STATE_BTN2_DOWN) ? ControlState::PRESSED : ControlState::NONE);
531 if (mnStateFlags & SCRBAR_STATE_BTN1_DISABLE)
532 nState1 &= ~ControlState::ENABLED;
533 if (mnStateFlags & SCRBAR_STATE_BTN2_DISABLE)
534 nState2 &= ~ControlState::ENABLED;
536 if (IsMouseOver())
538 tools::Rectangle* pRect = ImplFindPartRect(GetPointerPosPixel());
539 if (pRect)
541 if (pRect == &maBtn1Rect)
542 nState1 |= ControlState::ROLLOVER;
543 else if (pRect == &maBtn2Rect)
544 nState2 |= ControlState::ROLLOVER;
548 if (nDrawFlags & SCRBAR_DRAW_BTN1)
549 bNativeOK = rRenderContext.DrawNativeControl(ControlType::Scrollbar, part1, aCtrlRegion1, nState1, scrValue, OUString());
551 if (nDrawFlags & SCRBAR_DRAW_BTN2)
552 bNativeOK = rRenderContext.DrawNativeControl(ControlType::Scrollbar, part2, aCtrlRegion2, nState2, scrValue, OUString());
554 if ((nDrawFlags & SCRBAR_DRAW_THUMB) && !maThumbRect.IsEmpty())
556 ControlState nState = IsEnabled() ? ControlState::ENABLED : ControlState::NONE;
557 tools::Rectangle aCtrlRegion(maThumbRect);
559 if (mnStateFlags & SCRBAR_STATE_THUMB_DOWN)
560 nState |= ControlState::PRESSED;
562 if (HasFocus())
563 nState |= ControlState::FOCUSED;
565 if (IsMouseOver())
567 tools::Rectangle* pRect = ImplFindPartRect(GetPointerPosPixel());
568 if (pRect && pRect == &maThumbRect)
569 nState |= ControlState::ROLLOVER;
572 bNativeOK = rRenderContext.DrawNativeControl(ControlType::Scrollbar, (bHorz ? ControlPart::ThumbHorz : ControlPart::ThumbVert),
573 aCtrlRegion, nState, scrValue, OUString());
576 return bNativeOK;
579 void ScrollBar::ImplDraw(vcl::RenderContext& rRenderContext)
581 DecorationView aDecoView(&rRenderContext);
582 tools::Rectangle aTempRect;
583 DrawButtonFlags nStyle;
584 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
585 SymbolType eSymbolType;
586 bool bEnabled = IsEnabled();
588 // Finish some open calculations (if any)
589 if (mbCalcSize)
590 ImplCalc(false);
592 //vcl::Window *pWin = NULL;
593 //if (rRenderContext.GetOutDevType() == OUTDEV_WINDOW)
594 // pWin = static_cast<vcl::Window*>(&rRenderContext);
596 // Draw the entire control if the native theme engine needs it
597 if (rRenderContext.IsNativeControlSupported(ControlType::Scrollbar, ControlPart::DrawBackgroundHorz))
599 ImplDrawNative(rRenderContext, SCRBAR_DRAW_BACKGROUND);
600 return;
603 if (!ImplDrawNative(rRenderContext, SCRBAR_DRAW_BTN1))
605 nStyle = DrawButtonFlags::NoLightBorder;
606 if (mnStateFlags & SCRBAR_STATE_BTN1_DOWN)
607 nStyle |= DrawButtonFlags::Pressed;
608 aTempRect = aDecoView.DrawButton( PixelToLogic(maBtn1Rect), nStyle );
609 ImplCalcSymbolRect( aTempRect );
610 DrawSymbolFlags nSymbolStyle = DrawSymbolFlags::NONE;
611 if ((mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) || !bEnabled)
612 nSymbolStyle |= DrawSymbolFlags::Disable;
613 if (GetStyle() & WB_HORZ)
614 eSymbolType = SymbolType::SPIN_LEFT;
615 else
616 eSymbolType = SymbolType::SPIN_UP;
617 aDecoView.DrawSymbol(aTempRect, eSymbolType, rStyleSettings.GetButtonTextColor(), nSymbolStyle);
620 if (!ImplDrawNative(rRenderContext, SCRBAR_DRAW_BTN2))
622 nStyle = DrawButtonFlags::NoLightBorder;
623 if (mnStateFlags & SCRBAR_STATE_BTN2_DOWN)
624 nStyle |= DrawButtonFlags::Pressed;
625 aTempRect = aDecoView.DrawButton(PixelToLogic(maBtn2Rect), nStyle);
626 ImplCalcSymbolRect(aTempRect);
627 DrawSymbolFlags nSymbolStyle = DrawSymbolFlags::NONE;
628 if ((mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) || !bEnabled)
629 nSymbolStyle |= DrawSymbolFlags::Disable;
630 if (GetStyle() & WB_HORZ)
631 eSymbolType = SymbolType::SPIN_RIGHT;
632 else
633 eSymbolType = SymbolType::SPIN_DOWN;
634 aDecoView.DrawSymbol(aTempRect, eSymbolType, rStyleSettings.GetButtonTextColor(), nSymbolStyle);
637 rRenderContext.SetLineColor();
639 if (!ImplDrawNative(rRenderContext, SCRBAR_DRAW_THUMB))
641 if (!maThumbRect.IsEmpty())
643 if (bEnabled)
645 nStyle = DrawButtonFlags::NoLightBorder;
646 aTempRect = aDecoView.DrawButton(PixelToLogic(maThumbRect), nStyle);
648 else
650 rRenderContext.SetFillColor(rStyleSettings.GetCheckedColor());
651 rRenderContext.DrawRect(PixelToLogic(maThumbRect));
656 if (!ImplDrawNative(rRenderContext, SCRBAR_DRAW_PAGE1))
658 if (mnStateFlags & SCRBAR_STATE_PAGE1_DOWN)
659 rRenderContext.SetFillColor(rStyleSettings.GetShadowColor());
660 else
661 rRenderContext.SetFillColor(rStyleSettings.GetCheckedColor());
662 rRenderContext.DrawRect(PixelToLogic(maPage1Rect));
664 if (!ImplDrawNative(rRenderContext, SCRBAR_DRAW_PAGE2))
666 if (mnStateFlags & SCRBAR_STATE_PAGE2_DOWN)
667 rRenderContext.SetFillColor(rStyleSettings.GetShadowColor());
668 else
669 rRenderContext.SetFillColor(rStyleSettings.GetCheckedColor());
670 rRenderContext.DrawRect(PixelToLogic(maPage2Rect));
674 long ScrollBar::ImplScroll( long nNewPos, bool bCallEndScroll )
676 long nOldPos = mnThumbPos;
677 SetThumbPos( nNewPos );
678 long nDelta = mnThumbPos-nOldPos;
679 if ( nDelta )
681 mnDelta = nDelta;
682 Scroll();
683 if ( bCallEndScroll )
684 EndScroll();
685 mnDelta = 0;
687 return nDelta;
690 long ScrollBar::ImplDoAction( bool bCallEndScroll )
692 long nDelta = 0;
694 switch ( meScrollType )
696 case ScrollType::LineUp:
697 nDelta = ImplScroll( mnThumbPos-mnLineSize, bCallEndScroll );
698 break;
700 case ScrollType::LineDown:
701 nDelta = ImplScroll( mnThumbPos+mnLineSize, bCallEndScroll );
702 break;
704 case ScrollType::PageUp:
705 nDelta = ImplScroll( mnThumbPos-mnPageSize, bCallEndScroll );
706 break;
708 case ScrollType::PageDown:
709 nDelta = ImplScroll( mnThumbPos+mnPageSize, bCallEndScroll );
710 break;
711 default:
715 return nDelta;
718 void ScrollBar::ImplDoMouseAction( const Point& rMousePos, bool bCallAction )
720 sal_uInt16 nOldStateFlags = mnStateFlags;
721 bool bAction = false;
722 bool bHorizontal = ( GetStyle() & WB_HORZ ) != 0;
723 bool bIsInside = false;
725 Point aPoint( 0, 0 );
726 tools::Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
728 switch ( meScrollType )
730 case ScrollType::LineUp:
731 if ( HitTestNativeScrollbar( bHorizontal? (IsRTLEnabled()? ControlPart::ButtonRight: ControlPart::ButtonLeft): ControlPart::ButtonUp,
732 aControlRegion, rMousePos, bIsInside )?
733 bIsInside:
734 maBtn1Rect.IsInside( rMousePos ) )
736 bAction = bCallAction;
737 mnStateFlags |= SCRBAR_STATE_BTN1_DOWN;
739 else
740 mnStateFlags &= ~SCRBAR_STATE_BTN1_DOWN;
741 break;
743 case ScrollType::LineDown:
744 if ( HitTestNativeScrollbar( bHorizontal? (IsRTLEnabled()? ControlPart::ButtonLeft: ControlPart::ButtonRight): ControlPart::ButtonDown,
745 aControlRegion, rMousePos, bIsInside )?
746 bIsInside:
747 maBtn2Rect.IsInside( rMousePos ) )
749 bAction = bCallAction;
750 mnStateFlags |= SCRBAR_STATE_BTN2_DOWN;
752 else
753 mnStateFlags &= ~SCRBAR_STATE_BTN2_DOWN;
754 break;
756 case ScrollType::PageUp:
757 // HitTestNativeScrollbar, see remark at top of file
758 if ( HitTestNativeScrollbar( bHorizontal? ControlPart::TrackHorzLeft: ControlPart::TrackVertUpper,
759 maPage1Rect, rMousePos, bIsInside )?
760 bIsInside:
761 maPage1Rect.IsInside( rMousePos ) )
763 bAction = bCallAction;
764 mnStateFlags |= SCRBAR_STATE_PAGE1_DOWN;
766 else
767 mnStateFlags &= ~SCRBAR_STATE_PAGE1_DOWN;
768 break;
770 case ScrollType::PageDown:
771 // HitTestNativeScrollbar, see remark at top of file
772 if ( HitTestNativeScrollbar( bHorizontal? ControlPart::TrackHorzRight: ControlPart::TrackVertLower,
773 maPage2Rect, rMousePos, bIsInside )?
774 bIsInside:
775 maPage2Rect.IsInside( rMousePos ) )
777 bAction = bCallAction;
778 mnStateFlags |= SCRBAR_STATE_PAGE2_DOWN;
780 else
781 mnStateFlags &= ~SCRBAR_STATE_PAGE2_DOWN;
782 break;
783 default:
787 if ( nOldStateFlags != mnStateFlags )
788 Invalidate();
789 if ( bAction )
790 ImplDoAction( false );
793 void ScrollBar::ImplDragThumb( const Point& rMousePos )
795 long nMovePix;
796 if ( GetStyle() & WB_HORZ )
797 nMovePix = rMousePos.X()-(maThumbRect.Left()+mnMouseOff);
798 else
799 nMovePix = rMousePos.Y()-(maThumbRect.Top()+mnMouseOff);
801 // Move thumb if necessary
802 if ( nMovePix )
804 mnThumbPixPos += nMovePix;
805 if ( mnThumbPixPos < 0 )
806 mnThumbPixPos = 0;
807 if ( mnThumbPixPos > (mnThumbPixRange-mnThumbPixSize) )
808 mnThumbPixPos = mnThumbPixRange-mnThumbPixSize;
809 long nOldPos = mnThumbPos;
810 mnThumbPos = ImplCalcThumbPos( mnThumbPixPos );
811 ImplUpdateRects();
812 if ( mbFullDrag && (nOldPos != mnThumbPos) )
814 // When dragging in windows the repaint request gets starved so dragging
815 // the scrollbar feels slower than it actually is. Let's force an immediate
816 // repaint of the scrollbar.
817 if (SupportsDoubleBuffering())
819 Invalidate();
820 Update();
822 else
823 ImplDraw(*this);
825 mnDelta = mnThumbPos-nOldPos;
826 Scroll();
827 mnDelta = 0;
832 void ScrollBar::MouseButtonDown( const MouseEvent& rMEvt )
834 bool bPrimaryWarps = GetSettings().GetStyleSettings().GetPrimaryButtonWarpsSlider();
835 bool bWarp = bPrimaryWarps ? rMEvt.IsLeft() : rMEvt.IsMiddle();
836 bool bPrimaryWarping = bWarp && rMEvt.IsLeft();
837 bool bPage = bPrimaryWarps ? rMEvt.IsRight() : rMEvt.IsLeft();
839 if (!rMEvt.IsLeft() && !rMEvt.IsMiddle() && !rMEvt.IsRight())
840 return;
842 Point aPosPixel;
843 if (!IsMapModeEnabled() && GetMapMode().GetMapUnit() == MapUnit::MapTwip)
845 // rMEvt coordinates are in twips.
846 Push(PushFlags::MAPMODE);
847 EnableMapMode();
848 MapMode aMapMode = GetMapMode();
849 aMapMode.SetOrigin(Point(0, 0));
850 SetMapMode(aMapMode);
851 aPosPixel = LogicToPixel(rMEvt.GetPosPixel());
852 Pop();
854 const Point& rMousePos = (GetMapMode().GetMapUnit() != MapUnit::MapTwip ? rMEvt.GetPosPixel() : aPosPixel);
855 StartTrackingFlags nTrackFlags = StartTrackingFlags::NONE;
856 bool bHorizontal = ( GetStyle() & WB_HORZ ) != 0;
857 bool bIsInside = false;
858 bool bDragToMouse = false;
860 Point aPoint( 0, 0 );
861 tools::Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
863 if ( HitTestNativeScrollbar( bHorizontal? (IsRTLEnabled()? ControlPart::ButtonRight: ControlPart::ButtonLeft): ControlPart::ButtonUp,
864 aControlRegion, rMousePos, bIsInside )?
865 bIsInside:
866 maBtn1Rect.IsInside( rMousePos ) )
868 if (rMEvt.IsLeft() && !(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) )
870 nTrackFlags = StartTrackingFlags::ButtonRepeat;
871 meScrollType = ScrollType::LineUp;
874 else if ( HitTestNativeScrollbar( bHorizontal? (IsRTLEnabled()? ControlPart::ButtonLeft: ControlPart::ButtonRight): ControlPart::ButtonDown,
875 aControlRegion, rMousePos, bIsInside )?
876 bIsInside:
877 maBtn2Rect.IsInside( rMousePos ) )
879 if (rMEvt.IsLeft() && !(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) )
881 nTrackFlags = StartTrackingFlags::ButtonRepeat;
882 meScrollType = ScrollType::LineDown;
885 else
887 bool bThumbHit = HitTestNativeScrollbar( bHorizontal? ControlPart::ThumbHorz : ControlPart::ThumbVert,
888 maThumbRect, rMousePos, bIsInside )
889 ? bIsInside : maThumbRect.IsInside( rMousePos );
891 bool bThumbAction = bWarp || bPage;
893 bool bDragHandling = bWarp || (bThumbHit && bThumbAction);
894 if( bDragHandling )
896 if( mpData )
898 mpData->mbHide = true; // disable focus blinking
899 if (HasFocus())
901 mnStateFlags |= SCRBAR_DRAW_THUMB; // paint without focus
902 Invalidate();
906 if ( mnVisibleSize < mnMaxRange-mnMinRange )
908 nTrackFlags = StartTrackingFlags::NONE;
909 meScrollType = ScrollType::Drag;
911 // calculate mouse offset
912 if (bWarp && (!bThumbHit || !bPrimaryWarping))
914 bDragToMouse = true;
915 if ( GetStyle() & WB_HORZ )
916 mnMouseOff = maThumbRect.GetWidth()/2;
917 else
918 mnMouseOff = maThumbRect.GetHeight()/2;
920 else
922 if ( GetStyle() & WB_HORZ )
923 mnMouseOff = rMousePos.X()-maThumbRect.Left();
924 else
925 mnMouseOff = rMousePos.Y()-maThumbRect.Top();
928 mnStateFlags |= SCRBAR_STATE_THUMB_DOWN;
929 Invalidate();
932 else if(bPage && (!HitTestNativeScrollbar( bHorizontal? ControlPart::TrackHorzArea : ControlPart::TrackVertArea,
933 aControlRegion, rMousePos, bIsInside ) ||
934 bIsInside) )
936 nTrackFlags = StartTrackingFlags::ButtonRepeat;
938 // HitTestNativeScrollbar, see remark at top of file
939 if ( HitTestNativeScrollbar( bHorizontal? ControlPart::TrackHorzLeft : ControlPart::TrackVertUpper,
940 maPage1Rect, rMousePos, bIsInside )?
941 bIsInside:
942 maPage1Rect.IsInside( rMousePos ) )
944 meScrollType = ScrollType::PageUp;
946 else
948 meScrollType = ScrollType::PageDown;
953 // Should we start Tracking?
954 if ( meScrollType != ScrollType::DontKnow )
956 // store original position for cancel and EndScroll delta
957 mnStartPos = mnThumbPos;
958 // #92906# Call StartTracking() before ImplDoMouseAction(), otherwise
959 // MouseButtonUp() / EndTracking() may be called if somebody is spending
960 // a lot of time in the scroll handler
961 StartTracking( nTrackFlags );
962 ImplDoMouseAction( rMousePos );
964 if( bDragToMouse )
965 ImplDragThumb( rMousePos );
970 void ScrollBar::Tracking( const TrackingEvent& rTEvt )
972 if ( rTEvt.IsTrackingEnded() )
974 // Restore Button and PageRect status
975 sal_uInt16 nOldStateFlags = mnStateFlags;
976 mnStateFlags &= ~(SCRBAR_STATE_BTN1_DOWN | SCRBAR_STATE_BTN2_DOWN |
977 SCRBAR_STATE_PAGE1_DOWN | SCRBAR_STATE_PAGE2_DOWN |
978 SCRBAR_STATE_THUMB_DOWN);
979 if ( nOldStateFlags != mnStateFlags )
980 Invalidate();
982 // Restore the old ThumbPosition when canceled
983 if ( rTEvt.IsTrackingCanceled() )
985 long nOldPos = mnThumbPos;
986 SetThumbPos( mnStartPos );
987 mnDelta = mnThumbPos-nOldPos;
988 Scroll();
991 if ( meScrollType == ScrollType::Drag )
993 // On a SCROLLDRAG we recalculate the Thumb, so that it's back to a
994 // rounded ThumbPosition
995 ImplCalc();
997 if ( !mbFullDrag && (mnStartPos != mnThumbPos) )
999 mnDelta = mnThumbPos-mnStartPos;
1000 Scroll();
1001 mnDelta = 0;
1005 mnDelta = mnThumbPos-mnStartPos;
1006 EndScroll();
1007 mnDelta = 0;
1008 meScrollType = ScrollType::DontKnow;
1010 if( mpData )
1011 mpData->mbHide = false; // re-enable focus blinking
1013 else
1015 Point aPosPixel;
1016 if (!IsMapModeEnabled() && GetMapMode().GetMapUnit() == MapUnit::MapTwip)
1018 // rTEvt coordinates are in twips.
1019 Push(PushFlags::MAPMODE);
1020 EnableMapMode();
1021 MapMode aMapMode = GetMapMode();
1022 aMapMode.SetOrigin(Point(0, 0));
1023 SetMapMode(aMapMode);
1024 aPosPixel = LogicToPixel(rTEvt.GetMouseEvent().GetPosPixel());
1025 Pop();
1027 const Point rMousePos = (GetMapMode().GetMapUnit() != MapUnit::MapTwip ? rTEvt.GetMouseEvent().GetPosPixel() : aPosPixel);
1029 // Dragging is treated in a special way
1030 if ( meScrollType == ScrollType::Drag )
1031 ImplDragThumb( rMousePos );
1032 else
1033 ImplDoMouseAction( rMousePos, rTEvt.IsTrackingRepeat() );
1035 // If ScrollBar values are translated in a way that there's
1036 // nothing left to track, we cancel here
1037 if ( !IsVisible() || (mnVisibleSize >= (mnMaxRange-mnMinRange)) )
1038 EndTracking();
1042 void ScrollBar::KeyInput( const KeyEvent& rKEvt )
1044 if ( !rKEvt.GetKeyCode().GetModifier() )
1046 switch ( rKEvt.GetKeyCode().GetCode() )
1048 case KEY_HOME:
1049 DoScroll( 0 );
1050 break;
1052 case KEY_END:
1053 DoScroll( GetRangeMax() );
1054 break;
1056 case KEY_LEFT:
1057 case KEY_UP:
1058 DoScrollAction( ScrollType::LineUp );
1059 break;
1061 case KEY_RIGHT:
1062 case KEY_DOWN:
1063 DoScrollAction( ScrollType::LineDown );
1064 break;
1066 case KEY_PAGEUP:
1067 DoScrollAction( ScrollType::PageUp );
1068 break;
1070 case KEY_PAGEDOWN:
1071 DoScrollAction( ScrollType::PageDown );
1072 break;
1074 default:
1075 Control::KeyInput( rKEvt );
1076 break;
1079 else
1080 Control::KeyInput( rKEvt );
1083 void ScrollBar::ApplySettings(vcl::RenderContext& rRenderContext)
1085 rRenderContext.SetBackground();
1088 void ScrollBar::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
1090 ImplDraw(rRenderContext);
1093 void ScrollBar::Move()
1095 Control::Move();
1096 mbCalcSize = true;
1097 if (IsReallyVisible())
1098 ImplCalc(false);
1099 Invalidate();
1102 void ScrollBar::Resize()
1104 Control::Resize();
1105 mbCalcSize = true;
1106 if ( IsReallyVisible() )
1107 ImplCalc( false );
1108 Invalidate();
1111 IMPL_LINK_NOARG(ScrollBar, ImplAutoTimerHdl, Timer *, void)
1113 if( mpData && mpData->mbHide )
1114 return;
1115 ImplInvert();
1118 void ScrollBar::ImplInvert()
1120 tools::Rectangle aRect( maThumbRect );
1121 if( aRect.getWidth() > 4 )
1123 aRect.AdjustLeft(2 );
1124 aRect.AdjustRight( -2 );
1126 if( aRect.getHeight() > 4 )
1128 aRect.AdjustTop(2 );
1129 aRect.AdjustBottom( -2 );
1132 Invert( aRect );
1135 void ScrollBar::GetFocus()
1137 if( !mpData )
1139 mpData.reset(new ImplScrollBarData);
1140 mpData->maTimer.SetInvokeHandler( LINK( this, ScrollBar, ImplAutoTimerHdl ) );
1141 mpData->maTimer.SetDebugName( "vcl::ScrollBar mpData->maTimer" );
1142 mpData->mbHide = false;
1144 ImplInvert(); // react immediately
1145 mpData->maTimer.SetTimeout( GetSettings().GetStyleSettings().GetCursorBlinkTime() );
1146 mpData->maTimer.Start();
1147 Control::GetFocus();
1150 void ScrollBar::LoseFocus()
1152 if( mpData )
1153 mpData->maTimer.Stop();
1154 Invalidate();
1156 Control::LoseFocus();
1159 void ScrollBar::StateChanged( StateChangedType nType )
1161 Control::StateChanged( nType );
1163 if ( nType == StateChangedType::InitShow )
1164 ImplCalc( false );
1165 else if ( nType == StateChangedType::Data )
1167 if ( IsReallyVisible() && IsUpdateMode() )
1168 ImplCalc();
1170 else if ( nType == StateChangedType::UpdateMode )
1172 if ( IsReallyVisible() && IsUpdateMode() )
1174 ImplCalc( false );
1175 Invalidate();
1178 else if ( nType == StateChangedType::Enable )
1180 if ( IsReallyVisible() && IsUpdateMode() )
1181 Invalidate();
1183 else if ( nType == StateChangedType::Style )
1185 ImplInitStyle( GetStyle() );
1186 if ( IsReallyVisible() && IsUpdateMode() )
1188 if ( (GetPrevStyle() & SCRBAR_VIEW_STYLE) !=
1189 (GetStyle() & SCRBAR_VIEW_STYLE) )
1191 mbCalcSize = true;
1192 ImplCalc( false );
1193 Invalidate();
1199 void ScrollBar::DataChanged( const DataChangedEvent& rDCEvt )
1201 Control::DataChanged( rDCEvt );
1203 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1204 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
1206 mbCalcSize = true;
1207 ImplCalc( false );
1208 Invalidate();
1212 tools::Rectangle* ScrollBar::ImplFindPartRect( const Point& rPt )
1214 bool bHorizontal = ( GetStyle() & WB_HORZ ) != 0;
1215 bool bIsInside = false;
1217 Point aPoint( 0, 0 );
1218 tools::Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
1220 if( HitTestNativeScrollbar( bHorizontal? (IsRTLEnabled()? ControlPart::ButtonRight: ControlPart::ButtonLeft): ControlPart::ButtonUp,
1221 aControlRegion, rPt, bIsInside )?
1222 bIsInside:
1223 maBtn1Rect.IsInside( rPt ) )
1224 return &maBtn1Rect;
1225 else if( HitTestNativeScrollbar( bHorizontal? (IsRTLEnabled()? ControlPart::ButtonLeft: ControlPart::ButtonRight): ControlPart::ButtonDown,
1226 aControlRegion, rPt, bIsInside )?
1227 bIsInside:
1228 maBtn2Rect.IsInside( rPt ) )
1229 return &maBtn2Rect;
1230 // HitTestNativeScrollbar, see remark at top of file
1231 else if( HitTestNativeScrollbar( bHorizontal ? ControlPart::TrackHorzLeft : ControlPart::TrackVertUpper,
1232 maPage1Rect, rPt, bIsInside)?
1233 bIsInside:
1234 maPage1Rect.IsInside( rPt ) )
1235 return &maPage1Rect;
1236 // HitTestNativeScrollbar, see remark at top of file
1237 else if( HitTestNativeScrollbar( bHorizontal ? ControlPart::TrackHorzRight : ControlPart::TrackVertLower,
1238 maPage2Rect, rPt, bIsInside)?
1239 bIsInside:
1240 maPage2Rect.IsInside( rPt ) )
1241 return &maPage2Rect;
1242 // HitTestNativeScrollbar, see remark at top of file
1243 else if( HitTestNativeScrollbar( bHorizontal ? ControlPart::ThumbHorz : ControlPart::ThumbVert,
1244 maThumbRect, rPt, bIsInside)?
1245 bIsInside:
1246 maThumbRect.IsInside( rPt ) )
1247 return &maThumbRect;
1248 else
1249 return nullptr;
1252 bool ScrollBar::PreNotify( NotifyEvent& rNEvt )
1254 const MouseEvent* pMouseEvt = nullptr;
1256 if( (rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != nullptr )
1258 if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
1260 // Trigger a redraw if mouse over state has changed
1261 if( IsNativeControlSupported(ControlType::Scrollbar, ControlPart::Entire) )
1263 tools::Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
1264 tools::Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
1265 if( pRect != pLastRect || pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow() )
1267 vcl::Region aRgn( GetActiveClipRegion() );
1268 vcl::Region aClipRegion;
1270 if ( pRect )
1271 aClipRegion.Union( *pRect );
1272 if ( pLastRect )
1273 aClipRegion.Union( *pLastRect );
1275 // Support for 3-button scroll bars
1276 bool bHas3Buttons = IsNativeControlSupported( ControlType::Scrollbar, ControlPart::HasThreeButtons );
1277 if ( bHas3Buttons && ( pRect == &maBtn1Rect || pLastRect == &maBtn1Rect ) )
1279 aClipRegion.Union( maBtn2Rect );
1282 SetClipRegion( aClipRegion );
1283 Invalidate(aClipRegion.GetBoundRect());
1285 SetClipRegion( aRgn );
1291 return Control::PreNotify(rNEvt);
1294 void ScrollBar::Scroll()
1296 ImplCallEventListenersAndHandler( VclEventId::ScrollbarScroll, [this] () { maScrollHdl.Call(this); } );
1299 void ScrollBar::EndScroll()
1301 ImplCallEventListenersAndHandler( VclEventId::ScrollbarEndScroll, [this] () { maEndScrollHdl.Call(this); } );
1304 long ScrollBar::DoScroll( long nNewPos )
1306 if ( meScrollType != ScrollType::DontKnow )
1307 return 0;
1309 SAL_INFO("vcl.scrollbar", "DoScroll(" << nNewPos << ")");
1310 meScrollType = ScrollType::Drag;
1311 long nDelta = ImplScroll( nNewPos, true );
1312 meScrollType = ScrollType::DontKnow;
1313 return nDelta;
1316 long ScrollBar::DoScrollAction( ScrollType eScrollType )
1318 if ( (meScrollType != ScrollType::DontKnow) ||
1319 (eScrollType == ScrollType::DontKnow) ||
1320 (eScrollType == ScrollType::Drag) )
1321 return 0;
1323 meScrollType = eScrollType;
1324 long nDelta = ImplDoAction( true );
1325 meScrollType = ScrollType::DontKnow;
1326 return nDelta;
1329 void ScrollBar::SetRangeMin( long nNewRange )
1331 SetRange( Range( nNewRange, GetRangeMax() ) );
1334 void ScrollBar::SetRangeMax( long nNewRange )
1336 SetRange( Range( GetRangeMin(), nNewRange ) );
1339 void ScrollBar::SetRange( const Range& rRange )
1341 // Adapt Range
1342 Range aRange = rRange;
1343 aRange.Justify();
1344 long nNewMinRange = aRange.Min();
1345 long nNewMaxRange = aRange.Max();
1347 // If Range differs, set a new one
1348 if ( (mnMinRange != nNewMinRange) ||
1349 (mnMaxRange != nNewMaxRange) )
1351 mnMinRange = nNewMinRange;
1352 mnMaxRange = nNewMaxRange;
1354 // Adapt Thumb
1355 if ( mnThumbPos > mnMaxRange-mnVisibleSize )
1356 mnThumbPos = mnMaxRange-mnVisibleSize;
1357 if ( mnThumbPos < mnMinRange )
1358 mnThumbPos = mnMinRange;
1360 CompatStateChanged( StateChangedType::Data );
1364 void ScrollBar::SetThumbPos( long nNewThumbPos )
1366 if ( nNewThumbPos > mnMaxRange-mnVisibleSize )
1367 nNewThumbPos = mnMaxRange-mnVisibleSize;
1368 if ( nNewThumbPos < mnMinRange )
1369 nNewThumbPos = mnMinRange;
1371 if ( mnThumbPos != nNewThumbPos )
1373 mnThumbPos = nNewThumbPos;
1374 CompatStateChanged( StateChangedType::Data );
1378 void ScrollBar::SetVisibleSize( long nNewSize )
1380 if ( mnVisibleSize != nNewSize )
1382 mnVisibleSize = nNewSize;
1384 // Adapt Thumb
1385 if ( mnThumbPos > mnMaxRange-mnVisibleSize )
1386 mnThumbPos = mnMaxRange-mnVisibleSize;
1387 if ( mnThumbPos < mnMinRange )
1388 mnThumbPos = mnMinRange;
1389 CompatStateChanged( StateChangedType::Data );
1393 Size ScrollBar::GetOptimalSize() const
1395 if (mbCalcSize)
1396 const_cast<ScrollBar*>(this)->ImplCalc(false);
1398 Size aRet = getCurrentCalcSize();
1400 const long nMinThumbSize = GetSettings().GetStyleSettings().GetMinThumbSize();
1402 if (GetStyle() & WB_HORZ)
1404 aRet.setWidth( maBtn1Rect.GetWidth() + nMinThumbSize + maBtn2Rect.GetWidth() );
1406 else
1408 aRet.setHeight( maBtn1Rect.GetHeight() + nMinThumbSize + maBtn2Rect.GetHeight() );
1411 return aRet;
1414 Size ScrollBar::getCurrentCalcSize() const
1416 tools::Rectangle aCtrlRegion;
1417 aCtrlRegion.Union(maBtn1Rect);
1418 aCtrlRegion.Union(maBtn2Rect);
1419 aCtrlRegion.Union(maPage1Rect);
1420 aCtrlRegion.Union(maPage2Rect);
1421 aCtrlRegion.Union(maThumbRect);
1422 return aCtrlRegion.GetSize();
1425 void ScrollBarBox::ImplInit(vcl::Window* pParent, WinBits nStyle)
1427 Window::ImplInit( pParent, nStyle, nullptr );
1429 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1430 long nScrollSize = rStyleSettings.GetScrollBarSize();
1431 SetSizePixel(Size(nScrollSize, nScrollSize));
1434 ScrollBarBox::ScrollBarBox( vcl::Window* pParent, WinBits nStyle ) :
1435 Window( WindowType::SCROLLBARBOX )
1437 ImplInit( pParent, nStyle );
1440 void ScrollBarBox::ApplySettings(vcl::RenderContext& rRenderContext)
1442 if (rRenderContext.IsBackground())
1444 Color aColor = rRenderContext.GetSettings().GetStyleSettings().GetFaceColor();
1445 ApplyControlBackground(rRenderContext, aColor);
1449 void ScrollBarBox::StateChanged( StateChangedType nType )
1451 Window::StateChanged( nType );
1453 if (nType == StateChangedType::ControlBackground)
1455 Invalidate();
1459 void ScrollBarBox::DataChanged( const DataChangedEvent& rDCEvt )
1461 Window::DataChanged( rDCEvt );
1463 if ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1464 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
1466 Invalidate();
1470 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */