LibreOffice Module vcl (master)  1
spinbtn.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <vcl/event.hxx>
21 #include <vcl/spin.hxx>
22 #include <vcl/settings.hxx>
23 #include <vcl/vclevent.hxx>
24 
25 #include <spin.hxx>
26 
27 void SpinButton::ImplInit( vcl::Window* pParent, WinBits nStyle )
28 {
29  mbUpperIn = false;
30  mbLowerIn = false;
31  mbInitialUp = false;
32  mbInitialDown = false;
33 
34  mnMinRange = 0;
35  mnMaxRange = 100;
36  mnValue = 0;
37  mnValueStep = 1;
38 
40  maRepeatTimer.SetInvokeHandler(LINK(this, SpinButton, ImplTimeout));
41 
42  mbRepeat = 0 != (nStyle & WB_REPEAT);
43 
44  if (nStyle & WB_HSCROLL)
45  mbHorz = true;
46  else
47  mbHorz = false;
48 
49  Control::ImplInit( pParent, nStyle, nullptr );
50 }
51 
54  , mbUpperIsFocused(false)
55 {
56  ImplInit(pParent, nStyle);
57 }
58 
59 IMPL_LINK(SpinButton, ImplTimeout, Timer*, pTimer, void)
60 {
61  if (pTimer->GetTimeout() == MouseSettings::GetButtonStartRepeat())
62  {
63  pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
64  pTimer->Start();
65  }
66  else
67  {
68  if (mbInitialUp)
69  Up();
70  else
71  Down();
72  }
73 }
74 
76 {
77  if (ImplIsUpperEnabled())
78  {
81 
82  ImplMoveFocus(true);
83  }
84 
86 }
87 
89 {
90  if (ImplIsLowerEnabled())
91  {
94 
95  ImplMoveFocus(false);
96  }
97 
99 }
100 
102 {
103  Control::Resize();
104 
105  Size aSize(GetOutputSizePixel());
106  tools::Rectangle aRect(Point(), aSize);
107  if (mbHorz)
108  {
109  maLowerRect = tools::Rectangle(0, 0, aSize.Width() / 2, aSize.Height() - 1);
111  }
112  else
113  {
114  maUpperRect = tools::Rectangle(0, 0, aSize.Width() - 1, aSize.Height() / 2);
116  }
117 
119 
120  Invalidate();
121 }
122 
123 void SpinButton::Draw(OutputDevice* pDev, const Point& rPos, const Size& rSize, DrawFlags nFlags)
124 {
125  Point aPos = pDev->LogicToPixel(rPos);
126  Size aSize = pDev->LogicToPixel(rSize);
127 
128  pDev->Push();
129  pDev->SetMapMode();
130  if ( !(nFlags & DrawFlags::Mono) )
131  {
132  // DecoView uses the FaceColor...
133  AllSettings aSettings = pDev->GetSettings();
134  StyleSettings aStyleSettings = aSettings.GetStyleSettings();
135  if ( IsControlBackground() )
136  aStyleSettings.SetFaceColor( GetControlBackground() );
137  else
138  aStyleSettings.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
139 
140  aSettings.SetStyleSettings( aStyleSettings );
141  pDev->SetSettings( aSettings );
142  }
143 
144  tools::Rectangle aRect( Point( 0, 0 ), aSize );
145  tools::Rectangle aLowerRect, aUpperRect;
146  if ( mbHorz )
147  {
148  aLowerRect = tools::Rectangle( 0, 0, aSize.Width()/2, aSize.Height()-1 );
149  aUpperRect = tools::Rectangle( aLowerRect.TopRight(), aRect.BottomRight() );
150  }
151  else
152  {
153  aUpperRect = tools::Rectangle( 0, 0, aSize.Width()-1, aSize.Height()/2 );
154  aLowerRect = tools::Rectangle( aUpperRect.BottomLeft(), aRect.BottomRight() );
155  }
156 
157  aUpperRect += aPos;
158  aLowerRect += aPos;
159 
160  ImplDrawSpinButton(*pDev, this, aUpperRect, aLowerRect, false, false,
162  IsEnabled() && ImplIsLowerEnabled(), mbHorz, true);
163  pDev->Pop();
164 }
165 
166 void SpinButton::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
167 {
168  HideFocus();
169 
170  bool bEnable = IsEnabled();
172  bEnable && ImplIsUpperEnabled(),
173  bEnable && ImplIsLowerEnabled(), mbHorz, true);
174 
175  if (HasFocus())
177 }
178 
180 {
181  if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) && ( ImplIsUpperEnabled() ) )
182  {
183  mbUpperIn = true;
184  mbInitialUp = true;
186  }
187  else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) && ( ImplIsLowerEnabled() ) )
188  {
189  mbLowerIn = true;
190  mbInitialDown = true;
192  }
193 
194  if ( mbUpperIn || mbLowerIn )
195  {
196  Update();
197  CaptureMouse();
198  if ( mbRepeat )
200  }
201 }
202 
204 {
205  ReleaseMouse();
206  if ( mbRepeat )
207  {
210  }
211 
212  if ( mbUpperIn )
213  {
214  mbUpperIn = false;
216  Update();
217  Up();
218  }
219  else if ( mbLowerIn )
220  {
221  mbLowerIn = false;
223  Update();
224  Down();
225  }
226 
227  mbInitialUp = mbInitialDown = false;
228 }
229 
230 void SpinButton::MouseMove( const MouseEvent& rMEvt )
231 {
232  if ( !rMEvt.IsLeft() || (!mbInitialUp && !mbInitialDown) )
233  return;
234 
235  if ( !maUpperRect.IsInside( rMEvt.GetPosPixel() ) &&
237  {
238  mbUpperIn = false;
241  Update();
242  }
243  else if ( !maLowerRect.IsInside( rMEvt.GetPosPixel() ) &&
245  {
246  mbLowerIn = false;
249  Update();
250  }
251  else if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) &&
252  !mbUpperIn && mbInitialUp )
253  {
254  mbUpperIn = true;
255  if ( mbRepeat )
258  Update();
259  }
260  else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) &&
262  {
263  mbLowerIn = true;
264  if ( mbRepeat )
267  Update();
268  }
269 }
270 
271 void SpinButton::KeyInput( const KeyEvent& rKEvt )
272 {
273  if ( !rKEvt.GetKeyCode().GetModifier() )
274  {
275  switch ( rKEvt.GetKeyCode().GetCode() )
276  {
277  case KEY_LEFT:
278  case KEY_RIGHT:
279  {
280  bool bUp = KEY_RIGHT == rKEvt.GetKeyCode().GetCode();
281  if ( mbHorz && !ImplMoveFocus( bUp ) )
282  bUp ? Up() : Down();
283  }
284  break;
285 
286  case KEY_UP:
287  case KEY_DOWN:
288  {
289  bool bUp = KEY_UP == rKEvt.GetKeyCode().GetCode();
290  if ( !mbHorz && !ImplMoveFocus( KEY_UP == rKEvt.GetKeyCode().GetCode() ) )
291  bUp ? Up() : Down();
292  }
293  break;
294 
295  case KEY_SPACE:
296  mbUpperIsFocused ? Up() : Down();
297  break;
298 
299  default:
300  Control::KeyInput( rKEvt );
301  break;
302  }
303  }
304  else
305  Control::KeyInput( rKEvt );
306 }
307 
309 {
310  switch ( nType )
311  {
314  Invalidate();
315  break;
316 
318  {
319  bool bNewRepeat = 0 != ( GetStyle() & WB_REPEAT );
320  if ( bNewRepeat != mbRepeat )
321  {
322  if ( maRepeatTimer.IsActive() )
323  {
326  }
327  mbRepeat = bNewRepeat;
328  }
329 
330  bool bNewHorz = 0 != ( GetStyle() & WB_HSCROLL );
331  if ( bNewHorz != mbHorz )
332  {
333  mbHorz = bNewHorz;
334  Resize();
335  }
336  }
337  break;
338  default:;
339  }
340 
341  Control::StateChanged( nType );
342 }
343 
344 void SpinButton::SetRangeMin( long nNewRange )
345 {
346  SetRange( Range( nNewRange, GetRangeMax() ) );
347 }
348 
349 void SpinButton::SetRangeMax( long nNewRange )
350 {
351  SetRange( Range( GetRangeMin(), nNewRange ) );
352 }
353 
354 void SpinButton::SetRange( const Range& rRange )
355 {
356  // adjust rage
357  Range aRange = rRange;
358  aRange.Justify();
359  long nNewMinRange = aRange.Min();
360  long nNewMaxRange = aRange.Max();
361 
362  // do something only if old and new range differ
363  if ( (mnMinRange != nNewMinRange) ||
364  (mnMaxRange != nNewMaxRange) )
365  {
366  mnMinRange = nNewMinRange;
367  mnMaxRange = nNewMaxRange;
368 
369  // adjust value to new range, if necessary
370  if ( mnValue > mnMaxRange )
372  if ( mnValue < mnMinRange )
374 
376  }
377 }
378 
379 void SpinButton::SetValue( long nValue )
380 {
381  // adjust, if necessary
382  if ( nValue > mnMaxRange )
383  nValue = mnMaxRange;
384  if ( nValue < mnMinRange )
385  nValue = mnMinRange;
386 
387  if ( mnValue != nValue )
388  {
389  mnValue = nValue;
391  }
392 }
393 
395 {
398 }
399 
401 {
402  HideFocus();
404 }
405 
406 bool SpinButton::ImplMoveFocus( bool _bUpper )
407 {
408  if ( _bUpper == mbUpperIsFocused )
409  return false;
410 
411  HideFocus();
412  ImplCalcFocusRect( _bUpper );
413  if ( HasFocus() )
415  return true;
416 }
417 
418 void SpinButton::ImplCalcFocusRect( bool _bUpper )
419 {
420  maFocusRect = _bUpper ? maUpperRect : maLowerRect;
421  // inflate by some pixels
424  maFocusRect.AdjustRight( -2 );
426  mbUpperIsFocused = _bUpper;
427 }
428 
430 {
431  if( maUpperRect.IsInside( rPt ) )
432  return &maUpperRect;
433  else if( maLowerRect.IsInside( rPt ) )
434  return &maLowerRect;
435  else
436  return nullptr;
437 }
438 
440 {
441  const MouseEvent* pMouseEvt = nullptr;
442 
443  if ((rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != nullptr)
444  {
445  if (!pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged())
446  {
447  // trigger redraw if mouse over state has changed
450  {
453  if (pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()))
454  {
456  if (pLastRect)
457  {
458  SetClipRegion(vcl::Region(*pLastRect));
459  Invalidate(*pLastRect);
460  SetClipRegion( aRgn );
461  }
462  if (pRect)
463  {
464  SetClipRegion(vcl::Region(*pRect));
465  Invalidate(*pRect);
466  SetClipRegion(aRgn);
467  }
468  }
469  }
470  }
471  }
472 
473  return Control::PreNotify(rNEvt);
474 }
475 
476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SAL_DLLPRIVATE bool ImplIsUpperEnabled() const
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: spinbtn.cxx:439
long Width() const
bool IsControlBackground() const
Definition: window2.cxx:1081
bool ImplCallEventListenersAndHandler(VclEventId nEvent, std::function< void()> const &callHandler)
this calls both our event listeners, and a specified handler
Definition: ctrl.cxx:305
void CaptureMouse()
Definition: mouse.cxx:438
Point GetPointerPosPixel()
Definition: mouse.cxx:548
void HideFocus()
Definition: window2.cxx:91
#define KEY_SPACE
Definition: keycodes.hxx:123
virtual void KeyInput(const KeyEvent &rKEvt) override
Definition: spinbtn.cxx:271
void SetRangeMin(long nNewRange)
Definition: spinbtn.cxx:344
void SetStyleSettings(const StyleSettings &rSet)
long Height() const
void ImplDrawSpinButton(vcl::RenderContext &rRenderContext, vcl::Window *pWindow, const tools::Rectangle &rUpperRect, const tools::Rectangle &rLowerRect, bool bUpperIn, bool bLowerIn, bool bUpperEnabled, bool bLowerEnabled, bool bHorz, bool bMirrorHorz)
Definition: spinfld.cxx:157
Point BottomLeft() const
long AdjustLeft(long nHorzMoveDelta)
const StyleSettings & GetStyleSettings() const
virtual void StateChanged(StateChangedType nStateChange) override
Definition: ctrl.cxx:260
virtual void LoseFocus() override
Definition: spinbtn.cxx:400
void CompatStateChanged(StateChangedType nStateChange)
Definition: window.cxx:3730
sal_uInt16 GetCode() const
Definition: keycod.hxx:53
virtual void SetSettings(const AllSettings &rSettings)
Definition: outdev.cxx:213
const Color & GetControlBackground() const
Definition: window2.cxx:1076
virtual void GetFocus() override
Definition: spinbtn.cxx:394
long GetRangeMax() const
#define KEY_LEFT
Definition: keycodes.hxx:112
bool IsNativeControlSupported(ControlType nType, ControlPart nPart) const
Query the platform layer for control support.
void SetMapMode()
Definition: map.cxx:655
long AdjustBottom(long nVertMoveDelta)
bool IsActive() const
Definition: task.hxx:91
StateChangedType
Definition: window.hxx:309
SpinButton(vcl::Window *pParent, WinBits nStyle)
Definition: spinbtn.cxx:52
sal_Int64 WinBits
virtual void MouseMove(const MouseEvent &rMEvt) override
Definition: spinbtn.cxx:230
sal_uInt16 GetButtons() const
Definition: event.hxx:131
void SetRange(const Range &rRange)
Definition: spinbtn.cxx:354
void Down()
Definition: spinbtn.cxx:88
bool IsEnterWindow() const
Definition: event.hxx:122
WinBits const WB_HSCROLL
AutoTimer maRepeatTimer
sal_uInt16 GetModifier() const
Definition: keycod.hxx:56
virtual void Draw(OutputDevice *pDev, const Point &rPos, const Size &rSize, DrawFlags nFlags) override
Definition: spinbtn.cxx:123
tools::Rectangle maFocusRect
void Update()
Definition: paint.cxx:1273
virtual void Resize() override
Definition: spinbtn.cxx:101
void Justify()
Point BottomRight() const
virtual bool PreNotify(NotifyEvent &rNEvt)
Definition: event.cxx:51
SAL_DLLPRIVATE void ImplCalcFocusRect(bool _bUpper)
Definition: spinbtn.cxx:418
bool IsLeaveWindow() const
Definition: event.hxx:124
DrawFlags
Definition: window.hxx:352
tools::Rectangle maUpperRect
virtual void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
Definition: paint.cxx:1153
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:304
SAL_DLLPRIVATE tools::Rectangle * ImplFindPartRect(const Point &rPt)
Definition: spinbtn.cxx:429
virtual void Start() override
Activates the timer task.
Definition: timer.cxx:83
MouseNotifyEvent GetType() const
Definition: event.hxx:294
bool IsInside(const Point &rPOINT) const
void Up()
Definition: spinbtn.cxx:75
const AllSettings & GetSettings() const
Definition: outdev.hxx:420
Size GetOutputSizePixel() const
Definition: outdev.hxx:441
tools::Rectangle maLowerRect
virtual void LoseFocus()
Definition: window.cxx:1818
void SetTimeout(sal_uInt64 nTimeoutMs)
Definition: timer.cxx:89
SAL_DLLPRIVATE bool ImplIsLowerEnabled() const
virtual void ShowFocus(const tools::Rectangle &rRect)
Definition: window2.cxx:49
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect) override
Definition: spinbtn.cxx:166
WinBits const WB_REPEAT
Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:940
void ReleaseMouse()
Definition: mouse.cxx:457
virtual void KeyInput(const KeyEvent &rKEvt)
Definition: window.cxx:1767
SAL_DLLPRIVATE void ImplInit(vcl::Window *pParent, WinBits nStyle, SystemParentData *pSystemParentData)
Definition: window.cxx:930
bool IsModifierChanged() const
Definition: event.hxx:128
long Max() const
long GetRangeMin() const
const vcl::KeyCode & GetKeyCode() const
Definition: event.hxx:53
void SetFaceColor(const Color &rColor)
virtual void Resize() override
Definition: ctrl.cxx:74
#define KEY_DOWN
Definition: keycodes.hxx:110
void SetValue(long nValue)
Definition: spinbtn.cxx:379
long AdjustRight(long nHorzMoveDelta)
void Stop()
Definition: scheduler.cxx:594
WindowType
Definition: ctrl.hxx:33
bool IsSynthetic() const
Definition: event.hxx:126
virtual void GetFocus()
Definition: window.cxx:1804
SAL_DLLPRIVATE void ImplInit(vcl::Window *pParent, WinBits nStyle)
Definition: spinbtn.cxx:27
SAL_DLLPRIVATE bool ImplMoveFocus(bool _bUpper)
Definition: spinbtn.cxx:406
const MouseEvent * GetMouseEvent() const
Definition: event.hxx:310
bool IsLeft() const
Definition: event.hxx:133
long AdjustTop(long nVertMoveDelta)
void SetInvokeHandler(const Link< Timer *, void > &rLink)
Definition: timer.hxx:57
const Point & GetPosPixel() const
Definition: event.hxx:117
IMPL_LINK(SpinButton, ImplTimeout, Timer *, pTimer, void)
Definition: spinbtn.cxx:59
virtual vcl::Region GetActiveClipRegion() const override
bool IsEnabled() const
Definition: window2.cxx:1116
virtual void MouseButtonDown(const MouseEvent &rMEvt) override
Definition: spinbtn.cxx:179
virtual void MouseButtonUp(const MouseEvent &rMEvt) override
Definition: spinbtn.cxx:203
WinBits GetStyle() const
Definition: window2.cxx:947
Definition: timer.hxx:26
Point GetLastPointerPosPixel()
Definition: mouse.cxx:560
long Min() const
bool HasFocus() const
Definition: window.cxx:2985
void Push(PushFlags nFlags=PushFlags::ALL)
Definition: outdevstate.cxx:60
Point TopRight() const
#define KEY_RIGHT
Definition: keycodes.hxx:113
void SetRangeMax(long nNewRange)
Definition: spinbtn.cxx:349
virtual void StateChanged(StateChangedType nStateChange) override
Definition: spinbtn.cxx:308
#define KEY_UP
Definition: keycodes.hxx:111
static sal_uLong GetButtonStartRepeat()