LibreOffice Module vcl (master)  1
spinfld.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/commandevent.hxx>
21 #include <vcl/event.hxx>
22 #include <vcl/decoview.hxx>
23 #include <vcl/toolkit/spinfld.hxx>
24 #include <vcl/settings.hxx>
25 #include <vcl/uitest/uiobject.hxx>
26 #include <sal/log.hxx>
27 
28 #include <spin.hxx>
29 #include <svdata.hxx>
30 
31 namespace {
32 
33 void ImplGetSpinbuttonValue(vcl::Window* pWin,
34  const tools::Rectangle& rUpperRect, const tools::Rectangle& rLowerRect,
35  bool bUpperIn, bool bLowerIn, bool bUpperEnabled, bool bLowerEnabled,
36  bool bHorz, SpinbuttonValue& rValue )
37 {
38  // convert spinbutton data to a SpinbuttonValue structure for native painting
39 
40  rValue.maUpperRect = rUpperRect;
41  rValue.maLowerRect = rLowerRect;
42 
43  Point aPointerPos = pWin->GetPointerPosPixel();
44 
46  if (bUpperIn)
47  nState |= ControlState::PRESSED;
48  if (!pWin->IsEnabled() || !bUpperEnabled)
49  nState &= ~ControlState::ENABLED;
50  if (pWin->HasFocus())
51  nState |= ControlState::FOCUSED;
52  if (pWin->IsMouseOver() && rUpperRect.Contains(aPointerPos))
53  nState |= ControlState::ROLLOVER;
54  rValue.mnUpperState = nState;
55 
56  nState = ControlState::ENABLED;
57  if (bLowerIn)
58  nState |= ControlState::PRESSED;
59  if (!pWin->IsEnabled() || !bLowerEnabled)
60  nState &= ~ControlState::ENABLED;
61  if (pWin->HasFocus())
62  nState |= ControlState::FOCUSED;
63  // for overlapping spins: highlight only one
64  if (pWin->IsMouseOver() && rLowerRect.Contains(aPointerPos) && !rUpperRect.Contains(aPointerPos))
65  nState |= ControlState::ROLLOVER;
66  rValue.mnLowerState = nState;
67 
70 }
71 
72 bool ImplDrawNativeSpinfield(vcl::RenderContext& rRenderContext, vcl::Window const * pWin, const SpinbuttonValue& rSpinbuttonValue)
73 {
74  bool bNativeOK = false;
75 
77  // there is just no useful native support for spinfields with dropdown
78  !(pWin->GetStyle() & WB_DROPDOWN))
79  {
80  if (rRenderContext.IsNativeControlSupported(ControlType::Spinbox, rSpinbuttonValue.mnUpperPart) &&
81  rRenderContext.IsNativeControlSupported(ControlType::Spinbox, rSpinbuttonValue.mnLowerPart))
82  {
83  // only paint the embedded spin buttons, all buttons are painted at once
84  tools::Rectangle aUpperAndLowerButtons( rSpinbuttonValue.maUpperRect.GetUnion( rSpinbuttonValue.maLowerRect ) );
85  bNativeOK = rRenderContext.DrawNativeControl(ControlType::Spinbox, ControlPart::AllButtons, aUpperAndLowerButtons,
86  ControlState::ENABLED, rSpinbuttonValue, OUString());
87  }
88  else
89  {
90  // paint the spinbox as a whole, use borderwindow to have proper clipping
92 
93  // to not overwrite everything, set the button region as clipregion to the border window
94  tools::Rectangle aClipRect(rSpinbuttonValue.maLowerRect);
95  aClipRect.Union(rSpinbuttonValue.maUpperRect);
96 
97  vcl::RenderContext* pContext = &rRenderContext;
98  vcl::Region oldRgn;
99  Point aPt;
100  Size aSize(pBorder->GetOutputSizePixel()); // the size of the border window, i.e., the whole control
101  tools::Rectangle aNatRgn(aPt, aSize);
102 
103  if (!pWin->SupportsDoubleBuffering())
104  {
105  // convert from screen space to borderwin space
106  aClipRect.SetPos(pBorder->ScreenToOutputPixel(pWin->OutputToScreenPixel(aClipRect.TopLeft())));
107 
108  oldRgn = pBorder->GetOutDev()->GetClipRegion();
109  pBorder->GetOutDev()->SetClipRegion(vcl::Region(aClipRect));
110 
111  pContext = pBorder->GetOutDev();
112  }
113 
114  tools::Rectangle aBound, aContent;
115  if (!ImplGetSVData()->maNWFData.mbCanDrawWidgetAnySize &&
117  aNatRgn, ControlState::NONE, rSpinbuttonValue,
118  aBound, aContent))
119  {
120  aSize = aContent.GetSize();
121  }
122 
123  tools::Rectangle aRgn(aPt, aSize);
124  if (pWin->SupportsDoubleBuffering())
125  {
126  // convert from borderwin space, to the pWin's space
127  aRgn.SetPos(pWin->ScreenToOutputPixel(pBorder->OutputToScreenPixel(aRgn.TopLeft())));
128  }
129 
130  bNativeOK = pContext->DrawNativeControl(ControlType::Spinbox, ControlPart::Entire, aRgn,
131  ControlState::ENABLED, rSpinbuttonValue, OUString());
132 
133  if (!pWin->SupportsDoubleBuffering())
134  pBorder->GetOutDev()->SetClipRegion(oldRgn);
135  }
136  }
137  return bNativeOK;
138 }
139 
140 bool ImplDrawNativeSpinbuttons(vcl::RenderContext& rRenderContext, const SpinbuttonValue& rSpinbuttonValue)
141 {
142  bool bNativeOK = false;
143 
145  {
146  tools::Rectangle aArea = rSpinbuttonValue.maUpperRect.GetUnion(rSpinbuttonValue.maLowerRect);
147  // only paint the standalone spin buttons, all buttons are painted at once
148  bNativeOK = rRenderContext.DrawNativeControl(ControlType::SpinButtons, ControlPart::AllButtons, aArea,
149  ControlState::ENABLED, rSpinbuttonValue, OUString());
150  }
151  return bNativeOK;
152 }
153 
154 }
155 
156 void ImplDrawSpinButton(vcl::RenderContext& rRenderContext, vcl::Window* pWindow,
157  const tools::Rectangle& rUpperRect, const tools::Rectangle& rLowerRect,
158  bool bUpperIn, bool bLowerIn, bool bUpperEnabled, bool bLowerEnabled,
159  bool bHorz, bool bMirrorHorz)
160 {
161  bool bNativeOK = false;
162 
163  if (pWindow)
164  {
165  // are we drawing standalone spin buttons or members of a spinfield ?
167  switch (pWindow->GetType())
168  {
169  case WindowType::EDIT:
170  case WindowType::MULTILINEEDIT:
171  case WindowType::PATTERNFIELD:
172  case WindowType::METRICFIELD:
173  case WindowType::CURRENCYFIELD:
174  case WindowType::DATEFIELD:
175  case WindowType::TIMEFIELD:
176  case WindowType::SPINFIELD:
177  case WindowType::FORMATTEDFIELD:
178  aControl = ControlType::Spinbox;
179  break;
180  default:
181  aControl = ControlType::SpinButtons;
182  break;
183  }
184 
185  SpinbuttonValue aValue;
186  ImplGetSpinbuttonValue(pWindow, rUpperRect, rLowerRect,
187  bUpperIn, bLowerIn, bUpperEnabled, bLowerEnabled,
188  bHorz, aValue);
189 
190  if( aControl == ControlType::Spinbox )
191  bNativeOK = ImplDrawNativeSpinfield(rRenderContext, pWindow, aValue);
192  else if( aControl == ControlType::SpinButtons )
193  bNativeOK = ImplDrawNativeSpinbuttons(rRenderContext, aValue);
194  }
195 
196  if (bNativeOK)
197  return;
198 
199  ImplDrawUpDownButtons(rRenderContext,
200  rUpperRect, rLowerRect,
201  bUpperIn, bLowerIn, bUpperEnabled, bLowerEnabled,
202  bHorz, bMirrorHorz);
203 }
204 
206  const tools::Rectangle& rUpperRect, const tools::Rectangle& rLowerRect,
207  bool bUpperIn, bool bLowerIn, bool bUpperEnabled, bool bLowerEnabled,
208  bool bHorz, bool bMirrorHorz)
209 {
210  DecorationView aDecoView(&rRenderContext);
211 
212  SymbolType eType1, eType2;
213 
214  if ( bHorz )
215  {
216  eType1 = bMirrorHorz ? SymbolType::SPIN_RIGHT : SymbolType::SPIN_LEFT;
217  eType2 = bMirrorHorz ? SymbolType::SPIN_LEFT : SymbolType::SPIN_RIGHT;
218  }
219  else
220  {
221  eType1 = SymbolType::SPIN_UP;
222  eType2 = SymbolType::SPIN_DOWN;
223  }
224 
226  // draw upper/left Button
227  if (bUpperIn)
228  nStyle |= DrawButtonFlags::Pressed;
229 
230  tools::Rectangle aUpRect = aDecoView.DrawButton(rUpperRect, nStyle);
231 
233  // draw lower/right Button
234  if (bLowerIn)
235  nStyle |= DrawButtonFlags::Pressed;
236 
237  tools::Rectangle aLowRect = aDecoView.DrawButton(rLowerRect, nStyle);
238 
239  // make use of additional default edge
240  aUpRect.AdjustLeft( -1 );
241  aUpRect.AdjustTop( -1 );
242  aUpRect.AdjustRight( 1 );
243  aUpRect.AdjustBottom( 1 );
244  aLowRect.AdjustLeft( -1 );
245  aLowRect.AdjustTop( -1 );
246  aLowRect.AdjustRight( 1 );
247  aLowRect.AdjustBottom( 1 );
248 
249  // draw into the edge, so that something is visible if the rectangle is too small
250  if (aUpRect.GetHeight() < 4)
251  {
252  aUpRect.AdjustRight( 1 );
253  aUpRect.AdjustBottom( 1 );
254  aLowRect.AdjustRight( 1 );
255  aLowRect.AdjustBottom( 1 );
256  }
257 
258  // calculate Symbol size
259  tools::Long nTempSize1 = aUpRect.GetWidth();
260  tools::Long nTempSize2 = aLowRect.GetWidth();
261  if (std::abs( nTempSize1-nTempSize2 ) == 1)
262  {
263  if (nTempSize1 > nTempSize2)
264  aUpRect.AdjustLeft( 1 );
265  else
266  aLowRect.AdjustLeft( 1 );
267  }
268  nTempSize1 = aUpRect.GetHeight();
269  nTempSize2 = aLowRect.GetHeight();
270  if (std::abs(nTempSize1 - nTempSize2) == 1)
271  {
272  if (nTempSize1 > nTempSize2)
273  aUpRect.AdjustTop( 1 );
274  else
275  aLowRect.AdjustTop( 1 );
276  }
277 
278  const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
279 
281  if (!bUpperEnabled)
282  nSymStyle |= DrawSymbolFlags::Disable;
283  aDecoView.DrawSymbol(aUpRect, eType1, rStyleSettings.GetButtonTextColor(), nSymStyle);
284 
285  nSymStyle = DrawSymbolFlags::NONE;
286  if (!bLowerEnabled)
287  nSymStyle |= DrawSymbolFlags::Disable;
288  aDecoView.DrawSymbol(aLowRect, eType2, rStyleSettings.GetButtonTextColor(), nSymStyle);
289 }
290 
292 {
294  mbSpin = false;
295  mbRepeat = false;
296  mbUpperIn = false;
297  mbLowerIn = false;
298  mbInitialUp = false;
299  mbInitialDown = false;
300  mbInDropDown = false;
301 }
302 
303 void SpinField::ImplInit(vcl::Window* pParent, WinBits nWinStyle)
304 {
305  Edit::ImplInit( pParent, nWinStyle );
306 
307  if (!(nWinStyle & (WB_SPIN | WB_DROPDOWN)))
308  return;
309 
310  mbSpin = true;
311 
312  // Some themes want external spin buttons, therefore the main
313  // spinfield should not overdraw the border between its encapsulated
314  // edit field and the spin buttons
315  if ((nWinStyle & WB_SPIN) && ImplUseNativeBorder(*GetOutDev(), nWinStyle))
316  {
317  SetBackground();
320  }
321  else
323 
324  mpEdit->EnableRTL(false);
326  mpEdit->Show();
327 
329 
330  maRepeatTimer.SetInvokeHandler(LINK( this, SpinField, ImplTimeout));
332  if (nWinStyle & WB_REPEAT)
333  mbRepeat = true;
334 
335  SetCompoundControl(true);
336 }
337 
338 SpinField::SpinField(vcl::Window* pParent, WinBits nWinStyle, WindowType nType) :
339  Edit(nType)
340 {
342  ImplInit(pParent, nWinStyle);
343 }
344 
346 {
347  disposeOnce();
348 }
349 
351 {
353 
354  Edit::dispose();
355 }
356 
358 {
360 }
361 
363 {
365 }
366 
368 {
370 }
371 
373 {
375 }
376 
378 {
379  if (!HasFocus() && (!mpEdit || !mpEdit->HasFocus()))
380  {
381  GrabFocus();
382  }
383 
384  if (!IsReadOnly())
385  {
386  if (maUpperRect.Contains(rMEvt.GetPosPixel()))
387  {
388  mbUpperIn = true;
389  mbInitialUp = true;
391  }
392  else if (maLowerRect.Contains(rMEvt.GetPosPixel()))
393  {
394  mbLowerIn = true;
395  mbInitialDown = true;
397  }
398  else if (maDropDownRect.Contains(rMEvt.GetPosPixel()))
399  {
400  // put DropDownButton to the right
403  }
404 
405  if (mbUpperIn || mbLowerIn)
406  {
407  CaptureMouse();
408  if (mbRepeat)
410  return;
411  }
412  }
413 
414  Edit::MouseButtonDown(rMEvt);
415 }
416 
418 {
419  ReleaseMouse();
420  mbInitialUp = mbInitialDown = false;
423 
424  if (mbUpperIn)
425  {
426  mbUpperIn = false;
428  Up();
429  }
430  else if (mbLowerIn)
431  {
432  mbLowerIn = false;
434  Down();
435  }
436 
437  Edit::MouseButtonUp(rMEvt);
438 }
439 
441 {
442  if (rMEvt.IsLeft())
443  {
444  if (mbInitialUp)
445  {
446  bool bNewUpperIn = maUpperRect.Contains(rMEvt.GetPosPixel());
447  if (bNewUpperIn != mbUpperIn)
448  {
449  if (bNewUpperIn)
450  {
451  if (mbRepeat)
453  }
454  else
456 
457  mbUpperIn = bNewUpperIn;
459  }
460  }
461  else if (mbInitialDown)
462  {
463  bool bNewLowerIn = maLowerRect.Contains(rMEvt.GetPosPixel());
464  if (bNewLowerIn != mbLowerIn)
465  {
466  if (bNewLowerIn)
467  {
468  if (mbRepeat)
470  }
471  else
473 
474  mbLowerIn = bNewLowerIn;
476  }
477  }
478  }
479 
480  Edit::MouseMove(rMEvt);
481 }
482 
484 {
485  bool bDone = false;
486  if (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
487  {
488  const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
489  if (!IsReadOnly())
490  {
491  sal_uInt16 nMod = rKEvt.GetKeyCode().GetModifier();
492  switch (rKEvt.GetKeyCode().GetCode())
493  {
494  case KEY_UP:
495  {
496  if (!nMod)
497  {
498  Up();
499  bDone = true;
500  }
501  }
502  break;
503  case KEY_DOWN:
504  {
505  if (!nMod)
506  {
507  Down();
508  bDone = true;
509  }
510  else if ((nMod == KEY_MOD2) && !mbInDropDown && (GetStyle() & WB_DROPDOWN))
511  {
512  mbInDropDown = ShowDropDown(true);
514  bDone = true;
515  }
516  }
517  break;
518  case KEY_PAGEUP:
519  {
520  if (!nMod)
521  {
522  Last();
523  bDone = true;
524  }
525  }
526  break;
527  case KEY_PAGEDOWN:
528  {
529  if (!nMod)
530  {
531  First();
532  bDone = true;
533  }
534  }
535  break;
536  }
537  }
538  }
539 
540  if (rNEvt.GetType() == MouseNotifyEvent::COMMAND)
541  {
543  {
544  MouseWheelBehaviour nWheelBehavior(GetSettings().GetMouseSettings().GetWheelBehavior());
545  if (nWheelBehavior == MouseWheelBehaviour::ALWAYS
546  || (nWheelBehavior == MouseWheelBehaviour::FocusOnly && HasChildPathFocus()))
547  {
549  if (pData->GetMode() == CommandWheelMode::SCROLL)
550  {
551  if (pData->GetDelta() < 0)
552  Down();
553  else
554  Up();
555  bDone = true;
556 
557  if (!HasChildPathFocus())
558  GrabFocus();
559  }
560  }
561  else
562  bDone = false; // don't eat this event, let the default handling happen (i.e. scroll the context)
563  }
564  }
565 
566  return bDone || Edit::EventNotify(rNEvt);
567 }
568 
570 {
571  if (mbSpin)
572  {
573  mxLayoutData.emplace();
576  }
577  else
579 }
580 
581 void SpinField::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
582 {
583  if (mbSpin)
584  {
585  bool bEnable = IsEnabled();
586  ImplDrawSpinButton(rRenderContext, this, maUpperRect, maLowerRect,
587  mbUpperIn, mbLowerIn, bEnable, bEnable);
588  }
589 
590  if (GetStyle() & WB_DROPDOWN)
591  {
592  DecorationView aView(&rRenderContext);
593 
595  if (mbInDropDown)
596  nStyle |= DrawButtonFlags::Pressed;
597  tools::Rectangle aInnerRect = aView.DrawButton(maDropDownRect, nStyle);
598 
600  aView.DrawSymbol(aInnerRect, SymbolType::SPIN_DOWN, rRenderContext.GetSettings().GetStyleSettings().GetButtonTextColor(), nSymbolStyle);
601  }
602 
603  Edit::Paint(rRenderContext, rRect);
604 }
605 
606 void SpinField::ImplCalcButtonAreas(const OutputDevice* pDev, const Size& rOutSz, tools::Rectangle& rDDArea,
607  tools::Rectangle& rSpinUpArea, tools::Rectangle& rSpinDownArea)
608 {
609  const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings();
610 
611  Size aSize = rOutSz;
612  Size aDropDownSize;
613 
614  if (GetStyle() & WB_DROPDOWN)
615  {
616  tools::Long nW = rStyleSettings.GetScrollBarSize();
617  nW = GetDrawPixel( pDev, nW );
618  aDropDownSize = Size( CalcZoom( nW ), aSize.Height() );
619  aSize.AdjustWidth( -(aDropDownSize.Width()) );
620  rDDArea = tools::Rectangle( Point( aSize.Width(), 0 ), aDropDownSize );
621  rDDArea.AdjustTop( -1 );
622  }
623  else
624  rDDArea.SetEmpty();
625 
626  // calculate sizes according to the height
627  if (GetStyle() & WB_SPIN)
628  {
629  tools::Long nBottom1 = aSize.Height()/2;
630  tools::Long nBottom2 = aSize.Height()-1;
631  tools::Long nTop2 = nBottom1;
632  if ( !(aSize.Height() & 0x01) )
633  nBottom1--;
634 
635  bool bNativeRegionOK = false;
636  tools::Rectangle aContentUp, aContentDown;
637 
638  if ((pDev->GetOutDevType() == OUTDEV_WINDOW) &&
639  // there is just no useful native support for spinfields with dropdown
640  ! (GetStyle() & WB_DROPDOWN) &&
642  {
643  vcl::Window *pWin = pDev->GetOwnerWindow();
644  vcl::Window *pBorder = pWin->GetWindow( GetWindowType::Border );
645 
646  // get the system's spin button size
647  ImplControlValue aControlValue;
648  tools::Rectangle aBound;
649  Point aPoint;
650 
651  // use the full extent of the control
652  tools::Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
653 
654  bNativeRegionOK =
656  aArea, ControlState::NONE, aControlValue, aBound, aContentUp) &&
658  aArea, ControlState::NONE, aControlValue, aBound, aContentDown);
659 
660  if (bNativeRegionOK)
661  {
662  // convert back from border space to local coordinates
663  aPoint = pBorder->ScreenToOutputPixel( pWin->OutputToScreenPixel( aPoint ) );
664  aContentUp.Move(-aPoint.X(), -aPoint.Y());
665  aContentDown.Move(-aPoint.X(), -aPoint.Y());
666  }
667  }
668 
669  if (bNativeRegionOK)
670  {
671  rSpinUpArea = aContentUp;
672  rSpinDownArea = aContentDown;
673  }
674  else
675  {
676  aSize.AdjustWidth( -(CalcZoom( GetDrawPixel( pDev, rStyleSettings.GetSpinSize() ) )) );
677 
678  rSpinUpArea = tools::Rectangle( aSize.Width(), 0, rOutSz.Width()-aDropDownSize.Width()-1, nBottom1 );
679  rSpinDownArea = tools::Rectangle( rSpinUpArea.Left(), nTop2, rSpinUpArea.Right(), nBottom2 );
680  }
681  }
682  else
683  {
684  rSpinUpArea.SetEmpty();
685  rSpinDownArea.SetEmpty();
686  }
687 }
688 
690 {
691  if (!mbSpin)
692  return;
693 
694  Control::Resize();
695  Size aSize = GetOutputSizePixel();
696  bool bSubEditPositioned = false;
697 
698  if (GetStyle() & (WB_SPIN | WB_DROPDOWN))
699  {
701 
702  ImplControlValue aControlValue;
703  Point aPoint;
704  tools::Rectangle aContent, aBound;
705 
706  // use the full extent of the control
708  tools::Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
709 
710  // adjust position and size of the edit field
712  aControlValue, aBound, aContent) &&
713  // there is just no useful native support for spinfields with dropdown
714  !(GetStyle() & WB_DROPDOWN))
715  {
716  // convert back from border space to local coordinates
717  aPoint = pBorder->ScreenToOutputPixel(OutputToScreenPixel(aPoint));
718  aContent.Move(-aPoint.X(), -aPoint.Y());
719 
720  // use the themes drop down size
721  mpEdit->SetPosPixel( aContent.TopLeft() );
722  bSubEditPositioned = true;
723  aSize = aContent.GetSize();
724  }
725  else
726  {
727  if (maUpperRect.IsEmpty())
728  {
729  SAL_WARN_IF( maDropDownRect.IsEmpty(), "vcl", "SpinField::Resize: SPIN && DROPDOWN, but all empty rects?" );
730  aSize.setWidth( maDropDownRect.Left() );
731  }
732  else
733  aSize.setWidth( maUpperRect.Left() );
734  }
735  }
736 
737  if (!bSubEditPositioned)
738  {
739  // this moves our sub edit if RTL gets switched
741  }
742  mpEdit->SetSizePixel(aSize);
743 
744  if (GetStyle() & WB_SPIN)
746  if (GetStyle() & WB_DROPDOWN)
748 }
749 
751 {
752  Edit::StateChanged(nType);
753 
754  if (nType == StateChangedType::Enable)
755  {
756  if (mbSpin || (GetStyle() & WB_DROPDOWN))
757  {
758  mpEdit->Enable(IsEnabled());
759 
760  if (mbSpin)
761  {
764  }
765  if (GetStyle() & WB_DROPDOWN)
767  }
768  }
769  else if (nType == StateChangedType::Style)
770  {
771  if (GetStyle() & WB_REPEAT)
772  mbRepeat = true;
773  else
774  mbRepeat = false;
775  }
776  else if (nType == StateChangedType::Zoom)
777  {
778  Resize();
779  if (mpEdit)
780  mpEdit->SetZoom(GetZoom());
781  Invalidate();
782  }
783  else if (nType == StateChangedType::ControlFont)
784  {
785  if (mpEdit)
787  Invalidate();
788  }
789  else if (nType == StateChangedType::ControlForeground)
790  {
791  if (mpEdit)
793  Invalidate();
794  }
795  else if (nType == StateChangedType::ControlBackground)
796  {
797  if (mpEdit)
799  Invalidate();
800  }
801  else if( nType == StateChangedType::Mirroring )
802  {
803  if (mpEdit)
805  Resize();
806  }
807 }
808 
810 {
811  Edit::DataChanged(rDCEvt);
812 
813  if ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
814  (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
815  {
816  Resize();
817  Invalidate();
818  }
819 }
820 
822 {
823  if (maUpperRect.Contains(rPt))
824  return &maUpperRect;
825  else if (maLowerRect.Contains(rPt))
826  return &maLowerRect;
827  else
828  return nullptr;
829 }
830 
832 {
833  if (rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE)
834  {
835  const MouseEvent* pMouseEvt = rNEvt.GetMouseEvent();
836  if (pMouseEvt && !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged())
837  {
838  // trigger redraw if mouse over state has changed
841  {
844  if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
845  {
846  // FIXME: this is currently only on macOS
847  // check for other platforms that need similar handling
850  {
852  }
853  else
854  {
855  // paint directly
856  vcl::Region aRgn( GetOutDev()->GetActiveClipRegion() );
857  if (pLastRect)
858  {
859  GetOutDev()->SetClipRegion(vcl::Region(*pLastRect));
860  Invalidate(*pLastRect);
861  GetOutDev()->SetClipRegion( aRgn );
862  }
863  if (pRect)
864  {
865  GetOutDev()->SetClipRegion(vcl::Region(*pRect));
866  Invalidate(*pRect);
867  GetOutDev()->SetClipRegion( aRgn );
868  }
869  }
870  }
871  }
872  }
873  }
874 
875  return Edit::PreNotify(rNEvt);
876 }
877 
879 {
880  mbInDropDown = false;
882 }
883 
885 {
886  return false;
887 }
888 
889 Size SpinField::CalcMinimumSizeForText(const OUString &rString) const
890 {
891  Size aSz = Edit::CalcMinimumSizeForText(rString);
892 
893  if ( GetStyle() & WB_DROPDOWN )
894  aSz.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
895  if ( GetStyle() & WB_SPIN )
896  {
897  ImplControlValue aControlValue;
898  tools::Rectangle aArea( Point(), Size(100, aSz.Height()));
899  tools::Rectangle aEntireBound, aEntireContent, aEditBound, aEditContent;
900  if (
902  aArea, ControlState::NONE, aControlValue, aEntireBound, aEntireContent) &&
904  aArea, ControlState::NONE, aControlValue, aEditBound, aEditContent)
905  )
906  {
907  aSz.AdjustWidth(aEntireContent.GetWidth() - aEditContent.GetWidth());
908  }
909  else
910  {
912  }
913  }
914 
915  return aSz;
916 }
917 
919 {
921 }
922 
924 {
925  return CalcMinimumSize();
926 }
927 
928 Size SpinField::CalcSize(sal_Int32 nChars) const
929 {
930  Size aSz = Edit::CalcSize( nChars );
931 
932  if ( GetStyle() & WB_DROPDOWN )
933  aSz.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
934  if ( GetStyle() & WB_SPIN )
935  aSz.AdjustWidth(GetSettings().GetStyleSettings().GetSpinSize() );
936 
937  return aSz;
938 }
939 
940 IMPL_LINK( SpinField, ImplTimeout, Timer*, pTimer, void )
941 {
942  if ( pTimer->GetTimeout() == static_cast<sal_uInt64>(MouseSettings::GetButtonStartRepeat()) )
943  {
944  pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
945  pTimer->Start();
946  }
947  else
948  {
949  if ( mbInitialUp )
950  Up();
951  else
952  Down();
953  }
954 }
955 
956 void SpinField::Draw(OutputDevice* pDev, const Point& rPos, SystemTextColorFlags nFlags)
957 {
958  Edit::Draw(pDev, rPos, nFlags);
959 
960  WinBits nFieldStyle = GetStyle();
961  if ( (nFlags & SystemTextColorFlags::NoControls ) || !( nFieldStyle & (WB_SPIN|WB_DROPDOWN) ) )
962  return;
963 
964  Point aPos = pDev->LogicToPixel( rPos );
965  Size aSize = GetSizePixel();
966  AllSettings aOldSettings = pDev->GetSettings();
967 
968  pDev->Push();
969  pDev->SetMapMode();
970 
971  tools::Rectangle aDD, aUp, aDown;
972  ImplCalcButtonAreas(pDev, aSize, aDD, aUp, aDown);
973  aDD.Move(aPos.X(), aPos.Y());
974  aUp.Move(aPos.X(), aPos.Y());
975  aUp.AdjustTop( 1 );
976  aDown.Move(aPos.X(), aPos.Y());
977 
978  Color aButtonTextColor;
979  if (nFlags & SystemTextColorFlags::Mono)
980  aButtonTextColor = COL_BLACK;
981  else
982  aButtonTextColor = GetSettings().GetStyleSettings().GetButtonTextColor();
983 
984  if (GetStyle() & WB_DROPDOWN)
985  {
986  DecorationView aView( pDev );
989  aView.DrawSymbol(aInnerRect, SymbolType::SPIN_DOWN, aButtonTextColor, nSymbolStyle);
990  }
991 
992  if (GetStyle() & WB_SPIN)
993  {
994  ImplDrawSpinButton(*pDev, this, aUp, aDown, false, false);
995  }
996 
997  pDev->Pop();
998  pDev->SetSettings(aOldSettings);
999 
1000 }
1001 
1003 {
1005 }
1006 
1007 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect) override
Definition: edit.cxx:1722
vcl::Region GetClipRegion() const
OutDevType GetOutDevType() const
Definition: outdev.hxx:403
virtual void EnableRTL(bool bEnable=true) override
Definition: ctrl.cxx:64
virtual void Draw(OutputDevice *pDev, const Point &rPos, SystemTextColorFlags nFlags) override
Definition: spinfld.cxx:956
void SetBackground()
Definition: window3.cxx:100
bool ImplCallEventListenersAndHandler(VclEventId nEvent, std::function< void()> const &callHandler)
this calls both our event listeners, and a specified handler
Definition: ctrl.cxx:300
void CaptureMouse()
Definition: mouse.cxx:445
Point GetPointerPosPixel()
Definition: mouse.cxx:556
IMPL_LINK(SpinField, ImplTimeout, Timer *, pTimer, void)
Definition: spinfld.cxx:940
tools::Rectangle GetUnion(const tools::Rectangle &rRect) const
bool mbUpperIn
Definition: spinfld.hxx:88
virtual void MouseButtonDown(const MouseEvent &rMEvt) override
Definition: spinfld.cxx:377
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
void setWidth(tools::Long nWidth)
bool GetNativeControlRegion(ControlType nType, ControlPart nPart, const tools::Rectangle &rControlRegion, ControlState nState, const ImplControlValue &aValue, tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion) const
Query the native control's actual drawing region (including adornment)
const CommandEvent * GetCommandEvent() const
Definition: event.hxx:332
std::unique_ptr< ContentProperties > pData
Edit * GetSubEdit() const
Definition: edit.hxx:217
std::optional< vcl::ControlLayoutData > mxLayoutData
Definition: ctrl.hxx:84
A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for refer...
Definition: button.hxx:34
virtual Size GetOptimalSize() const override
Definition: spinfld.cxx:923
constexpr tools::Long Left() 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:156
bool Contains(const Point &rPOINT) const
void ImplDrawUpDownButtons(vcl::RenderContext &rRenderContext, const tools::Rectangle &rUpperRect, const tools::Rectangle &rLowerRect, bool bUpperIn, bool bLowerIn, bool bUpperEnabled, bool bLowerEnabled, bool bHorz, bool bMirrorHorz)
Definition: spinfld.cxx:205
virtual Size CalcMinimumSizeForText(const OUString &rString) const
Definition: edit.cxx:2607
long Long
void disposeAndClear()
Definition: vclptr.hxx:200
const StyleSettings & GetStyleSettings() const
ImplSVNWFData maNWFData
Definition: svdata.hxx:399
std::function< std::unique_ptr< UIObject >vcl::Window *)> FactoryFunction
virtual Size GetSizePixel() const
Definition: window.cxx:2399
virtual void SetSizePixel(const Size &rNewSize)
Definition: window2.cxx:1256
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect) override
Definition: spinfld.cxx:581
virtual void MouseButtonUp(const MouseEvent &rMEvt) override
Definition: spinfld.cxx:417
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: edit.cxx:223
SAL_DLLPRIVATE void CompatStateChanged(StateChangedType nStateChange)
Definition: window.cxx:3888
sal_uInt16 GetCode() const
Definition: keycod.hxx:49
ControlPart mnLowerPart
DataChangedEventType GetType() const
Definition: event.hxx:362
const KeyEvent * GetKeyEvent() const
Definition: event.hxx:316
DrawButtonFlags
Definition: decoview.hxx:53
void AppendLayoutData(const Control &rSubControl) const
Definition: ctrl.cxx:268
virtual void SetSettings(const AllSettings &rSettings)
Definition: outdev.cxx:218
bool mbInDropDown
Definition: spinfld.hxx:88
virtual void Up()
Definition: spinfld.cxx:357
const Color & GetControlBackground() const
Definition: window2.cxx:1076
const CommandWheelData * GetWheelData() const
tools::Rectangle * ImplFindPartRect(const Point &rPt)
Definition: spinfld.cxx:821
tools::Rectangle DrawButton(const tools::Rectangle &rRect, DrawButtonFlags nStyle)
Definition: decoview.cxx:918
tools::Rectangle maLowerRect
bool HasChildPathFocus(bool bSystemWindow=false) const
Definition: window.cxx:3001
bool IsNativeControlSupported(ControlType nType, ControlPart nPart) const
Query the platform layer for control support.
void SetMapMode()
Definition: map.cxx:592
constexpr sal_uInt16 KEY_UP
Definition: keycodes.hxx:111
const Fraction & GetZoom() const
Definition: window2.cxx:1204
StateChangedType
Definition: window.hxx:289
constexpr tools::Long Width() const
tools::Rectangle maUpperRect
sal_Int64 WinBits
void SetControlFont()
Definition: window2.cxx:403
virtual void FillLayoutData() const override
Definition: edit.cxx:1716
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: spinfld.cxx:350
bool mbInitialDown
Definition: spinfld.hxx:88
AutoTimer maRepeatTimer
Definition: spinfld.hxx:85
void Enable(bool bEnable=true, bool bChild=true)
Definition: window.cxx:2430
sal_uInt16 GetButtons() const
Definition: event.hxx:147
SymbolType
Definition: vclenum.hxx:73
bool IsEnterWindow() const
Definition: event.hxx:138
tools::Rectangle maDropDownRect
Definition: spinfld.hxx:67
tools::Rectangle maLowerRect
Definition: spinfld.hxx:66
Link< SpinField &, void > maDownHdlLink
Definition: spinfld.hxx:87
virtual ~SpinField() override
Definition: spinfld.cxx:345
AllSettingsFlags GetFlags() const
Definition: event.hxx:363
constexpr sal_uInt16 KEY_PAGEUP
Definition: keycodes.hxx:116
virtual void MouseMove(const MouseEvent &rMEvt) override
Definition: spinfld.cxx:440
constexpr tools::Long GetWidth() const
SystemTextColorFlags
void Pop()
Definition: stack.cxx:93
void SetCompoundControl(bool bCompound)
Definition: window2.cxx:941
sal_uInt16 GetModifier() const
Definition: keycod.hxx:52
virtual void MouseButtonUp(const MouseEvent &rMEvt) override
Definition: edit.cxx:1358
virtual bool ShowDropDown(bool bShow)
Definition: spinfld.cxx:884
Definition: edit.hxx:55
virtual FactoryFunction GetUITestFactory() const override
Definition: spinfld.cxx:1002
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
virtual void Down()
Definition: spinfld.cxx:362
constexpr bool IsEmpty() const
const Color & GetControlForeground() const
Definition: window2.cxx:1066
SAL_DLLPRIVATE bool ImplUseNativeBorder(vcl::RenderContext const &rRenderContext, WinBits nStyle)
Definition: edit.cxx:288
ControlPart mnUpperPart
ControlState mnUpperState
constexpr sal_uInt16 KEY_DOWN
Definition: keycodes.hxx:110
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:75
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: spinfld.cxx:483
sal_Int32 GetScrollBarSize() const
virtual bool PreNotify(NotifyEvent &rNEvt)
Definition: event.cxx:52
bool IsLeaveWindow() const
Definition: event.hxx:140
The edit field part of a control, e.g.
bool IsNativeWidgetEnabled() const
Definition: window.cxx:3700
bool mbInitialUp
Definition: spinfld.hxx:88
virtual void StateChanged(StateChangedType nType) override
Definition: edit.cxx:2154
void SetControlBackground()
Definition: window2.cxx:491
void SetControlForeground()
Definition: window2.cxx:451
CommandWheelMode GetMode() const
virtual void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
Definition: paint.cxx:1164
ControlState mnLowerState
virtual OUString GetText() const override
Definition: edit.cxx:2564
constexpr tools::Long Right() const
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:168
const AllSettings & GetSettings() const
Definition: window3.cxx:129
CommandEventId GetCommand() const
virtual void Start(bool bStartTimer=true) override
Schedules the task for execution.
Definition: timer.cxx:83
void SetZoom(const Fraction &rZoom)
Definition: window2.cxx:364
bool GetNativeControlRegion(ControlType nType, ControlPart nPart, const tools::Rectangle &rControlRegion, ControlState nState, const ImplControlValue &aValue, tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion) const
Query the native control's actual drawing region (including adornment)
Definition: window3.cxx:79
virtual void FillLayoutData() const override
Definition: spinfld.cxx:569
constexpr sal_uInt16 KEY_PAGEDOWN
Definition: keycodes.hxx:117
DrawSymbolFlags
Definition: decoview.hxx:34
MouseNotifyEvent GetType() const
Definition: event.hxx:308
bool DrawNativeControl(ControlType nType, ControlPart nPart, const tools::Rectangle &rControlRegion, ControlState nState, const ImplControlValue &aValue, const OUString &aCaption, const Color &rBackgroundColor=COL_AUTO)
Request rendering of a particular control and/or part.
void SetSubEdit(Edit *pEdit)
Definition: edit.cxx:2592
WinBits const WB_DROPDOWN
const AllSettings & GetSettings() const
Definition: outdev.hxx:288
constexpr sal_uInt16 KEY_MOD2
Definition: keycodes.hxx:32
void SetTimeout(sal_uInt64 nTimeoutMs)
Definition: timer.cxx:90
Point ScreenToOutputPixel(const Point &rPos) const
Definition: window.cxx:2806
void GrabFocus()
Definition: window.cxx:2973
virtual Size CalcSize(sal_Int32 nChars) const override
Definition: spinfld.cxx:928
WinBits const WB_REPEAT
WinBits const WB_NOBORDER
constexpr Point TopLeft() const
tools::Long AdjustTop(tools::Long nVertMoveDelta)
vcl::Window * GetWindow(GetWindowType nType) const
Definition: stacking.cxx:1035
SAL_DLLPRIVATE void ImplInitSpinFieldData()
Definition: spinfld.cxx:291
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:876
ControlType
These types are all based on the supported variants vcl/salnativewidgets.hxx and must be kept in-sync...
void ReleaseMouse()
Definition: mouse.cxx:463
virtual Size CalcSize(sal_Int32 nChars) const
Definition: edit.cxx:2667
bool IsModifierChanged() const
Definition: event.hxx:144
void EndDropDown()
Definition: spinfld.cxx:878
bool mbSpin
Definition: spinfld.hxx:88
const vcl::KeyCode & GetKeyCode() const
Definition: event.hxx:57
static SAL_DLLPRIVATE void ImplInvalidateOutermostBorder(vcl::Window *pWin)
Definition: edit.cxx:1832
constexpr Size GetSize() const
virtual void First()
Definition: spinfld.cxx:367
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: spinfld.cxx:809
bool IsMouseOver() const
Definition: mouse.cxx:612
SAL_DLLPRIVATE void ImplInit(vcl::Window *pParent, WinBits nStyle)
Definition: spinfld.cxx:303
virtual void Resize() override
Definition: ctrl.cxx:73
void Stop()
Definition: scheduler.cxx:590
WindowType
bool IsSynthetic() const
Definition: event.hxx:142
Link< SpinField &, void > maUpHdlLink
Definition: spinfld.hxx:86
const Color & GetButtonTextColor() const
bool mbNoFocusRects
Definition: svdata.hxx:323
#define SAL_WARN_IF(condition, area, stream)
SpinField(vcl::Window *pParent, WinBits nWinStyle, WindowType nType=WindowType::SPINFIELD)
Definition: spinfld.cxx:338
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: edit.cxx:2235
constexpr tools::Long Height() const
const MouseEvent * GetMouseEvent() const
Definition: event.hxx:324
virtual void MouseButtonDown(const MouseEvent &rMEvt) override
Definition: edit.cxx:1317
static std::unique_ptr< UIObject > create(vcl::Window *pWindow)
::OutputDevice const * GetOutDev() const
Definition: window.cxx:565
bool IsLeft() const
Definition: event.hxx:149
tools::Long AdjustWidth(tools::Long n)
virtual Size CalcMinimumSize() const override
Definition: spinfld.cxx:918
bool mbLowerIn
Definition: spinfld.hxx:88
SAL_DLLPRIVATE void ImplCalcButtonAreas(const OutputDevice *pDev, const Size &rOutSz, tools::Rectangle &rDDArea, tools::Rectangle &rSpinUpArea, tools::Rectangle &rSpinDownArea)
Definition: spinfld.cxx:606
virtual void Last()
Definition: spinfld.cxx:372
virtual void Resize() override
Definition: spinfld.cxx:689
tools::Long CalcZoom(tools::Long n) const
Definition: window2.cxx:391
bool mbRepeat
Definition: spinfld.hxx:88
tools::Long GetDrawPixel(::OutputDevice const *pDev, tools::Long nPixels) const
Definition: window2.cxx:557
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BLACK
void SetInvokeHandler(const Link< Timer *, void > &rLink)
Definition: timer.hxx:56
const Point & GetPosPixel() const
Definition: event.hxx:123
void set(reference_type *pBody)
Definition: vclptr.hxx:148
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: spinfld.cxx:831
Size GetOutputSizePixel() const
Definition: window3.cxx:89
constexpr Point BottomRight() const
WindowType GetType() const
Definition: window2.cxx:968
sal_Int32 GetSpinSize() const
tools::Long GetDelta() const
void Move(tools::Long nHorzMoveDelta, tools::Long nVertMoveDelta)
bool IsEnabled() const
Definition: window2.cxx:1116
virtual void MouseMove(const MouseEvent &rMEvt)
Definition: mouse.cxx:413
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
void DrawSymbol(const tools::Rectangle &rRect, SymbolType eType, const Color &rColor, DrawSymbolFlags nStyle=DrawSymbolFlags::NONE)
Definition: decoview.cxx:781
MouseWheelBehaviour
Definition: settings.hxx:77
WinBits GetStyle() const
Definition: window2.cxx:947
Definition: timer.hxx:26
Point OutputToScreenPixel(const Point &rPos) const
Definition: window.cxx:2800
bool IsNativeControlSupported(ControlType nType, ControlPart nPart) const
Query the platform layer for control support.
Definition: window3.cxx:74
virtual bool IsReadOnly() const
Definition: edit.hxx:175
Point GetLastPointerPosPixel()
Definition: mouse.cxx:568
virtual Size CalcMinimumSizeForText(const OUString &rString) const override
Definition: spinfld.cxx:889
vcl::Font GetControlFont() const
Definition: window2.cxx:432
bool HasFocus() const
Definition: window.cxx:2978
void Push(PushFlags nFlags=PushFlags::ALL)
Definition: stack.cxx:34
WinBits const WB_SPIN
bool SupportsDoubleBuffering() const
Can the widget derived from this Window do the double-buffering via RenderContext properly...
Definition: window.cxx:3850
virtual vcl::Window * GetOwnerWindow() const
Get the vcl::Window that this OutputDevice belongs to, if any.
Definition: outdev.hxx:1901
sal_Int32 nState
virtual void SetPosPixel(const Point &rNewPos)
Definition: window2.cxx:1251
VclPtr< Edit > mpEdit
Definition: spinfld.hxx:84
virtual void Draw(OutputDevice *pDev, const Point &rPos, SystemTextColorFlags nFlags) override
Definition: edit.cxx:1741
SAL_DLLPRIVATE void ImplInit(vcl::Window *pParent, WinBits nStyle)
Definition: edit.cxx:304
tools::Rectangle maUpperRect
Definition: spinfld.hxx:65
virtual void StateChanged(StateChangedType nType) override
Definition: spinfld.cxx:750
static sal_Int32 GetButtonStartRepeat()
constexpr tools::Long GetHeight() const
void SetLayoutDataParent(const Control *pParent) const
Definition: ctrl.cxx:319
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: ctrl.cxx:224
void Show(bool bVisible=true, ShowFlags nFlags=ShowFlags::NONE)
Definition: window.cxx:2184