1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/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>
28 #include <controldata.hxx>
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
)
39 // convert spinbutton data to a SpinbuttonValue structure for native painting
41 rValue
.maUpperRect
= rUpperRect
;
42 rValue
.maLowerRect
= rLowerRect
;
44 Point aPointerPos
= pWin
->GetPointerPosPixel();
46 ControlState nState
= ControlState::ENABLED
;
48 nState
|= ControlState::PRESSED
;
49 if (!pWin
->IsEnabled() || !bUpperEnabled
)
50 nState
&= ~ControlState::ENABLED
;
52 nState
|= ControlState::FOCUSED
;
53 if (pWin
->IsMouseOver() && rUpperRect
.IsInside(aPointerPos
))
54 nState
|= ControlState::ROLLOVER
;
55 rValue
.mnUpperState
= nState
;
57 nState
= ControlState::ENABLED
;
59 nState
|= ControlState::PRESSED
;
60 if (!pWin
->IsEnabled() || !bLowerEnabled
)
61 nState
&= ~ControlState::ENABLED
;
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
;
69 rValue
.mnUpperPart
= bHorz
? ControlPart::ButtonLeft
: ControlPart::ButtonUp
;
70 rValue
.mnLowerPart
= bHorz
? ControlPart::ButtonRight
: ControlPart::ButtonDown
;
73 bool ImplDrawNativeSpinfield(vcl::RenderContext
& rRenderContext
, vcl::Window
const * pWin
, const SpinbuttonValue
& rSpinbuttonValue
)
75 bool bNativeOK
= false;
77 if (rRenderContext
.IsNativeControlSupported(ControlType::Spinbox
, ControlPart::Entire
) &&
78 // there is just no useful native support for spinfields with dropdown
79 !(pWin
->GetStyle() & WB_DROPDOWN
))
81 if (rRenderContext
.IsNativeControlSupported(ControlType::Spinbox
, rSpinbuttonValue
.mnUpperPart
) &&
82 rRenderContext
.IsNativeControlSupported(ControlType::Spinbox
, rSpinbuttonValue
.mnLowerPart
))
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());
91 // paint the spinbox as a whole, use borderwindow to have proper clipping
92 vcl::Window
* pBorder
= pWin
->GetWindow(GetWindowType::Border
);
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
);
98 vcl::RenderContext
* pContext
= &rRenderContext
;
101 Size
aSize(pBorder
->GetOutputSizePixel()); // the size of the border window, i.e., the whole control
102 tools::Rectangle
aNatRgn(aPt
, aSize
);
104 if (!pWin
->SupportsDoubleBuffering())
106 // convert from screen space to borderwin space
107 aClipRect
.SetPos(pBorder
->ScreenToOutputPixel(pWin
->OutputToScreenPixel(aClipRect
.TopLeft())));
109 oldRgn
= pBorder
->GetClipRegion();
110 pBorder
->SetClipRegion(vcl::Region(aClipRect
));
115 tools::Rectangle aBound
, aContent
;
116 if (!ImplGetSVData()->maNWFData
.mbCanDrawWidgetAnySize
&&
117 pContext
->GetNativeControlRegion(ControlType::Spinbox
, ControlPart::Entire
,
118 aNatRgn
, ControlState::NONE
, rSpinbuttonValue
,
121 aSize
= aContent
.GetSize();
124 tools::Rectangle
aRgn(aPt
, aSize
);
125 if (pWin
->SupportsDoubleBuffering())
127 // convert from borderwin space, to the pWin's space
128 aRgn
.SetPos(pWin
->ScreenToOutputPixel(pBorder
->OutputToScreenPixel(aRgn
.TopLeft())));
131 bNativeOK
= pContext
->DrawNativeControl(ControlType::Spinbox
, ControlPart::Entire
, aRgn
,
132 ControlState::ENABLED
, rSpinbuttonValue
, OUString());
134 if (!pWin
->SupportsDoubleBuffering())
135 pBorder
->SetClipRegion(oldRgn
);
141 bool ImplDrawNativeSpinbuttons(vcl::RenderContext
& rRenderContext
, const SpinbuttonValue
& rSpinbuttonValue
)
143 bool bNativeOK
= false;
145 if (rRenderContext
.IsNativeControlSupported(ControlType::SpinButtons
, ControlPart::Entire
))
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());
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
)
162 bool bNativeOK
= false;
166 // are we drawing standalone spin buttons or members of a spinfield ?
167 ControlType aControl
= ControlType::SpinButtons
;
168 switch (pWindow
->GetType())
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
;
182 aControl
= ControlType::SpinButtons
;
186 SpinbuttonValue aValue
;
187 ImplGetSpinbuttonValue(pWindow
, rUpperRect
, rLowerRect
,
188 bUpperIn
, bLowerIn
, bUpperEnabled
, bLowerEnabled
,
191 if( aControl
== ControlType::Spinbox
)
192 bNativeOK
= ImplDrawNativeSpinfield(rRenderContext
, pWindow
, aValue
);
193 else if( aControl
== ControlType::SpinButtons
)
194 bNativeOK
= ImplDrawNativeSpinbuttons(rRenderContext
, aValue
);
200 ImplDrawUpDownButtons(rRenderContext
,
201 rUpperRect
, rLowerRect
,
202 bUpperIn
, bLowerIn
, bUpperEnabled
, bLowerEnabled
,
206 void ImplDrawUpDownButtons(vcl::RenderContext
& rRenderContext
,
207 const tools::Rectangle
& rUpperRect
, const tools::Rectangle
& rLowerRect
,
208 bool bUpperIn
, bool bLowerIn
, bool bUpperEnabled
, bool bLowerEnabled
,
209 bool bHorz
, bool bMirrorHorz
)
211 DecorationView
aDecoView(&rRenderContext
);
213 SymbolType eType1
, eType2
;
217 eType1
= bMirrorHorz
? SymbolType::SPIN_RIGHT
: SymbolType::SPIN_LEFT
;
218 eType2
= bMirrorHorz
? SymbolType::SPIN_LEFT
: SymbolType::SPIN_RIGHT
;
222 eType1
= SymbolType::SPIN_UP
;
223 eType2
= SymbolType::SPIN_DOWN
;
226 DrawButtonFlags nStyle
= DrawButtonFlags::NoLeftLightBorder
;
227 // draw upper/left Button
229 nStyle
|= DrawButtonFlags::Pressed
;
231 tools::Rectangle aUpRect
= aDecoView
.DrawButton(rUpperRect
, nStyle
);
233 nStyle
= DrawButtonFlags::NoLeftLightBorder
;
234 // draw lower/right Button
236 nStyle
|= DrawButtonFlags::Pressed
;
238 tools::Rectangle aLowRect
= aDecoView
.DrawButton(rLowerRect
, nStyle
);
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 );
250 // draw into the edge, so that something is visible if the rectangle is too small
251 if (aUpRect
.GetHeight() < 4)
253 aUpRect
.AdjustRight( 1 );
254 aUpRect
.AdjustBottom( 1 );
255 aLowRect
.AdjustRight( 1 );
256 aLowRect
.AdjustBottom( 1 );
259 // calculate Symbol size
260 tools::Long nTempSize1
= aUpRect
.GetWidth();
261 tools::Long nTempSize2
= aLowRect
.GetWidth();
262 if (std::abs( nTempSize1
-nTempSize2
) == 1)
264 if (nTempSize1
> nTempSize2
)
265 aUpRect
.AdjustLeft( 1 );
267 aLowRect
.AdjustLeft( 1 );
269 nTempSize1
= aUpRect
.GetHeight();
270 nTempSize2
= aLowRect
.GetHeight();
271 if (std::abs(nTempSize1
- nTempSize2
) == 1)
273 if (nTempSize1
> nTempSize2
)
274 aUpRect
.AdjustTop( 1 );
276 aLowRect
.AdjustTop( 1 );
279 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
281 DrawSymbolFlags nSymStyle
= DrawSymbolFlags::NONE
;
283 nSymStyle
|= DrawSymbolFlags::Disable
;
284 aDecoView
.DrawSymbol(aUpRect
, eType1
, rStyleSettings
.GetButtonTextColor(), nSymStyle
);
286 nSymStyle
= DrawSymbolFlags::NONE
;
288 nSymStyle
|= DrawSymbolFlags::Disable
;
289 aDecoView
.DrawSymbol(aLowRect
, eType2
, rStyleSettings
.GetButtonTextColor(), nSymStyle
);
292 void SpinField::ImplInitSpinFieldData()
294 mpEdit
.disposeAndClear();
300 mbInitialDown
= false;
301 mbInDropDown
= false;
304 void SpinField::ImplInit(vcl::Window
* pParent
, WinBits nWinStyle
)
306 Edit::ImplInit( pParent
, nWinStyle
);
308 if (!(nWinStyle
& (WB_SPIN
| WB_DROPDOWN
)))
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
))
319 mpEdit
.set(VclPtr
<Edit
>::Create(this, WB_NOBORDER
));
320 mpEdit
->SetBackground();
323 mpEdit
.set(VclPtr
<Edit
>::Create(this, WB_NOBORDER
));
325 mpEdit
->EnableRTL(false);
326 mpEdit
->SetPosPixel(Point());
331 maRepeatTimer
.SetInvokeHandler(LINK( this, SpinField
, ImplTimeout
));
332 maRepeatTimer
.SetTimeout(MouseSettings::GetButtonStartRepeat());
333 if (nWinStyle
& WB_REPEAT
)
336 SetCompoundControl(true);
339 SpinField::SpinField(vcl::Window
* pParent
, WinBits nWinStyle
, WindowType nType
) :
342 ImplInitSpinFieldData();
343 ImplInit(pParent
, nWinStyle
);
346 SpinField::~SpinField()
351 void SpinField::dispose()
353 mpEdit
.disposeAndClear();
360 ImplCallEventListenersAndHandler( VclEventId::SpinfieldUp
, [this] () { maUpHdlLink
.Call(*this); } );
363 void SpinField::Down()
365 ImplCallEventListenersAndHandler( VclEventId::SpinfieldDown
, [this] () { maDownHdlLink
.Call(*this); } );
368 void SpinField::First()
370 ImplCallEventListenersAndHandler(VclEventId::SpinfieldFirst
, nullptr);
373 void SpinField::Last()
375 ImplCallEventListenersAndHandler(VclEventId::SpinfieldLast
, nullptr);
378 void SpinField::MouseButtonDown( const MouseEvent
& rMEvt
)
380 if (!HasFocus() && (!mpEdit
|| !mpEdit
->HasFocus()))
387 if (maUpperRect
.IsInside(rMEvt
.GetPosPixel()))
391 Invalidate(maUpperRect
);
393 else if (maLowerRect
.IsInside(rMEvt
.GetPosPixel()))
396 mbInitialDown
= true;
397 Invalidate(maLowerRect
);
399 else if (maDropDownRect
.IsInside(rMEvt
.GetPosPixel()))
401 // put DropDownButton to the right
402 mbInDropDown
= ShowDropDown( !mbInDropDown
);
403 Invalidate(tools::Rectangle(Point(), GetOutputSizePixel()));
406 if (mbUpperIn
|| mbLowerIn
)
410 maRepeatTimer
.Start();
415 Edit::MouseButtonDown(rMEvt
);
418 void SpinField::MouseButtonUp(const MouseEvent
& rMEvt
)
421 mbInitialUp
= mbInitialDown
= false;
422 maRepeatTimer
.Stop();
423 maRepeatTimer
.SetTimeout(MouseSettings::GetButtonStartRepeat());
428 Invalidate(maUpperRect
);
434 Invalidate(maLowerRect
);
438 Edit::MouseButtonUp(rMEvt
);
441 void SpinField::MouseMove(const MouseEvent
& rMEvt
)
447 bool bNewUpperIn
= maUpperRect
.IsInside(rMEvt
.GetPosPixel());
448 if (bNewUpperIn
!= mbUpperIn
)
453 maRepeatTimer
.Start();
456 maRepeatTimer
.Stop();
458 mbUpperIn
= bNewUpperIn
;
459 Invalidate(maUpperRect
);
462 else if (mbInitialDown
)
464 bool bNewLowerIn
= maLowerRect
.IsInside(rMEvt
.GetPosPixel());
465 if (bNewLowerIn
!= mbLowerIn
)
470 maRepeatTimer
.Start();
473 maRepeatTimer
.Stop();
475 mbLowerIn
= bNewLowerIn
;
476 Invalidate(maLowerRect
);
481 Edit::MouseMove(rMEvt
);
484 bool SpinField::EventNotify(NotifyEvent
& rNEvt
)
487 if (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
)
489 const KeyEvent
& rKEvt
= *rNEvt
.GetKeyEvent();
492 sal_uInt16 nMod
= rKEvt
.GetKeyCode().GetModifier();
493 switch (rKEvt
.GetKeyCode().GetCode())
511 else if ((nMod
== KEY_MOD2
) && !mbInDropDown
&& (GetStyle() & WB_DROPDOWN
))
513 mbInDropDown
= ShowDropDown(true);
514 Invalidate(tools::Rectangle(Point(), GetOutputSizePixel()));
541 if (rNEvt
.GetType() == MouseNotifyEvent::COMMAND
)
543 if ((rNEvt
.GetCommandEvent()->GetCommand() == CommandEventId::Wheel
) && !IsReadOnly())
545 MouseWheelBehaviour
nWheelBehavior(GetSettings().GetMouseSettings().GetWheelBehavior());
546 if (nWheelBehavior
== MouseWheelBehaviour::ALWAYS
547 || (nWheelBehavior
== MouseWheelBehaviour::FocusOnly
&& HasChildPathFocus()))
549 const CommandWheelData
* pData
= rNEvt
.GetCommandEvent()->GetWheelData();
550 if (pData
->GetMode() == CommandWheelMode::SCROLL
)
552 if (pData
->GetDelta() < 0)
558 if (!HasChildPathFocus())
563 bDone
= false; // don't eat this event, let the default handling happen (i.e. scroll the context)
567 return bDone
|| Edit::EventNotify(rNEvt
);
570 void SpinField::FillLayoutData() const
574 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
575 AppendLayoutData(*GetSubEdit());
576 GetSubEdit()->SetLayoutDataParent(this);
579 Edit::FillLayoutData();
582 void SpinField::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
586 bool bEnable
= IsEnabled();
587 ImplDrawSpinButton(rRenderContext
, this, maUpperRect
, maLowerRect
,
588 mbUpperIn
, mbLowerIn
, bEnable
, bEnable
);
591 if (GetStyle() & WB_DROPDOWN
)
593 DecorationView
aView(&rRenderContext
);
595 DrawButtonFlags nStyle
= DrawButtonFlags::NoLightBorder
;
597 nStyle
|= DrawButtonFlags::Pressed
;
598 tools::Rectangle aInnerRect
= aView
.DrawButton(maDropDownRect
, nStyle
);
600 DrawSymbolFlags nSymbolStyle
= IsEnabled() ? DrawSymbolFlags::NONE
: DrawSymbolFlags::Disable
;
601 aView
.DrawSymbol(aInnerRect
, SymbolType::SPIN_DOWN
, rRenderContext
.GetSettings().GetStyleSettings().GetButtonTextColor(), nSymbolStyle
);
604 Edit::Paint(rRenderContext
, rRect
);
607 void SpinField::ImplCalcButtonAreas(OutputDevice
* pDev
, const Size
& rOutSz
, tools::Rectangle
& rDDArea
,
608 tools::Rectangle
& rSpinUpArea
, tools::Rectangle
& rSpinDownArea
)
610 const StyleSettings
& rStyleSettings
= pDev
->GetSettings().GetStyleSettings();
615 if (GetStyle() & WB_DROPDOWN
)
617 tools::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 );
627 // calculate sizes according to the height
628 if (GetStyle() & WB_SPIN
)
630 tools::Long nBottom1
= aSize
.Height()/2;
631 tools::Long nBottom2
= aSize
.Height()-1;
632 tools::Long nTop2
= nBottom1
;
633 if ( !(aSize
.Height() & 0x01) )
636 bool bNativeRegionOK
= false;
637 tools::Rectangle aContentUp
, aContentDown
;
639 if ((pDev
->GetOutDevType() == OUTDEV_WINDOW
) &&
640 // there is just no useful native support for spinfields with dropdown
641 ! (GetStyle() & WB_DROPDOWN
) &&
642 IsNativeControlSupported(ControlType::Spinbox
, ControlPart::Entire
))
644 vcl::Window
*pWin
= static_cast<vcl::Window
*>(pDev
);
645 vcl::Window
*pBorder
= pWin
->GetWindow( GetWindowType::Border
);
647 // get the system's spin button size
648 ImplControlValue aControlValue
;
649 tools::Rectangle aBound
;
652 // use the full extent of the control
653 tools::Rectangle
aArea( aPoint
, pBorder
->GetOutputSizePixel() );
656 pWin
->GetNativeControlRegion(ControlType::Spinbox
, ControlPart::ButtonUp
,
657 aArea
, ControlState::NONE
, aControlValue
, aBound
, aContentUp
) &&
658 pWin
->GetNativeControlRegion(ControlType::Spinbox
, ControlPart::ButtonDown
,
659 aArea
, ControlState::NONE
, aControlValue
, aBound
, aContentDown
);
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());
672 rSpinUpArea
= aContentUp
;
673 rSpinDownArea
= aContentDown
;
677 aSize
.AdjustWidth( -(CalcZoom( GetDrawPixel( pDev
, rStyleSettings
.GetSpinSize() ) )) );
679 rSpinUpArea
= tools::Rectangle( aSize
.Width(), 0, rOutSz
.Width()-aDropDownSize
.Width()-1, nBottom1
);
680 rSpinDownArea
= tools::Rectangle( rSpinUpArea
.Left(), nTop2
, rSpinUpArea
.Right(), nBottom2
);
685 rSpinUpArea
.SetEmpty();
686 rSpinDownArea
.SetEmpty();
690 void SpinField::Resize()
696 Size aSize
= GetOutputSizePixel();
697 bool bSubEditPositioned
= false;
699 if (GetStyle() & (WB_SPIN
| WB_DROPDOWN
))
701 ImplCalcButtonAreas( this, aSize
, maDropDownRect
, maUpperRect
, maLowerRect
);
703 ImplControlValue aControlValue
;
705 tools::Rectangle aContent
, aBound
;
707 // use the full extent of the control
708 vcl::Window
*pBorder
= GetWindow( GetWindowType::Border
);
709 tools::Rectangle
aArea( aPoint
, pBorder
->GetOutputSizePixel() );
711 // adjust position and size of the edit field
712 if (GetNativeControlRegion(ControlType::Spinbox
, ControlPart::SubEdit
, aArea
, ControlState::NONE
,
713 aControlValue
, aBound
, aContent
) &&
714 // there is just no useful native support for spinfields with dropdown
715 !(GetStyle() & WB_DROPDOWN
))
717 // convert back from border space to local coordinates
718 aPoint
= pBorder
->ScreenToOutputPixel(OutputToScreenPixel(aPoint
));
719 aContent
.Move(-aPoint
.X(), -aPoint
.Y());
721 // use the themes drop down size
722 mpEdit
->SetPosPixel( aContent
.TopLeft() );
723 bSubEditPositioned
= true;
724 aSize
= aContent
.GetSize();
728 if (maUpperRect
.IsEmpty())
730 SAL_WARN_IF( maDropDownRect
.IsEmpty(), "vcl", "SpinField::Resize: SPIN && DROPDOWN, but all empty rects?" );
731 aSize
.setWidth( maDropDownRect
.Left() );
734 aSize
.setWidth( maUpperRect
.Left() );
738 if (!bSubEditPositioned
)
740 // this moves our sub edit if RTL gets switched
741 mpEdit
->SetPosPixel(Point());
743 mpEdit
->SetSizePixel(aSize
);
745 if (GetStyle() & WB_SPIN
)
746 Invalidate(tools::Rectangle(maUpperRect
.TopLeft(), maLowerRect
.BottomRight()));
747 if (GetStyle() & WB_DROPDOWN
)
748 Invalidate(maDropDownRect
);
751 void SpinField::StateChanged(StateChangedType nType
)
753 Edit::StateChanged(nType
);
755 if (nType
== StateChangedType::Enable
)
757 if (mbSpin
|| (GetStyle() & WB_DROPDOWN
))
759 mpEdit
->Enable(IsEnabled());
763 Invalidate(maLowerRect
);
764 Invalidate(maUpperRect
);
766 if (GetStyle() & WB_DROPDOWN
)
767 Invalidate(maDropDownRect
);
770 else if (nType
== StateChangedType::Style
)
772 if (GetStyle() & WB_REPEAT
)
777 else if (nType
== StateChangedType::Zoom
)
781 mpEdit
->SetZoom(GetZoom());
784 else if (nType
== StateChangedType::ControlFont
)
787 mpEdit
->SetControlFont(GetControlFont());
790 else if (nType
== StateChangedType::ControlForeground
)
793 mpEdit
->SetControlForeground(GetControlForeground());
796 else if (nType
== StateChangedType::ControlBackground
)
799 mpEdit
->SetControlBackground(GetControlBackground());
802 else if( nType
== StateChangedType::Mirroring
)
805 mpEdit
->CompatStateChanged(StateChangedType::Mirroring
);
810 void SpinField::DataChanged( const DataChangedEvent
& rDCEvt
)
812 Edit::DataChanged(rDCEvt
);
814 if ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
815 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))
822 tools::Rectangle
* SpinField::ImplFindPartRect(const Point
& rPt
)
824 if (maUpperRect
.IsInside(rPt
))
826 else if (maLowerRect
.IsInside(rPt
))
832 bool SpinField::PreNotify(NotifyEvent
& rNEvt
)
834 if (rNEvt
.GetType() == MouseNotifyEvent::MOUSEMOVE
)
836 const MouseEvent
* pMouseEvt
= rNEvt
.GetMouseEvent();
837 if (pMouseEvt
&& !pMouseEvt
->GetButtons() && !pMouseEvt
->IsSynthetic() && !pMouseEvt
->IsModifierChanged())
839 // trigger redraw if mouse over state has changed
840 if( IsNativeControlSupported(ControlType::Spinbox
, ControlPart::Entire
) ||
841 IsNativeControlSupported(ControlType::Spinbox
, ControlPart::AllButtons
) )
843 tools::Rectangle
* pRect
= ImplFindPartRect( GetPointerPosPixel() );
844 tools::Rectangle
* pLastRect
= ImplFindPartRect( GetLastPointerPosPixel() );
845 if( pRect
!= pLastRect
|| (pMouseEvt
->IsLeaveWindow() || pMouseEvt
->IsEnterWindow()) )
847 // FIXME: this is currently only on macOS
848 // check for other platforms that need similar handling
849 if (ImplGetSVData()->maNWFData
.mbNoFocusRects
&& IsNativeWidgetEnabled() &&
850 IsNativeControlSupported(ControlType::Editbox
, ControlPart::Entire
))
852 ImplInvalidateOutermostBorder(this);
857 vcl::Region
aRgn( GetActiveClipRegion() );
860 SetClipRegion(vcl::Region(*pLastRect
));
861 Invalidate(*pLastRect
);
862 SetClipRegion( aRgn
);
866 SetClipRegion(vcl::Region(*pRect
));
868 SetClipRegion( aRgn
);
876 return Edit::PreNotify(rNEvt
);
879 void SpinField::EndDropDown()
881 mbInDropDown
= false;
882 Invalidate(tools::Rectangle(Point(), GetOutputSizePixel()));
885 bool SpinField::ShowDropDown( bool )
890 Size
SpinField::CalcMinimumSizeForText(const OUString
&rString
) const
892 Size aSz
= Edit::CalcMinimumSizeForText(rString
);
894 if ( GetStyle() & WB_DROPDOWN
)
895 aSz
.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
896 if ( GetStyle() & WB_SPIN
)
898 ImplControlValue aControlValue
;
899 tools::Rectangle
aArea( Point(), Size(100, aSz
.Height()));
900 tools::Rectangle aEntireBound
, aEntireContent
, aEditBound
, aEditContent
;
902 GetNativeControlRegion(ControlType::Spinbox
, ControlPart::Entire
,
903 aArea
, ControlState::NONE
, aControlValue
, aEntireBound
, aEntireContent
) &&
904 GetNativeControlRegion(ControlType::Spinbox
, ControlPart::SubEdit
,
905 aArea
, ControlState::NONE
, aControlValue
, aEditBound
, aEditContent
)
908 aSz
.AdjustWidth(aEntireContent
.GetWidth() - aEditContent
.GetWidth());
912 aSz
.AdjustWidth(maUpperRect
.GetWidth() );
919 Size
SpinField::CalcMinimumSize() const
921 return CalcMinimumSizeForText(GetText());
924 Size
SpinField::GetOptimalSize() const
926 return CalcMinimumSize();
929 Size
SpinField::CalcSize(sal_Int32 nChars
) const
931 Size aSz
= Edit::CalcSize( nChars
);
933 if ( GetStyle() & WB_DROPDOWN
)
934 aSz
.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
935 if ( GetStyle() & WB_SPIN
)
936 aSz
.AdjustWidth(GetSettings().GetStyleSettings().GetSpinSize() );
941 IMPL_LINK( SpinField
, ImplTimeout
, Timer
*, pTimer
, void )
943 if ( pTimer
->GetTimeout() == MouseSettings::GetButtonStartRepeat() )
945 pTimer
->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
957 void SpinField::Draw(OutputDevice
* pDev
, const Point
& rPos
, DrawFlags nFlags
)
959 Edit::Draw(pDev
, rPos
, nFlags
);
961 WinBits nFieldStyle
= GetStyle();
962 if ( (nFlags
& DrawFlags::NoControls
) || !( nFieldStyle
& (WB_SPIN
|WB_DROPDOWN
) ) )
965 Point aPos
= pDev
->LogicToPixel( rPos
);
966 Size aSize
= GetSizePixel();
967 AllSettings aOldSettings
= pDev
->GetSettings();
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());
977 aDown
.Move(aPos
.X(), aPos
.Y());
979 Color aButtonTextColor
;
980 if (nFlags
& DrawFlags::Mono
)
981 aButtonTextColor
= COL_BLACK
;
983 aButtonTextColor
= GetSettings().GetStyleSettings().GetButtonTextColor();
985 if (GetStyle() & WB_DROPDOWN
)
987 DecorationView
aView( pDev
);
988 tools::Rectangle aInnerRect
= aView
.DrawButton( aDD
, DrawButtonFlags::NoLightBorder
);
989 DrawSymbolFlags nSymbolStyle
= IsEnabled() ? DrawSymbolFlags::NONE
: DrawSymbolFlags::Disable
;
990 aView
.DrawSymbol(aInnerRect
, SymbolType::SPIN_DOWN
, aButtonTextColor
, nSymbolStyle
);
993 if (GetStyle() & WB_SPIN
)
995 ImplDrawSpinButton(*pDev
, this, aUp
, aDown
, false, false);
999 pDev
->SetSettings(aOldSettings
);
1003 FactoryFunction
SpinField::GetUITestFactory() const
1005 return SpinFieldUIObject::create
;
1008 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */