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