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/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::LONGCURRENCYFIELD:
178  case WindowType::NUMERICFIELD:
179  case WindowType::SPINFIELD:
180  aControl = ControlType::Spinbox;
181  break;
182  default:
183  aControl = ControlType::SpinButtons;
184  break;
185  }
186 
187  SpinbuttonValue aValue;
188  ImplGetSpinbuttonValue(pWindow, rUpperRect, rLowerRect,
189  bUpperIn, bLowerIn, bUpperEnabled, bLowerEnabled,
190  bHorz, aValue);
191 
192  if( aControl == ControlType::Spinbox )
193  bNativeOK = ImplDrawNativeSpinfield(rRenderContext, pWindow, aValue);
194  else if( aControl == ControlType::SpinButtons )
195  bNativeOK = ImplDrawNativeSpinbuttons(rRenderContext, aValue);
196  }
197 
198  if (bNativeOK)
199  return;
200 
201  ImplDrawUpDownButtons(rRenderContext,
202  rUpperRect, rLowerRect,
203  bUpperIn, bLowerIn, bUpperEnabled, bLowerEnabled,
204  bHorz, bMirrorHorz);
205 }
206 
208  const tools::Rectangle& rUpperRect, const tools::Rectangle& rLowerRect,
209  bool bUpperIn, bool bLowerIn, bool bUpperEnabled, bool bLowerEnabled,
210  bool bHorz, bool bMirrorHorz)
211 {
212  DecorationView aDecoView(&rRenderContext);
213 
214  SymbolType eType1, eType2;
215 
216  if ( bHorz )
217  {
218  eType1 = bMirrorHorz ? SymbolType::SPIN_RIGHT : SymbolType::SPIN_LEFT;
219  eType2 = bMirrorHorz ? SymbolType::SPIN_LEFT : SymbolType::SPIN_RIGHT;
220  }
221  else
222  {
223  eType1 = SymbolType::SPIN_UP;
224  eType2 = SymbolType::SPIN_DOWN;
225  }
226 
228  // draw upper/left Button
229  if (bUpperIn)
230  nStyle |= DrawButtonFlags::Pressed;
231 
232  tools::Rectangle aUpRect = aDecoView.DrawButton(rUpperRect, nStyle);
233 
235  // draw lower/right Button
236  if (bLowerIn)
237  nStyle |= DrawButtonFlags::Pressed;
238 
239  tools::Rectangle aLowRect = aDecoView.DrawButton(rLowerRect, nStyle);
240 
241  // make use of additional default edge
242  aUpRect.AdjustLeft( -1 );
243  aUpRect.AdjustTop( -1 );
244  aUpRect.AdjustRight( 1 );
245  aUpRect.AdjustBottom( 1 );
246  aLowRect.AdjustLeft( -1 );
247  aLowRect.AdjustTop( -1 );
248  aLowRect.AdjustRight( 1 );
249  aLowRect.AdjustBottom( 1 );
250 
251  // draw into the edge, so that something is visible if the rectangle is too small
252  if (aUpRect.GetHeight() < 4)
253  {
254  aUpRect.AdjustRight( 1 );
255  aUpRect.AdjustBottom( 1 );
256  aLowRect.AdjustRight( 1 );
257  aLowRect.AdjustBottom( 1 );
258  }
259 
260  // calculate Symbol size
261  long nTempSize1 = aUpRect.GetWidth();
262  long nTempSize2 = aLowRect.GetWidth();
263  if (std::abs( nTempSize1-nTempSize2 ) == 1)
264  {
265  if (nTempSize1 > nTempSize2)
266  aUpRect.AdjustLeft( 1 );
267  else
268  aLowRect.AdjustLeft( 1 );
269  }
270  nTempSize1 = aUpRect.GetHeight();
271  nTempSize2 = aLowRect.GetHeight();
272  if (std::abs(nTempSize1 - nTempSize2) == 1)
273  {
274  if (nTempSize1 > nTempSize2)
275  aUpRect.AdjustTop( 1 );
276  else
277  aLowRect.AdjustTop( 1 );
278  }
279 
280  const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
281 
283  if (!bUpperEnabled)
284  nSymStyle |= DrawSymbolFlags::Disable;
285  aDecoView.DrawSymbol(aUpRect, eType1, rStyleSettings.GetButtonTextColor(), nSymStyle);
286 
287  nSymStyle = DrawSymbolFlags::NONE;
288  if (!bLowerEnabled)
289  nSymStyle |= DrawSymbolFlags::Disable;
290  aDecoView.DrawSymbol(aLowRect, eType2, rStyleSettings.GetButtonTextColor(), nSymStyle);
291 }
292 
294 {
296  mbSpin = false;
297  mbRepeat = false;
298  mbUpperIn = false;
299  mbLowerIn = false;
300  mbInitialUp = false;
301  mbInitialDown = false;
302  mbInDropDown = false;
303 }
304 
305 void SpinField::ImplInit(vcl::Window* pParent, WinBits nWinStyle)
306 {
307  Edit::ImplInit( pParent, nWinStyle );
308 
309  if (nWinStyle & (WB_SPIN | WB_DROPDOWN))
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 
342 {
344  ImplInit(pParent, nWinStyle);
345 }
346 
348 {
349  disposeOnce();
350 }
351 
353 {
355 
356  Edit::dispose();
357 }
358 
360 {
362 }
363 
365 {
367 }
368 
370 {
372 }
373 
375 {
377 }
378 
380 {
381  if (!HasFocus() && (!mpEdit || !mpEdit->HasFocus()))
382  {
383  GrabFocus();
384  }
385 
386  if (!IsReadOnly())
387  {
388  if (maUpperRect.IsInside(rMEvt.GetPosPixel()))
389  {
390  mbUpperIn = true;
391  mbInitialUp = true;
393  }
394  else if (maLowerRect.IsInside(rMEvt.GetPosPixel()))
395  {
396  mbLowerIn = true;
397  mbInitialDown = true;
399  }
400  else if (maDropDownRect.IsInside(rMEvt.GetPosPixel()))
401  {
402  // put DropDownButton to the right
405  }
406 
407  if (mbUpperIn || mbLowerIn)
408  {
409  Update();
410  CaptureMouse();
411  if (mbRepeat)
413  return;
414  }
415  }
416 
417  Edit::MouseButtonDown(rMEvt);
418 }
419 
421 {
422  ReleaseMouse();
423  mbInitialUp = mbInitialDown = false;
426 
427  if (mbUpperIn)
428  {
429  mbUpperIn = false;
431  Update();
432  Up();
433  }
434  else if (mbLowerIn)
435  {
436  mbLowerIn = false;
438  Update();
439  Down();
440  }
441 
442  Edit::MouseButtonUp(rMEvt);
443 }
444 
446 {
447  if (rMEvt.IsLeft())
448  {
449  if (mbInitialUp)
450  {
451  bool bNewUpperIn = maUpperRect.IsInside(rMEvt.GetPosPixel());
452  if (bNewUpperIn != mbUpperIn)
453  {
454  if (bNewUpperIn)
455  {
456  if (mbRepeat)
458  }
459  else
461 
462  mbUpperIn = bNewUpperIn;
464  Update();
465  }
466  }
467  else if (mbInitialDown)
468  {
469  bool bNewLowerIn = maLowerRect.IsInside(rMEvt.GetPosPixel());
470  if (bNewLowerIn != mbLowerIn)
471  {
472  if (bNewLowerIn)
473  {
474  if (mbRepeat)
476  }
477  else
479 
480  mbLowerIn = bNewLowerIn;
482  Update();
483  }
484  }
485  }
486 
487  Edit::MouseMove(rMEvt);
488 }
489 
491 {
492  bool bDone = false;
493  if (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
494  {
495  const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
496  if (!IsReadOnly())
497  {
498  sal_uInt16 nMod = rKEvt.GetKeyCode().GetModifier();
499  switch (rKEvt.GetKeyCode().GetCode())
500  {
501  case KEY_UP:
502  {
503  if (!nMod)
504  {
505  Up();
506  bDone = true;
507  }
508  }
509  break;
510  case KEY_DOWN:
511  {
512  if (!nMod)
513  {
514  Down();
515  bDone = true;
516  }
517  else if ((nMod == KEY_MOD2) && !mbInDropDown && (GetStyle() & WB_DROPDOWN))
518  {
519  mbInDropDown = ShowDropDown(true);
521  bDone = true;
522  }
523  }
524  break;
525  case KEY_PAGEUP:
526  {
527  if (!nMod)
528  {
529  Last();
530  bDone = true;
531  }
532  }
533  break;
534  case KEY_PAGEDOWN:
535  {
536  if (!nMod)
537  {
538  First();
539  bDone = true;
540  }
541  }
542  break;
543  }
544  }
545  }
546 
547  if (rNEvt.GetType() == MouseNotifyEvent::COMMAND)
548  {
550  {
551  MouseWheelBehaviour nWheelBehavior(GetSettings().GetMouseSettings().GetWheelBehavior());
552  if (nWheelBehavior == MouseWheelBehaviour::ALWAYS
553  || (nWheelBehavior == MouseWheelBehaviour::FocusOnly && HasChildPathFocus()))
554  {
555  const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
556  if (pData->GetMode() == CommandWheelMode::SCROLL)
557  {
558  if (pData->GetDelta() < 0)
559  Down();
560  else
561  Up();
562  bDone = true;
563  }
564  }
565  else
566  bDone = false; // don't eat this event, let the default handling happen (i.e. scroll the context)
567  }
568  }
569 
570  return bDone || Edit::EventNotify(rNEvt);
571 }
572 
574 {
575  if (mbSpin)
576  {
577  mpControlData->mpLayoutData.reset( new vcl::ControlLayoutData );
580  }
581  else
583 }
584 
585 void SpinField::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
586 {
587  if (mbSpin)
588  {
589  bool bEnable = IsEnabled();
590  ImplDrawSpinButton(rRenderContext, this, maUpperRect, maLowerRect,
591  mbUpperIn, mbLowerIn, bEnable, bEnable);
592  }
593 
594  if (GetStyle() & WB_DROPDOWN)
595  {
596  DecorationView aView(&rRenderContext);
597 
599  if (mbInDropDown)
600  nStyle |= DrawButtonFlags::Pressed;
601  tools::Rectangle aInnerRect = aView.DrawButton(maDropDownRect, nStyle);
602 
604  aView.DrawSymbol(aInnerRect, SymbolType::SPIN_DOWN, rRenderContext.GetSettings().GetStyleSettings().GetButtonTextColor(), nSymbolStyle);
605  }
606 
607  Edit::Paint(rRenderContext, rRect);
608 }
609 
611  tools::Rectangle& rSpinUpArea, tools::Rectangle& rSpinDownArea)
612 {
613  const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings();
614 
615  Size aSize = rOutSz;
616  Size aDropDownSize;
617 
618  if (GetStyle() & WB_DROPDOWN)
619  {
620  long nW = rStyleSettings.GetScrollBarSize();
621  nW = GetDrawPixel( pDev, nW );
622  aDropDownSize = Size( CalcZoom( nW ), aSize.Height() );
623  aSize.AdjustWidth( -(aDropDownSize.Width()) );
624  rDDArea = tools::Rectangle( Point( aSize.Width(), 0 ), aDropDownSize );
625  rDDArea.AdjustTop( -1 );
626  }
627  else
628  rDDArea.SetEmpty();
629 
630  // calculate sizes according to the height
631  if (GetStyle() & WB_SPIN)
632  {
633  long nBottom1 = aSize.Height()/2;
634  long nBottom2 = aSize.Height()-1;
635  long nTop2 = nBottom1;
636  if ( !(aSize.Height() & 0x01) )
637  nBottom1--;
638 
639  bool bNativeRegionOK = false;
640  tools::Rectangle aContentUp, aContentDown;
641 
642  if ((pDev->GetOutDevType() == OUTDEV_WINDOW) &&
643  // there is just no useful native support for spinfields with dropdown
644  ! (GetStyle() & WB_DROPDOWN) &&
646  {
647  vcl::Window *pWin = static_cast<vcl::Window*>(pDev);
648  vcl::Window *pBorder = pWin->GetWindow( GetWindowType::Border );
649 
650  // get the system's spin button size
651  ImplControlValue aControlValue;
652  tools::Rectangle aBound;
653  Point aPoint;
654 
655  // use the full extent of the control
656  tools::Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
657 
658  bNativeRegionOK =
660  aArea, ControlState::NONE, aControlValue, aBound, aContentUp) &&
662  aArea, ControlState::NONE, aControlValue, aBound, aContentDown);
663 
664  if (bNativeRegionOK)
665  {
666  // convert back from border space to local coordinates
667  aPoint = pBorder->ScreenToOutputPixel( pWin->OutputToScreenPixel( aPoint ) );
668  aContentUp.Move(-aPoint.X(), -aPoint.Y());
669  aContentDown.Move(-aPoint.X(), -aPoint.Y());
670  }
671  }
672 
673  if (bNativeRegionOK)
674  {
675  rSpinUpArea = aContentUp;
676  rSpinDownArea = aContentDown;
677  }
678  else
679  {
680  aSize.AdjustWidth( -(CalcZoom( GetDrawPixel( pDev, rStyleSettings.GetSpinSize() ) )) );
681 
682  rSpinUpArea = tools::Rectangle( aSize.Width(), 0, rOutSz.Width()-aDropDownSize.Width()-1, nBottom1 );
683  rSpinDownArea = tools::Rectangle( rSpinUpArea.Left(), nTop2, rSpinUpArea.Right(), nBottom2 );
684  }
685  }
686  else
687  {
688  rSpinUpArea.SetEmpty();
689  rSpinDownArea.SetEmpty();
690  }
691 }
692 
694 {
695  if (mbSpin)
696  {
697  Control::Resize();
698  Size aSize = GetOutputSizePixel();
699  bool bSubEditPositioned = false;
700 
701  if (GetStyle() & (WB_SPIN | WB_DROPDOWN))
702  {
704 
705  ImplControlValue aControlValue;
706  Point aPoint;
707  tools::Rectangle aContent, aBound;
708 
709  // use the full extent of the control
711  tools::Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
712 
713  // adjust position and size of the edit field
715  aControlValue, aBound, aContent) &&
716  // there is just no useful native support for spinfields with dropdown
717  !(GetStyle() & WB_DROPDOWN))
718  {
719  // convert back from border space to local coordinates
720  aPoint = pBorder->ScreenToOutputPixel(OutputToScreenPixel(aPoint));
721  aContent.Move(-aPoint.X(), -aPoint.Y());
722 
723  // use the themes drop down size
724  mpEdit->SetPosPixel( aContent.TopLeft() );
725  bSubEditPositioned = true;
726  aSize = aContent.GetSize();
727  }
728  else
729  {
730  if (maUpperRect.IsEmpty())
731  {
732  SAL_WARN_IF( maDropDownRect.IsEmpty(), "vcl", "SpinField::Resize: SPIN && DROPDOWN, but all empty rects?" );
733  aSize.setWidth( maDropDownRect.Left() );
734  }
735  else
736  aSize.setWidth( maUpperRect.Left() );
737  }
738  }
739 
740  if (!bSubEditPositioned)
741  {
742  // this moves our sub edit if RTL gets switched
744  }
745  mpEdit->SetSizePixel(aSize);
746 
747  if (GetStyle() & WB_SPIN)
749  if (GetStyle() & WB_DROPDOWN)
751  }
752 }
753 
755 {
756  Edit::StateChanged(nType);
757 
758  if (nType == StateChangedType::Enable)
759  {
760  if (mbSpin || (GetStyle() & WB_DROPDOWN))
761  {
762  mpEdit->Enable(IsEnabled());
763 
764  if (mbSpin)
765  {
768  }
769  if (GetStyle() & WB_DROPDOWN)
771  }
772  }
773  else if (nType == StateChangedType::Style)
774  {
775  if (GetStyle() & WB_REPEAT)
776  mbRepeat = true;
777  else
778  mbRepeat = false;
779  }
780  else if (nType == StateChangedType::Zoom)
781  {
782  Resize();
783  if (mpEdit)
784  mpEdit->SetZoom(GetZoom());
785  Invalidate();
786  }
787  else if (nType == StateChangedType::ControlFont)
788  {
789  if (mpEdit)
791  Invalidate();
792  }
793  else if (nType == StateChangedType::ControlForeground)
794  {
795  if (mpEdit)
797  Invalidate();
798  }
799  else if (nType == StateChangedType::ControlBackground)
800  {
801  if (mpEdit)
803  Invalidate();
804  }
805  else if( nType == StateChangedType::Mirroring )
806  {
807  if (mpEdit)
809  Resize();
810  }
811 }
812 
814 {
815  Edit::DataChanged(rDCEvt);
816 
817  if ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
818  (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
819  {
820  Resize();
821  Invalidate();
822  }
823 }
824 
826 {
827  if (maUpperRect.IsInside(rPt))
828  return &maUpperRect;
829  else if (maLowerRect.IsInside(rPt))
830  return &maLowerRect;
831  else
832  return nullptr;
833 }
834 
836 {
837  const MouseEvent* pMouseEvt = nullptr;
838 
839  if ((rNEvt.GetType() == MouseNotifyEvent::MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != nullptr)
840  {
841  if (!pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged())
842  {
843  // trigger redraw if mouse over state has changed
846  {
849  if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
850  {
851  // FIXME: this is currently only on macOS
852  // check for other platforms that need similar handling
855  {
857  }
858  else
859  {
860  // paint directly
862  if (pLastRect)
863  {
864  SetClipRegion(vcl::Region(*pLastRect));
865  Invalidate(*pLastRect);
866  SetClipRegion( aRgn );
867  }
868  if (pRect)
869  {
870  SetClipRegion(vcl::Region(*pRect));
871  Invalidate(*pRect);
872  SetClipRegion( aRgn );
873  }
874  }
875  }
876  }
877  }
878  }
879 
880  return Edit::PreNotify(rNEvt);
881 }
882 
884 {
885  mbInDropDown = false;
887 }
888 
890 {
891  return false;
892 }
893 
894 Size SpinField::CalcMinimumSizeForText(const OUString &rString) const
895 {
896  Size aSz = Edit::CalcMinimumSizeForText(rString);
897 
898  if ( GetStyle() & WB_DROPDOWN )
899  aSz.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
900  if ( GetStyle() & WB_SPIN )
901  {
902  ImplControlValue aControlValue;
903  tools::Rectangle aArea( Point(), Size(100, aSz.Height()));
904  tools::Rectangle aEntireBound, aEntireContent, aEditBound, aEditContent;
905  if (
907  aArea, ControlState::NONE, aControlValue, aEntireBound, aEntireContent) &&
909  aArea, ControlState::NONE, aControlValue, aEditBound, aEditContent)
910  )
911  {
912  aSz.AdjustWidth(aEntireContent.GetWidth() - aEditContent.GetWidth());
913  }
914  else
915  {
917  }
918  }
919 
920  return aSz;
921 }
922 
924 {
926 }
927 
929 {
930  return CalcMinimumSize();
931 }
932 
933 Size SpinField::CalcSize(sal_Int32 nChars) const
934 {
935  Size aSz = Edit::CalcSize( nChars );
936 
937  if ( GetStyle() & WB_DROPDOWN )
938  aSz.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
939  if ( GetStyle() & WB_SPIN )
940  aSz.AdjustWidth(GetSettings().GetStyleSettings().GetSpinSize() );
941 
942  return aSz;
943 }
944 
945 IMPL_LINK( SpinField, ImplTimeout, Timer*, pTimer, void )
946 {
947  if ( pTimer->GetTimeout() == MouseSettings::GetButtonStartRepeat() )
948  {
949  pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
950  pTimer->Start();
951  }
952  else
953  {
954  if ( mbInitialUp )
955  Up();
956  else
957  Down();
958  }
959 }
960 
961 void SpinField::Draw(OutputDevice* pDev, const Point& rPos, const Size& rSize, DrawFlags nFlags)
962 {
963  Edit::Draw(pDev, rPos, rSize, nFlags);
964 
965  WinBits nFieldStyle = GetStyle();
966  if ( (nFlags & DrawFlags::NoControls ) || !( nFieldStyle & (WB_SPIN|WB_DROPDOWN) ) )
967  return;
968 
969  Point aPos = pDev->LogicToPixel( rPos );
970  Size aSize = pDev->LogicToPixel( rSize );
971  OutDevType eOutDevType = pDev->GetOutDevType();
972  AllSettings aOldSettings = pDev->GetSettings();
973 
974  pDev->Push();
975  pDev->SetMapMode();
976 
977  if (eOutDevType == OUTDEV_PRINTER)
978  {
979  StyleSettings aStyleSettings = aOldSettings.GetStyleSettings();
980  aStyleSettings.SetFaceColor(COL_LIGHTGRAY);
981  aStyleSettings.SetButtonTextColor(COL_BLACK);
982  AllSettings aSettings(aOldSettings);
983  aSettings.SetStyleSettings(aStyleSettings);
984  pDev->SetSettings(aSettings);
985  }
986 
987  tools::Rectangle aDD, aUp, aDown;
988  ImplCalcButtonAreas(pDev, aSize, aDD, aUp, aDown);
989  aDD.Move(aPos.X(), aPos.Y());
990  aUp.Move(aPos.X(), aPos.Y());
991  aUp.AdjustTop( 1 );
992  aDown.Move(aPos.X(), aPos.Y());
993 
994  Color aButtonTextColor;
995  if ((nFlags & DrawFlags::Mono) || (eOutDevType == OUTDEV_PRINTER))
996  aButtonTextColor = COL_BLACK;
997  else
998  aButtonTextColor = GetSettings().GetStyleSettings().GetButtonTextColor();
999 
1000  if (GetStyle() & WB_DROPDOWN)
1001  {
1002  DecorationView aView( pDev );
1003  tools::Rectangle aInnerRect = aView.DrawButton( aDD, DrawButtonFlags::NoLightBorder );
1005  aView.DrawSymbol(aInnerRect, SymbolType::SPIN_DOWN, aButtonTextColor, nSymbolStyle);
1006  }
1007 
1008  if (GetStyle() & WB_SPIN)
1009  {
1010  ImplDrawSpinButton(*pDev, this, aUp, aDown, false, false);
1011  }
1012 
1013  pDev->Pop();
1014  pDev->SetSettings(aOldSettings);
1015 
1016 }
1017 
1019 {
1021 }
1022 
1023 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect) override
Definition: edit.cxx:1709
Point TopLeft() const
long Width() const
vcl::Region GetClipRegion() const
OutDevType GetOutDevType() const
Definition: outdev.hxx:522
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:439
Point GetPointerPosPixel()
Definition: mouse.cxx:549
IMPL_LINK(SpinField, ImplTimeout, Timer *, pTimer, void)
Definition: spinfld.cxx:945
long GetHeight() const
constexpr::Color COL_BLACK(0x00, 0x00, 0x00)
tools::Rectangle GetUnion(const tools::Rectangle &rRect) const
bool mbUpperIn
Definition: spinfld.hxx:86
bool DrawNativeControl(ControlType nType, ControlPart nPart, const tools::Rectangle &rControlRegion, ControlState nState, const ImplControlValue &aValue, const OUString &aCaption)
Request rendering of a particular control and/or part.
virtual void MouseButtonDown(const MouseEvent &rMEvt) override
Definition: spinfld.cxx:379
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)
#define KEY_PAGEDOWN
Definition: keycodes.hxx:117
const CommandEvent * GetCommandEvent() const
Definition: event.hxx:318
Edit * GetSubEdit() const
Definition: edit.hxx:226
A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for refer...
Definition: button.hxx:32
void SetStyleSettings(const StyleSettings &rSet)
long Height() const
virtual Size GetOptimalSize() const override
Definition: spinfld.cxx:928
#define KEY_PAGEUP
Definition: keycodes.hxx:116
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:207
virtual Size CalcMinimumSizeForText(const OUString &rString) const
Definition: edit.cxx:2619
long AdjustLeft(long nHorzMoveDelta)
void disposeAndClear()
Definition: vclptr.hxx:200
const StyleSettings & GetStyleSettings() const
ImplSVNWFData maNWFData
Definition: svdata.hxx:352
std::function< std::unique_ptr< UIObject >vcl::Window *)> FactoryFunction
virtual void SetSizePixel(const Size &rNewSize)
Definition: window2.cxx:1251
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect) override
Definition: spinfld.cxx:585
virtual void MouseButtonUp(const MouseEvent &rMEvt) override
Definition: spinfld.cxx:420
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: edit.cxx:213
void CompatStateChanged(StateChangedType nStateChange)
Definition: window.cxx:3853
sal_uInt16 GetCode() const
Definition: keycod.hxx:53
ControlPart mnLowerPart
DataChangedEventType GetType() const
Definition: event.hxx:348
const KeyEvent * GetKeyEvent() const
Definition: event.hxx:302
DrawButtonFlags
Definition: decoview.hxx:78
SAL_DLLPRIVATE void ImplCalcButtonAreas(OutputDevice *pDev, const Size &rOutSz, tools::Rectangle &rDDArea, tools::Rectangle &rSpinUpArea, tools::Rectangle &rSpinDownArea)
Definition: spinfld.cxx:610
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:86
constexpr::Color COL_LIGHTGRAY(0xC0, 0xC0, 0xC0)
virtual void Up()
Definition: spinfld.cxx:359
const Color & GetControlBackground() const
Definition: window2.cxx:1071
const CommandWheelData * GetWheelData() const
tools::Rectangle * ImplFindPartRect(const Point &rPt)
Definition: spinfld.cxx:825
tools::Rectangle DrawButton(const tools::Rectangle &rRect, DrawButtonFlags nStyle)
Definition: decoview.cxx:942
void SetButtonTextColor(const Color &rColor)
tools::Rectangle maLowerRect
bool HasChildPathFocus(bool bSystemWindow=false) const
Definition: window.cxx:3009
bool IsNativeControlSupported(ControlType nType, ControlPart nPart) const
Query the platform layer for control support.
void SetMapMode()
Definition: map.cxx:655
long AdjustBottom(long nVertMoveDelta)
void Move(long nHorzMoveDelta, long nVertMoveDelta)
bool IsEmpty() const
const Fraction & GetZoom() const
Definition: window2.cxx:1199
StateChangedType
Definition: window.hxx:311
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:1703
virtual void dispose() override
This is intended to be used to clear any locally held references to other Window-subclass objects...
Definition: spinfld.cxx:352
bool mbInitialDown
Definition: spinfld.hxx:86
AutoTimer maRepeatTimer
Definition: spinfld.hxx:83
void Enable(bool bEnable=true, bool bChild=true)
Definition: window.cxx:2396
sal_uInt16 GetButtons() const
Definition: event.hxx:131
#define KEY_MOD2
Definition: keycodes.hxx:32
SymbolType
Definition: vclenum.hxx:73
bool IsEnterWindow() const
Definition: event.hxx:122
tools::Rectangle maDropDownRect
Definition: spinfld.hxx:65
tools::Rectangle maLowerRect
Definition: spinfld.hxx:64
Link< SpinField &, void > maDownHdlLink
Definition: spinfld.hxx:85
virtual ~SpinField() override
Definition: spinfld.cxx:347
AllSettingsFlags GetFlags() const
Definition: event.hxx:349
virtual void MouseMove(const MouseEvent &rMEvt) override
Definition: spinfld.cxx:445
void SetCompoundControl(bool bCompound)
Definition: window2.cxx:936
sal_uInt16 GetModifier() const
Definition: keycod.hxx:56
virtual void MouseButtonUp(const MouseEvent &rMEvt) override
Definition: edit.cxx:1345
virtual bool ShowDropDown(bool bShow)
Definition: spinfld.cxx:889
Definition: edit.hxx:57
virtual FactoryFunction GetUITestFactory() const override
Definition: spinfld.cxx:1018
virtual void Down()
Definition: spinfld.cxx:364
const Color & GetControlForeground() const
Definition: window2.cxx:1061
long GetDrawPixel(::OutputDevice const *pDev, long nPixels) const
Definition: window2.cxx:563
void Update()
Definition: paint.cxx:1276
SAL_DLLPRIVATE bool ImplUseNativeBorder(vcl::RenderContext const &rRenderContext, WinBits nStyle)
Definition: edit.cxx:281
ControlPart mnUpperPart
ControlState mnUpperState
Point BottomRight() const
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:67
virtual bool EventNotify(NotifyEvent &rNEvt) override
Definition: spinfld.cxx:490
virtual bool PreNotify(NotifyEvent &rNEvt)
Definition: event.cxx:51
bool IsLeaveWindow() const
Definition: event.hxx:124
DrawFlags
Definition: window.hxx:354
OutDevType
Definition: outdev.hxx:278
The edit field part of a control, e.g.
bool IsNativeWidgetEnabled() const
Definition: window.cxx:3704
bool mbInitialUp
Definition: spinfld.hxx:86
virtual void StateChanged(StateChangedType nType) override
Definition: edit.cxx:2145
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:1156
ControlState mnLowerState
virtual OUString GetText() const override
Definition: edit.cxx:2564
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:304
CommandEventId GetCommand() const
void SetZoom(const Fraction &rZoom)
Definition: window2.cxx:365
virtual void FillLayoutData() const override
Definition: spinfld.cxx:573
DrawSymbolFlags
Definition: decoview.hxx:34
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 SetSubEdit(Edit *pEdit)
Definition: edit.cxx:2604
WinBits const WB_DROPDOWN
const AllSettings & GetSettings() const
Definition: outdev.hxx:420
Size GetOutputSizePixel() const
Definition: outdev.hxx:441
void SetTimeout(sal_uInt64 nTimeoutMs)
Definition: timer.cxx:89
Point ScreenToOutputPixel(const Point &rPos) const
Definition: window.cxx:2825
void GrabFocus()
Definition: window.cxx:2981
virtual Size CalcSize(sal_Int32 nChars) const override
Definition: spinfld.cxx:933
long X() const
Size GetSize() const
WinBits const WB_REPEAT
WinBits const WB_NOBORDER
vcl::Window * GetWindow(GetWindowType nType) const
Definition: stacking.cxx:1035
SAL_DLLPRIVATE void ImplInitSpinFieldData()
Definition: spinfld.cxx:293
Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:940
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:2687
bool IsModifierChanged() const
Definition: event.hxx:128
void EndDropDown()
Definition: spinfld.cxx:883
bool mbSpin
Definition: spinfld.hxx:86
const vcl::KeyCode & GetKeyCode() const
Definition: event.hxx:53
static SAL_DLLPRIVATE void ImplInvalidateOutermostBorder(vcl::Window *pWin)
Definition: edit.cxx:1817
virtual void First()
Definition: spinfld.cxx:369
void SetFaceColor(const Color &rColor)
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: spinfld.cxx:813
bool IsMouseOver() const
Definition: mouse.cxx:605
SAL_DLLPRIVATE void ImplInit(vcl::Window *pParent, WinBits nStyle)
Definition: spinfld.cxx:305
virtual void Resize() override
Definition: ctrl.cxx:74
#define KEY_DOWN
Definition: keycodes.hxx:110
long AdjustRight(long nHorzMoveDelta)
void Stop()
Definition: scheduler.cxx:593
WindowType
long GetDelta() const
bool IsSynthetic() const
Definition: event.hxx:126
Link< SpinField &, void > maUpHdlLink
Definition: spinfld.hxx:84
const Color & GetButtonTextColor() const
bool mbNoFocusRects
Definition: svdata.hxx:276
#define SAL_WARN_IF(condition, area, stream)
virtual void DataChanged(const DataChangedEvent &rDCEvt) override
Definition: edit.cxx:2226
const MouseEvent * GetMouseEvent() const
Definition: event.hxx:310
std::unique_ptr< vcl::ImplControlData > mpControlData
Definition: ctrl.hxx:36
virtual void MouseButtonDown(const MouseEvent &rMEvt) override
Definition: edit.cxx:1304
static std::unique_ptr< UIObject > create(vcl::Window *pWindow)
bool IsLeft() const
Definition: event.hxx:133
virtual Size CalcMinimumSize() const override
Definition: spinfld.cxx:923
bool mbLowerIn
Definition: spinfld.hxx:86
virtual void Last()
Definition: spinfld.cxx:374
long AdjustTop(long nVertMoveDelta)
virtual void Resize() override
Definition: spinfld.cxx:693
bool mbRepeat
Definition: spinfld.hxx:86
long GetSpinSize() const
void SetInvokeHandler(const Link< Timer *, void > &rLink)
Definition: timer.hxx:56
const Point & GetPosPixel() const
Definition: event.hxx:117
long Left() const
void set(reference_type *pBody)
Definition: vclptr.hxx:148
virtual bool PreNotify(NotifyEvent &rNEvt) override
Definition: spinfld.cxx:835
WindowType GetType() const
Definition: window2.cxx:963
virtual vcl::Region GetActiveClipRegion() const override
bool IsEnabled() const
Definition: window2.cxx:1111
virtual void MouseMove(const MouseEvent &rMEvt)
Definition: mouse.cxx:407
void DrawSymbol(const tools::Rectangle &rRect, SymbolType eType, const Color &rColor, DrawSymbolFlags nStyle=DrawSymbolFlags::NONE)
Definition: decoview.cxx:805
MouseWheelBehaviour
Definition: settings.hxx:83
WinBits GetStyle() const
Definition: window2.cxx:942
Definition: timer.hxx:26
Point OutputToScreenPixel(const Point &rPos) const
Definition: window.cxx:2819
virtual bool IsReadOnly() const
Definition: edit.hxx:181
Point GetLastPointerPosPixel()
Definition: mouse.cxx:561
long GetScrollBarSize() const
virtual Size CalcMinimumSizeForText(const OUString &rString) const override
Definition: spinfld.cxx:894
virtual void Draw(OutputDevice *pDev, const Point &rPos, const Size &rSize, DrawFlags nFlags) override
Definition: edit.cxx:1728
vcl::Font GetControlFont() const
Definition: window2.cxx:438
bool HasFocus() const
Definition: window.cxx:2986
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:3815
void setWidth(long nWidth)
SpinField(vcl::Window *pParent, WinBits nWinStyle)
Definition: spinfld.cxx:340
virtual void SetPosPixel(const Point &rNewPos)
Definition: window2.cxx:1246
VclPtr< Edit > mpEdit
Definition: spinfld.hxx:82
virtual void Draw(OutputDevice *pDev, const Point &rPos, const Size &rSize, DrawFlags nFlags) override
Definition: spinfld.cxx:961
SAL_DLLPRIVATE void ImplInit(vcl::Window *pParent, WinBits nStyle)
Definition: edit.cxx:297
long Y() const
tools::Rectangle maUpperRect
Definition: spinfld.hxx:63
virtual void StateChanged(StateChangedType nType) override
Definition: spinfld.cxx:754
void SetLayoutDataParent(const Control *pParent) const
Definition: ctrl.cxx:324
#define KEY_UP
Definition: keycodes.hxx:111
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:2151