1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/toolkit/spin.hxx>
22 #include <vcl/settings.hxx>
23 #include <vcl/vclevent.hxx>
27 void SpinButton::ImplInit( vcl::Window
* pParent
, WinBits nStyle
)
32 mbInitialDown
= false;
39 maRepeatTimer
.SetTimeout(MouseSettings::GetButtonStartRepeat());
40 maRepeatTimer
.SetInvokeHandler(LINK(this, SpinButton
, ImplTimeout
));
42 mbRepeat
= 0 != (nStyle
& WB_REPEAT
);
44 if (nStyle
& WB_HSCROLL
)
49 Control::ImplInit( pParent
, nStyle
, nullptr );
52 SpinButton::SpinButton( vcl::Window
* pParent
, WinBits nStyle
)
53 : Control(WindowType::SPINBUTTON
)
54 , maRepeatTimer("SpinButton maRepeatTimer")
55 , mbUpperIsFocused(false)
57 ImplInit(pParent
, nStyle
);
60 IMPL_LINK(SpinButton
, ImplTimeout
, Timer
*, pTimer
, void)
62 if (pTimer
->GetTimeout() == static_cast<sal_uInt64
>(MouseSettings::GetButtonStartRepeat()))
64 pTimer
->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
78 if (ImplIsUpperEnabled())
80 mnValue
+= mnValueStep
;
81 CompatStateChanged(StateChangedType::Data
);
86 ImplCallEventListenersAndHandler(VclEventId::SpinbuttonUp
, nullptr );
89 void SpinButton::Down()
91 if (ImplIsLowerEnabled())
93 mnValue
-= mnValueStep
;
94 CompatStateChanged(StateChangedType::Data
);
99 ImplCallEventListenersAndHandler(VclEventId::SpinbuttonDown
, nullptr );
102 void SpinButton::Resize()
106 Size
aSize(GetOutputSizePixel());
107 tools::Rectangle
aRect(Point(), aSize
);
110 maLowerRect
= tools::Rectangle(0, 0, aSize
.Width() / 2, aSize
.Height() - 1);
111 maUpperRect
= tools::Rectangle(maLowerRect
.TopRight(), aRect
.BottomRight());
115 maUpperRect
= tools::Rectangle(0, 0, aSize
.Width() - 1, aSize
.Height() / 2);
116 maLowerRect
= tools::Rectangle(maUpperRect
.BottomLeft(), aRect
.BottomRight());
119 ImplCalcFocusRect(ImplIsUpperEnabled() || !ImplIsLowerEnabled());
124 void SpinButton::Draw(OutputDevice
* pDev
, const Point
& rPos
, SystemTextColorFlags nFlags
)
126 Point aPos
= pDev
->LogicToPixel(rPos
);
127 Size aSize
= GetSizePixel();
131 if ( !(nFlags
& SystemTextColorFlags::Mono
) )
133 // DecoView uses the FaceColor...
134 AllSettings aSettings
= pDev
->GetSettings();
135 StyleSettings aStyleSettings
= aSettings
.GetStyleSettings();
136 if ( IsControlBackground() )
137 aStyleSettings
.SetFaceColor( GetControlBackground() );
139 aStyleSettings
.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
141 aSettings
.SetStyleSettings( aStyleSettings
);
142 pDev
->SetSettings( aSettings
);
145 tools::Rectangle
aRect( Point( 0, 0 ), aSize
);
146 tools::Rectangle aLowerRect
, aUpperRect
;
149 aLowerRect
= tools::Rectangle( 0, 0, aSize
.Width()/2, aSize
.Height()-1 );
150 aUpperRect
= tools::Rectangle( aLowerRect
.TopRight(), aRect
.BottomRight() );
154 aUpperRect
= tools::Rectangle( 0, 0, aSize
.Width()-1, aSize
.Height()/2 );
155 aLowerRect
= tools::Rectangle( aUpperRect
.BottomLeft(), aRect
.BottomRight() );
161 ImplDrawSpinButton(*pDev
, this, aUpperRect
, aLowerRect
, false, false,
162 IsEnabled() && ImplIsUpperEnabled(),
163 IsEnabled() && ImplIsLowerEnabled(), mbHorz
, true);
167 void SpinButton::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& /*rRect*/)
171 bool bEnable
= IsEnabled();
172 ImplDrawSpinButton(rRenderContext
, this, maUpperRect
, maLowerRect
, mbUpperIn
, mbLowerIn
,
173 bEnable
&& ImplIsUpperEnabled(),
174 bEnable
&& ImplIsLowerEnabled(), mbHorz
, true);
177 ShowFocus(maFocusRect
);
180 void SpinButton::MouseButtonDown( const MouseEvent
& rMEvt
)
182 if ( maUpperRect
.Contains( rMEvt
.GetPosPixel() ) && ( ImplIsUpperEnabled() ) )
186 Invalidate( maUpperRect
);
188 else if ( maLowerRect
.Contains( rMEvt
.GetPosPixel() ) && ( ImplIsLowerEnabled() ) )
191 mbInitialDown
= true;
192 Invalidate( maLowerRect
);
195 if ( mbUpperIn
|| mbLowerIn
)
199 maRepeatTimer
.Start();
203 void SpinButton::MouseButtonUp( const MouseEvent
& )
208 maRepeatTimer
.Stop();
209 maRepeatTimer
.SetTimeout(MouseSettings::GetButtonStartRepeat() );
215 Invalidate( maUpperRect
);
218 else if ( mbLowerIn
)
221 Invalidate( maLowerRect
);
225 mbInitialUp
= mbInitialDown
= false;
228 void SpinButton::MouseMove( const MouseEvent
& rMEvt
)
230 if ( !rMEvt
.IsLeft() || (!mbInitialUp
&& !mbInitialDown
) )
233 if ( !maUpperRect
.Contains( rMEvt
.GetPosPixel() ) &&
234 mbUpperIn
&& mbInitialUp
)
237 maRepeatTimer
.Stop();
238 Invalidate( maUpperRect
);
240 else if ( !maLowerRect
.Contains( rMEvt
.GetPosPixel() ) &&
241 mbLowerIn
&& mbInitialDown
)
244 maRepeatTimer
.Stop();
245 Invalidate( maLowerRect
);
247 else if ( maUpperRect
.Contains( rMEvt
.GetPosPixel() ) &&
248 !mbUpperIn
&& mbInitialUp
)
252 maRepeatTimer
.Start();
253 Invalidate( maUpperRect
);
255 else if ( maLowerRect
.Contains( rMEvt
.GetPosPixel() ) &&
256 !mbLowerIn
&& mbInitialDown
)
260 maRepeatTimer
.Start();
261 Invalidate( maLowerRect
);
265 void SpinButton::KeyInput( const KeyEvent
& rKEvt
)
267 if ( !rKEvt
.GetKeyCode().GetModifier() )
269 switch ( rKEvt
.GetKeyCode().GetCode() )
274 bool bUp
= KEY_RIGHT
== rKEvt
.GetKeyCode().GetCode();
275 if ( mbHorz
&& !ImplMoveFocus( bUp
) )
283 bool bUp
= KEY_UP
== rKEvt
.GetKeyCode().GetCode();
284 if ( !mbHorz
&& !ImplMoveFocus( KEY_UP
== rKEvt
.GetKeyCode().GetCode() ) )
290 mbUpperIsFocused
? Up() : Down();
294 Control::KeyInput( rKEvt
);
299 Control::KeyInput( rKEvt
);
302 void SpinButton::StateChanged( StateChangedType nType
)
306 case StateChangedType::Data
:
307 case StateChangedType::Enable
:
311 case StateChangedType::Style
:
313 bool bNewRepeat
= 0 != ( GetStyle() & WB_REPEAT
);
314 if ( bNewRepeat
!= mbRepeat
)
316 if ( maRepeatTimer
.IsActive() )
318 maRepeatTimer
.Stop();
319 maRepeatTimer
.SetTimeout( MouseSettings::GetButtonStartRepeat() );
321 mbRepeat
= bNewRepeat
;
324 bool bNewHorz
= 0 != ( GetStyle() & WB_HSCROLL
);
325 if ( bNewHorz
!= mbHorz
)
335 Control::StateChanged( nType
);
338 void SpinButton::SetRangeMin( tools::Long nNewRange
)
340 SetRange( Range( nNewRange
, GetRangeMax() ) );
343 void SpinButton::SetRangeMax( tools::Long nNewRange
)
345 SetRange( Range( GetRangeMin(), nNewRange
) );
348 void SpinButton::SetRange( const Range
& rRange
)
351 Range aRange
= rRange
;
353 tools::Long nNewMinRange
= aRange
.Min();
354 tools::Long nNewMaxRange
= aRange
.Max();
356 // do something only if old and new range differ
357 if ( (mnMinRange
== nNewMinRange
) && (mnMaxRange
== nNewMaxRange
))
360 mnMinRange
= nNewMinRange
;
361 mnMaxRange
= nNewMaxRange
;
363 // adjust value to new range, if necessary
364 if ( mnValue
> mnMaxRange
)
365 mnValue
= mnMaxRange
;
366 if ( mnValue
< mnMinRange
)
367 mnValue
= mnMinRange
;
369 CompatStateChanged( StateChangedType::Data
);
372 void SpinButton::SetValue( tools::Long nValue
)
374 // adjust, if necessary
375 if ( nValue
> mnMaxRange
)
377 if ( nValue
< mnMinRange
)
380 if ( mnValue
!= nValue
)
383 CompatStateChanged( StateChangedType::Data
);
387 void SpinButton::GetFocus()
389 ShowFocus( maFocusRect
);
393 void SpinButton::LoseFocus()
396 Control::LoseFocus();
399 bool SpinButton::ImplMoveFocus( bool _bUpper
)
401 if ( _bUpper
== mbUpperIsFocused
)
405 ImplCalcFocusRect( _bUpper
);
407 ShowFocus( maFocusRect
);
411 void SpinButton::ImplCalcFocusRect( bool _bUpper
)
413 maFocusRect
= _bUpper
? maUpperRect
: maLowerRect
;
414 // inflate by some pixels
415 maFocusRect
.AdjustLeft(2 );
416 maFocusRect
.AdjustTop(2 );
417 maFocusRect
.AdjustRight( -2 );
418 maFocusRect
.AdjustBottom( -2 );
419 mbUpperIsFocused
= _bUpper
;
422 tools::Rectangle
* SpinButton::ImplFindPartRect( const Point
& rPt
)
424 if( maUpperRect
.Contains( rPt
) )
426 else if( maLowerRect
.Contains( rPt
) )
432 bool SpinButton::PreNotify( NotifyEvent
& rNEvt
)
434 if (rNEvt
.GetType() == NotifyEventType::MOUSEMOVE
)
436 const MouseEvent
* pMouseEvt
= rNEvt
.GetMouseEvent();
437 if (pMouseEvt
&& !pMouseEvt
->GetButtons() && !pMouseEvt
->IsSynthetic() && !pMouseEvt
->IsModifierChanged())
439 // trigger redraw if mouse over state has changed
440 if (IsNativeControlSupported(ControlType::Spinbox
, ControlPart::Entire
) ||
441 IsNativeControlSupported(ControlType::Spinbox
, ControlPart::AllButtons
) )
443 tools::Rectangle
* pRect
= ImplFindPartRect( GetPointerPosPixel() );
444 tools::Rectangle
* pLastRect
= ImplFindPartRect( GetLastPointerPosPixel() );
445 if (pRect
!= pLastRect
|| (pMouseEvt
->IsLeaveWindow() || pMouseEvt
->IsEnterWindow()))
447 vcl::Region
aRgn(GetOutDev()->GetActiveClipRegion());
450 GetOutDev()->SetClipRegion(vcl::Region(*pLastRect
));
451 Invalidate(*pLastRect
);
452 GetOutDev()->SetClipRegion( aRgn
);
456 GetOutDev()->SetClipRegion(vcl::Region(*pRect
));
458 GetOutDev()->SetClipRegion(aRgn
);
465 return Control::PreNotify(rNEvt
);
468 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */