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>
33 void ImplGetSpinbuttonValue(vcl::Window
* pWin
,
34 const tools::Rectangle
& rUpperRect
, const tools::Rectangle
& rLowerRect
,
35 bool bUpperIn
, bool bLowerIn
, bool bUpperEnabled
, bool bLowerEnabled
,
36 bool bHorz
, SpinbuttonValue
& rValue
)
38 // convert spinbutton data to a SpinbuttonValue structure for native painting
40 rValue
.maUpperRect
= rUpperRect
;
41 rValue
.maLowerRect
= rLowerRect
;
43 Point aPointerPos
= pWin
->GetPointerPosPixel();
45 ControlState nState
= ControlState::ENABLED
;
47 nState
|= ControlState::PRESSED
;
48 if (!pWin
->IsEnabled() || !bUpperEnabled
)
49 nState
&= ~ControlState::ENABLED
;
51 nState
|= ControlState::FOCUSED
;
52 if (pWin
->IsMouseOver() && rUpperRect
.Contains(aPointerPos
))
53 nState
|= ControlState::ROLLOVER
;
54 rValue
.mnUpperState
= nState
;
56 nState
= ControlState::ENABLED
;
58 nState
|= ControlState::PRESSED
;
59 if (!pWin
->IsEnabled() || !bLowerEnabled
)
60 nState
&= ~ControlState::ENABLED
;
62 nState
|= ControlState::FOCUSED
;
63 // for overlapping spins: highlight only one
64 if (pWin
->IsMouseOver() && rLowerRect
.Contains(aPointerPos
) && !rUpperRect
.Contains(aPointerPos
))
65 nState
|= ControlState::ROLLOVER
;
66 rValue
.mnLowerState
= nState
;
68 rValue
.mnUpperPart
= bHorz
? ControlPart::ButtonLeft
: ControlPart::ButtonUp
;
69 rValue
.mnLowerPart
= bHorz
? ControlPart::ButtonRight
: ControlPart::ButtonDown
;
72 bool ImplDrawNativeSpinfield(vcl::RenderContext
& rRenderContext
, vcl::Window
const * pWin
, const SpinbuttonValue
& rSpinbuttonValue
)
74 bool bNativeOK
= false;
76 if (rRenderContext
.IsNativeControlSupported(ControlType::Spinbox
, ControlPart::Entire
) &&
77 // there is just no useful native support for spinfields with dropdown
78 !(pWin
->GetStyle() & WB_DROPDOWN
))
80 if (rRenderContext
.IsNativeControlSupported(ControlType::Spinbox
, rSpinbuttonValue
.mnUpperPart
) &&
81 rRenderContext
.IsNativeControlSupported(ControlType::Spinbox
, rSpinbuttonValue
.mnLowerPart
))
83 // only paint the embedded spin buttons, all buttons are painted at once
84 tools::Rectangle
aUpperAndLowerButtons( rSpinbuttonValue
.maUpperRect
.GetUnion( rSpinbuttonValue
.maLowerRect
) );
85 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::Spinbox
, ControlPart::AllButtons
, aUpperAndLowerButtons
,
86 ControlState::ENABLED
, rSpinbuttonValue
, OUString());
90 // paint the spinbox as a whole, use borderwindow to have proper clipping
91 vcl::Window
* pBorder
= pWin
->GetWindow(GetWindowType::Border
);
93 // to not overwrite everything, set the button region as clipregion to the border window
94 tools::Rectangle
aClipRect(rSpinbuttonValue
.maLowerRect
);
95 aClipRect
.Union(rSpinbuttonValue
.maUpperRect
);
97 vcl::RenderContext
* pContext
= &rRenderContext
;
100 Size
aSize(pBorder
->GetOutputSizePixel()); // the size of the border window, i.e., the whole control
101 tools::Rectangle
aNatRgn(aPt
, aSize
);
103 if (!pWin
->SupportsDoubleBuffering())
105 // convert from screen space to borderwin space
106 aClipRect
.SetPos(pBorder
->ScreenToOutputPixel(pWin
->OutputToScreenPixel(aClipRect
.TopLeft())));
108 oldRgn
= pBorder
->GetOutDev()->GetClipRegion();
109 pBorder
->GetOutDev()->SetClipRegion(vcl::Region(aClipRect
));
111 pContext
= pBorder
->GetOutDev();
114 tools::Rectangle aBound
, aContent
;
115 if (!ImplGetSVData()->maNWFData
.mbCanDrawWidgetAnySize
&&
116 pContext
->GetNativeControlRegion(ControlType::Spinbox
, ControlPart::Entire
,
117 aNatRgn
, ControlState::NONE
, rSpinbuttonValue
,
120 aSize
= aContent
.GetSize();
123 tools::Rectangle
aRgn(aPt
, aSize
);
124 if (pWin
->SupportsDoubleBuffering())
126 // convert from borderwin space, to the pWin's space
127 aRgn
.SetPos(pWin
->ScreenToOutputPixel(pBorder
->OutputToScreenPixel(aRgn
.TopLeft())));
130 bNativeOK
= pContext
->DrawNativeControl(ControlType::Spinbox
, ControlPart::Entire
, aRgn
,
131 ControlState::ENABLED
, rSpinbuttonValue
, OUString());
133 if (!pWin
->SupportsDoubleBuffering())
134 pBorder
->GetOutDev()->SetClipRegion(oldRgn
);
140 bool ImplDrawNativeSpinbuttons(vcl::RenderContext
& rRenderContext
, const SpinbuttonValue
& rSpinbuttonValue
)
142 bool bNativeOK
= false;
144 if (rRenderContext
.IsNativeControlSupported(ControlType::SpinButtons
, ControlPart::Entire
))
146 tools::Rectangle aArea
= rSpinbuttonValue
.maUpperRect
.GetUnion(rSpinbuttonValue
.maLowerRect
);
147 // only paint the standalone spin buttons, all buttons are painted at once
148 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::SpinButtons
, ControlPart::AllButtons
, aArea
,
149 ControlState::ENABLED
, rSpinbuttonValue
, OUString());
156 void ImplDrawSpinButton(vcl::RenderContext
& rRenderContext
, vcl::Window
* pWindow
,
157 const tools::Rectangle
& rUpperRect
, const tools::Rectangle
& rLowerRect
,
158 bool bUpperIn
, bool bLowerIn
, bool bUpperEnabled
, bool bLowerEnabled
,
159 bool bHorz
, bool bMirrorHorz
)
161 bool bNativeOK
= false;
165 // are we drawing standalone spin buttons or members of a spinfield ?
166 ControlType aControl
= ControlType::SpinButtons
;
167 switch (pWindow
->GetType())
169 case WindowType::EDIT
:
170 case WindowType::MULTILINEEDIT
:
171 case WindowType::PATTERNFIELD
:
172 case WindowType::METRICFIELD
:
173 case WindowType::CURRENCYFIELD
:
174 case WindowType::DATEFIELD
:
175 case WindowType::TIMEFIELD
:
176 case WindowType::SPINFIELD
:
177 case WindowType::FORMATTEDFIELD
:
178 aControl
= ControlType::Spinbox
;
181 aControl
= ControlType::SpinButtons
;
185 SpinbuttonValue aValue
;
186 ImplGetSpinbuttonValue(pWindow
, rUpperRect
, rLowerRect
,
187 bUpperIn
, bLowerIn
, bUpperEnabled
, bLowerEnabled
,
190 if( aControl
== ControlType::Spinbox
)
191 bNativeOK
= ImplDrawNativeSpinfield(rRenderContext
, pWindow
, aValue
);
192 else if( aControl
== ControlType::SpinButtons
)
193 bNativeOK
= ImplDrawNativeSpinbuttons(rRenderContext
, aValue
);
199 ImplDrawUpDownButtons(rRenderContext
,
200 rUpperRect
, rLowerRect
,
201 bUpperIn
, bLowerIn
, bUpperEnabled
, bLowerEnabled
,
205 void ImplDrawUpDownButtons(vcl::RenderContext
& rRenderContext
,
206 const tools::Rectangle
& rUpperRect
, const tools::Rectangle
& rLowerRect
,
207 bool bUpperIn
, bool bLowerIn
, bool bUpperEnabled
, bool bLowerEnabled
,
208 bool bHorz
, bool bMirrorHorz
)
210 DecorationView
aDecoView(&rRenderContext
);
212 SymbolType eType1
, eType2
;
216 eType1
= bMirrorHorz
? SymbolType::SPIN_RIGHT
: SymbolType::SPIN_LEFT
;
217 eType2
= bMirrorHorz
? SymbolType::SPIN_LEFT
: SymbolType::SPIN_RIGHT
;
221 eType1
= SymbolType::SPIN_UP
;
222 eType2
= SymbolType::SPIN_DOWN
;
225 DrawButtonFlags nStyle
= DrawButtonFlags::NoLeftLightBorder
;
226 // draw upper/left Button
228 nStyle
|= DrawButtonFlags::Pressed
;
230 tools::Rectangle aUpRect
= aDecoView
.DrawButton(rUpperRect
, nStyle
);
232 nStyle
= DrawButtonFlags::NoLeftLightBorder
;
233 // draw lower/right Button
235 nStyle
|= DrawButtonFlags::Pressed
;
237 tools::Rectangle aLowRect
= aDecoView
.DrawButton(rLowerRect
, nStyle
);
239 // make use of additional default edge
240 aUpRect
.AdjustLeft( -1 );
241 aUpRect
.AdjustTop( -1 );
242 aUpRect
.AdjustRight( 1 );
243 aUpRect
.AdjustBottom( 1 );
244 aLowRect
.AdjustLeft( -1 );
245 aLowRect
.AdjustTop( -1 );
246 aLowRect
.AdjustRight( 1 );
247 aLowRect
.AdjustBottom( 1 );
249 // draw into the edge, so that something is visible if the rectangle is too small
250 if (aUpRect
.GetHeight() < 4)
252 aUpRect
.AdjustRight( 1 );
253 aUpRect
.AdjustBottom( 1 );
254 aLowRect
.AdjustRight( 1 );
255 aLowRect
.AdjustBottom( 1 );
258 // calculate Symbol size
259 tools::Long nTempSize1
= aUpRect
.GetWidth();
260 tools::Long nTempSize2
= aLowRect
.GetWidth();
261 if (std::abs( nTempSize1
-nTempSize2
) == 1)
263 if (nTempSize1
> nTempSize2
)
264 aUpRect
.AdjustLeft( 1 );
266 aLowRect
.AdjustLeft( 1 );
268 nTempSize1
= aUpRect
.GetHeight();
269 nTempSize2
= aLowRect
.GetHeight();
270 if (std::abs(nTempSize1
- nTempSize2
) == 1)
272 if (nTempSize1
> nTempSize2
)
273 aUpRect
.AdjustTop( 1 );
275 aLowRect
.AdjustTop( 1 );
278 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
280 DrawSymbolFlags nSymStyle
= DrawSymbolFlags::NONE
;
282 nSymStyle
|= DrawSymbolFlags::Disable
;
283 aDecoView
.DrawSymbol(aUpRect
, eType1
, rStyleSettings
.GetButtonTextColor(), nSymStyle
);
285 nSymStyle
= DrawSymbolFlags::NONE
;
287 nSymStyle
|= DrawSymbolFlags::Disable
;
288 aDecoView
.DrawSymbol(aLowRect
, eType2
, rStyleSettings
.GetButtonTextColor(), nSymStyle
);
291 void SpinField::ImplInitSpinFieldData()
293 mpEdit
.disposeAndClear();
299 mbInitialDown
= false;
300 mbInDropDown
= false;
301 mbUpperEnabled
= true;
302 mbLowerEnabled
= true;
305 void SpinField::ImplInit(vcl::Window
* pParent
, WinBits nWinStyle
)
307 Edit::ImplInit( pParent
, nWinStyle
);
309 if (!(nWinStyle
& (WB_SPIN
| WB_DROPDOWN
)))
314 // Some themes want external spin buttons, therefore the main
315 // spinfield should not overdraw the border between its encapsulated
316 // edit field and the spin buttons
317 if ((nWinStyle
& WB_SPIN
) && ImplUseNativeBorder(*GetOutDev(), nWinStyle
))
320 mpEdit
.set(VclPtr
<Edit
>::Create(this, WB_NOBORDER
));
321 mpEdit
->SetBackground();
324 mpEdit
.set(VclPtr
<Edit
>::Create(this, WB_NOBORDER
));
326 mpEdit
->EnableRTL(false);
327 mpEdit
->SetPosPixel(Point());
332 maRepeatTimer
.SetInvokeHandler(LINK( this, SpinField
, ImplTimeout
));
333 maRepeatTimer
.SetTimeout(MouseSettings::GetButtonStartRepeat());
334 if (nWinStyle
& WB_REPEAT
)
337 SetCompoundControl(true);
340 SpinField::SpinField(vcl::Window
* pParent
, WinBits nWinStyle
, WindowType nType
) :
341 Edit(nType
), maRepeatTimer("SpinField maRepeatTimer")
343 ImplInitSpinFieldData();
344 ImplInit(pParent
, nWinStyle
);
347 SpinField::~SpinField()
352 void SpinField::dispose()
354 mpEdit
.disposeAndClear();
361 ImplCallEventListenersAndHandler( VclEventId::SpinfieldUp
, [this] () { maUpHdlLink
.Call(*this); } );
364 void SpinField::Down()
366 ImplCallEventListenersAndHandler( VclEventId::SpinfieldDown
, [this] () { maDownHdlLink
.Call(*this); } );
369 void SpinField::First()
371 ImplCallEventListenersAndHandler(VclEventId::SpinfieldFirst
, nullptr);
374 void SpinField::Last()
376 ImplCallEventListenersAndHandler(VclEventId::SpinfieldLast
, nullptr);
379 void SpinField::MouseButtonDown( const MouseEvent
& rMEvt
)
381 if (!HasFocus() && (!mpEdit
|| !mpEdit
->HasFocus()))
388 if (maUpperRect
.Contains(rMEvt
.GetPosPixel()))
392 Invalidate(maUpperRect
);
394 else if (maLowerRect
.Contains(rMEvt
.GetPosPixel()))
397 mbInitialDown
= true;
398 Invalidate(maLowerRect
);
400 else if (maDropDownRect
.Contains(rMEvt
.GetPosPixel()))
402 // put DropDownButton to the right
403 mbInDropDown
= ShowDropDown( !mbInDropDown
);
404 Invalidate(tools::Rectangle(Point(), GetOutputSizePixel()));
407 if (mbUpperIn
|| mbLowerIn
)
411 maRepeatTimer
.Start();
416 Edit::MouseButtonDown(rMEvt
);
419 void SpinField::MouseButtonUp(const MouseEvent
& rMEvt
)
422 mbInitialUp
= mbInitialDown
= false;
423 maRepeatTimer
.Stop();
424 maRepeatTimer
.SetTimeout(MouseSettings::GetButtonStartRepeat());
429 Invalidate(maUpperRect
);
435 Invalidate(maLowerRect
);
439 Edit::MouseButtonUp(rMEvt
);
442 void SpinField::MouseMove(const MouseEvent
& rMEvt
)
448 bool bNewUpperIn
= maUpperRect
.Contains(rMEvt
.GetPosPixel());
449 if (bNewUpperIn
!= mbUpperIn
)
454 maRepeatTimer
.Start();
457 maRepeatTimer
.Stop();
459 mbUpperIn
= bNewUpperIn
;
460 Invalidate(maUpperRect
);
463 else if (mbInitialDown
)
465 bool bNewLowerIn
= maLowerRect
.Contains(rMEvt
.GetPosPixel());
466 if (bNewLowerIn
!= mbLowerIn
)
471 maRepeatTimer
.Start();
474 maRepeatTimer
.Stop();
476 mbLowerIn
= bNewLowerIn
;
477 Invalidate(maLowerRect
);
482 Edit::MouseMove(rMEvt
);
485 bool SpinField::EventNotify(NotifyEvent
& rNEvt
)
488 if (rNEvt
.GetType() == NotifyEventType::KEYINPUT
)
490 const KeyEvent
& rKEvt
= *rNEvt
.GetKeyEvent();
493 sal_uInt16 nMod
= rKEvt
.GetKeyCode().GetModifier();
494 switch (rKEvt
.GetKeyCode().GetCode())
512 else if ((nMod
== KEY_MOD2
) && !mbInDropDown
&& (GetStyle() & WB_DROPDOWN
))
514 mbInDropDown
= ShowDropDown(true);
515 Invalidate(tools::Rectangle(Point(), GetOutputSizePixel()));
542 if (rNEvt
.GetType() == NotifyEventType::COMMAND
)
544 if ((rNEvt
.GetCommandEvent()->GetCommand() == CommandEventId::Wheel
) && !IsReadOnly())
546 MouseWheelBehaviour
nWheelBehavior(GetSettings().GetMouseSettings().GetWheelBehavior());
547 if (nWheelBehavior
== MouseWheelBehaviour::ALWAYS
548 || (nWheelBehavior
== MouseWheelBehaviour::FocusOnly
&& HasChildPathFocus()))
550 const CommandWheelData
* pData
= rNEvt
.GetCommandEvent()->GetWheelData();
551 if (pData
->GetMode() == CommandWheelMode::SCROLL
)
553 if (pData
->GetDelta() < 0)
559 if (!HasChildPathFocus())
564 bDone
= false; // don't eat this event, let the default handling happen (i.e. scroll the context)
568 return bDone
|| Edit::EventNotify(rNEvt
);
571 void SpinField::FillLayoutData() const
575 mxLayoutData
.emplace();
576 AppendLayoutData(*GetSubEdit());
577 GetSubEdit()->SetLayoutDataParent(this);
580 Edit::FillLayoutData();
583 void SpinField::SetUpperEnabled(bool bEnabled
)
585 if (mbUpperEnabled
== bEnabled
)
588 mbUpperEnabled
= bEnabled
;
591 Invalidate(maUpperRect
);
594 void SpinField::SetLowerEnabled(bool bEnabled
)
596 if (mbLowerEnabled
== bEnabled
)
599 mbLowerEnabled
= bEnabled
;
602 Invalidate(maLowerRect
);
605 void SpinField::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
609 bool bEnabled
= IsEnabled();
610 bool bUpperEnabled
= bEnabled
&& IsUpperEnabled();
611 bool bLowerEnabled
= bEnabled
&& IsLowerEnabled();
612 ImplDrawSpinButton(rRenderContext
, this, maUpperRect
, maLowerRect
,
613 mbUpperIn
&& bUpperEnabled
, mbLowerIn
&& bLowerEnabled
,
614 bUpperEnabled
, bLowerEnabled
);
617 if (GetStyle() & WB_DROPDOWN
)
619 DecorationView
aView(&rRenderContext
);
621 DrawButtonFlags nStyle
= DrawButtonFlags::NoLightBorder
;
623 nStyle
|= DrawButtonFlags::Pressed
;
624 tools::Rectangle aInnerRect
= aView
.DrawButton(maDropDownRect
, nStyle
);
626 DrawSymbolFlags nSymbolStyle
= IsEnabled() ? DrawSymbolFlags::NONE
: DrawSymbolFlags::Disable
;
627 aView
.DrawSymbol(aInnerRect
, SymbolType::SPIN_DOWN
, rRenderContext
.GetSettings().GetStyleSettings().GetButtonTextColor(), nSymbolStyle
);
630 Edit::Paint(rRenderContext
, rRect
);
633 void SpinField::ImplCalcButtonAreas(const OutputDevice
* pDev
, const Size
& rOutSz
, tools::Rectangle
& rDDArea
,
634 tools::Rectangle
& rSpinUpArea
, tools::Rectangle
& rSpinDownArea
)
636 const StyleSettings
& rStyleSettings
= pDev
->GetSettings().GetStyleSettings();
641 if (GetStyle() & WB_DROPDOWN
)
643 tools::Long nW
= rStyleSettings
.GetScrollBarSize();
644 nW
= GetDrawPixel( pDev
, nW
);
645 aDropDownSize
= Size( CalcZoom( nW
), aSize
.Height() );
646 aSize
.AdjustWidth( -(aDropDownSize
.Width()) );
647 rDDArea
= tools::Rectangle( Point( aSize
.Width(), 0 ), aDropDownSize
);
648 rDDArea
.AdjustTop( -1 );
653 // calculate sizes according to the height
654 if (GetStyle() & WB_SPIN
)
656 tools::Long nBottom1
= aSize
.Height()/2;
657 tools::Long nBottom2
= aSize
.Height()-1;
658 tools::Long nTop2
= nBottom1
;
659 if ( !(aSize
.Height() & 0x01) )
662 bool bNativeRegionOK
= false;
663 tools::Rectangle aContentUp
, aContentDown
;
665 if ((pDev
->GetOutDevType() == OUTDEV_WINDOW
) &&
666 // there is just no useful native support for spinfields with dropdown
667 ! (GetStyle() & WB_DROPDOWN
) &&
668 IsNativeControlSupported(ControlType::Spinbox
, ControlPart::Entire
))
670 vcl::Window
*pWin
= pDev
->GetOwnerWindow();
671 vcl::Window
*pBorder
= pWin
->GetWindow( GetWindowType::Border
);
673 // get the system's spin button size
674 ImplControlValue aControlValue
;
675 tools::Rectangle aBound
;
678 // use the full extent of the control
679 tools::Rectangle
aArea( aPoint
, pBorder
->GetOutputSizePixel() );
682 pWin
->GetNativeControlRegion(ControlType::Spinbox
, ControlPart::ButtonUp
,
683 aArea
, ControlState::NONE
, aControlValue
, aBound
, aContentUp
) &&
684 pWin
->GetNativeControlRegion(ControlType::Spinbox
, ControlPart::ButtonDown
,
685 aArea
, ControlState::NONE
, aControlValue
, aBound
, aContentDown
);
689 // convert back from border space to local coordinates
690 aPoint
= pBorder
->ScreenToOutputPixel( pWin
->OutputToScreenPixel( aPoint
) );
691 aContentUp
.Move(-aPoint
.X(), -aPoint
.Y());
692 aContentDown
.Move(-aPoint
.X(), -aPoint
.Y());
698 rSpinUpArea
= aContentUp
;
699 rSpinDownArea
= aContentDown
;
703 aSize
.AdjustWidth( -(CalcZoom( GetDrawPixel( pDev
, rStyleSettings
.GetSpinSize() ) )) );
705 rSpinUpArea
= tools::Rectangle( aSize
.Width(), 0, rOutSz
.Width()-aDropDownSize
.Width()-1, nBottom1
);
706 rSpinDownArea
= tools::Rectangle( rSpinUpArea
.Left(), nTop2
, rSpinUpArea
.Right(), nBottom2
);
711 rSpinUpArea
.SetEmpty();
712 rSpinDownArea
.SetEmpty();
716 void SpinField::Resize()
722 Size aSize
= GetOutputSizePixel();
723 bool bSubEditPositioned
= false;
725 if (GetStyle() & (WB_SPIN
| WB_DROPDOWN
))
727 ImplCalcButtonAreas( GetOutDev(), aSize
, maDropDownRect
, maUpperRect
, maLowerRect
);
729 ImplControlValue aControlValue
;
731 tools::Rectangle aContent
, aBound
;
733 // use the full extent of the control
734 vcl::Window
*pBorder
= GetWindow( GetWindowType::Border
);
735 tools::Rectangle
aArea( aPoint
, pBorder
->GetOutputSizePixel() );
737 // adjust position and size of the edit field
738 if (GetNativeControlRegion(ControlType::Spinbox
, ControlPart::SubEdit
, aArea
, ControlState::NONE
,
739 aControlValue
, aBound
, aContent
) &&
740 // there is just no useful native support for spinfields with dropdown
741 !(GetStyle() & WB_DROPDOWN
))
743 // convert back from border space to local coordinates
744 aPoint
= pBorder
->ScreenToOutputPixel(OutputToScreenPixel(aPoint
));
745 aContent
.Move(-aPoint
.X(), -aPoint
.Y());
747 // use the themes drop down size
748 mpEdit
->SetPosPixel( aContent
.TopLeft() );
749 bSubEditPositioned
= true;
750 aSize
= aContent
.GetSize();
754 if (maUpperRect
.IsEmpty())
756 SAL_WARN_IF( maDropDownRect
.IsEmpty(), "vcl", "SpinField::Resize: SPIN && DROPDOWN, but all empty rects?" );
757 aSize
.setWidth( maDropDownRect
.Left() );
760 aSize
.setWidth( maUpperRect
.Left() );
764 if (!bSubEditPositioned
)
766 // this moves our sub edit if RTL gets switched
767 mpEdit
->SetPosPixel(Point());
769 mpEdit
->SetSizePixel(aSize
);
771 if (GetStyle() & WB_SPIN
)
772 Invalidate(tools::Rectangle(maUpperRect
.TopLeft(), maLowerRect
.BottomRight()));
773 if (GetStyle() & WB_DROPDOWN
)
774 Invalidate(maDropDownRect
);
777 void SpinField::StateChanged(StateChangedType nType
)
779 Edit::StateChanged(nType
);
781 if (nType
== StateChangedType::Enable
)
783 if (mbSpin
|| (GetStyle() & WB_DROPDOWN
))
785 mpEdit
->Enable(IsEnabled());
789 Invalidate(maLowerRect
);
790 Invalidate(maUpperRect
);
792 if (GetStyle() & WB_DROPDOWN
)
793 Invalidate(maDropDownRect
);
796 else if (nType
== StateChangedType::Style
)
798 if (GetStyle() & WB_REPEAT
)
803 else if (nType
== StateChangedType::Zoom
)
807 mpEdit
->SetZoom(GetZoom());
810 else if (nType
== StateChangedType::ControlFont
)
813 mpEdit
->SetControlFont(GetControlFont());
816 else if (nType
== StateChangedType::ControlForeground
)
819 mpEdit
->SetControlForeground(GetControlForeground());
822 else if (nType
== StateChangedType::ControlBackground
)
825 mpEdit
->SetControlBackground(GetControlBackground());
828 else if( nType
== StateChangedType::Mirroring
)
831 mpEdit
->CompatStateChanged(StateChangedType::Mirroring
);
836 void SpinField::DataChanged( const DataChangedEvent
& rDCEvt
)
838 Edit::DataChanged(rDCEvt
);
840 if ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
841 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))
848 tools::Rectangle
* SpinField::ImplFindPartRect(const Point
& rPt
)
850 if (maUpperRect
.Contains(rPt
))
852 else if (maLowerRect
.Contains(rPt
))
858 bool SpinField::PreNotify(NotifyEvent
& rNEvt
)
860 if (rNEvt
.GetType() == NotifyEventType::MOUSEMOVE
)
862 const MouseEvent
* pMouseEvt
= rNEvt
.GetMouseEvent();
863 if (pMouseEvt
&& !pMouseEvt
->GetButtons() && !pMouseEvt
->IsSynthetic() && !pMouseEvt
->IsModifierChanged())
865 // trigger redraw if mouse over state has changed
866 if( IsNativeControlSupported(ControlType::Spinbox
, ControlPart::Entire
) ||
867 IsNativeControlSupported(ControlType::Spinbox
, ControlPart::AllButtons
) )
869 tools::Rectangle
* pRect
= ImplFindPartRect( GetPointerPosPixel() );
870 tools::Rectangle
* pLastRect
= ImplFindPartRect( GetLastPointerPosPixel() );
871 if( pRect
!= pLastRect
|| (pMouseEvt
->IsLeaveWindow() || pMouseEvt
->IsEnterWindow()) )
873 if (!IsNativeWidgetEnabled() ||
874 !IsNativeControlSupported(ControlType::Editbox
, ControlPart::Entire
))
877 vcl::Region
aRgn( GetOutDev()->GetActiveClipRegion() );
880 GetOutDev()->SetClipRegion(vcl::Region(*pLastRect
));
881 Invalidate(*pLastRect
);
882 GetOutDev()->SetClipRegion( aRgn
);
886 GetOutDev()->SetClipRegion(vcl::Region(*pRect
));
888 GetOutDev()->SetClipRegion( aRgn
);
896 return Edit::PreNotify(rNEvt
);
899 void SpinField::EndDropDown()
901 mbInDropDown
= false;
902 Invalidate(tools::Rectangle(Point(), GetOutputSizePixel()));
905 bool SpinField::ShowDropDown( bool )
910 Size
SpinField::CalcMinimumSizeForText(const OUString
&rString
) const
912 Size aSz
= Edit::CalcMinimumSizeForText(rString
);
914 if ( GetStyle() & WB_DROPDOWN
)
915 aSz
.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
916 if ( GetStyle() & WB_SPIN
)
918 ImplControlValue aControlValue
;
919 tools::Rectangle
aArea( Point(), Size(100, aSz
.Height()));
920 tools::Rectangle aEntireBound
, aEntireContent
, aEditBound
, aEditContent
;
922 GetNativeControlRegion(ControlType::Spinbox
, ControlPart::Entire
,
923 aArea
, ControlState::NONE
, aControlValue
, aEntireBound
, aEntireContent
) &&
924 GetNativeControlRegion(ControlType::Spinbox
, ControlPart::SubEdit
,
925 aArea
, ControlState::NONE
, aControlValue
, aEditBound
, aEditContent
)
928 aSz
.AdjustWidth(aEntireContent
.GetWidth() - aEditContent
.GetWidth());
932 aSz
.AdjustWidth(maUpperRect
.GetWidth() );
939 Size
SpinField::CalcMinimumSize() const
941 return CalcMinimumSizeForText(GetText());
944 Size
SpinField::GetOptimalSize() const
946 return CalcMinimumSize();
949 Size
SpinField::CalcSize(sal_Int32 nChars
) const
951 Size aSz
= Edit::CalcSize( nChars
);
953 if ( GetStyle() & WB_DROPDOWN
)
954 aSz
.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize() );
955 if ( GetStyle() & WB_SPIN
)
956 aSz
.AdjustWidth(GetSettings().GetStyleSettings().GetSpinSize() );
961 IMPL_LINK( SpinField
, ImplTimeout
, Timer
*, pTimer
, void )
963 if ( pTimer
->GetTimeout() == static_cast<sal_uInt64
>(MouseSettings::GetButtonStartRepeat()) )
965 pTimer
->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
977 void SpinField::Draw(OutputDevice
* pDev
, const Point
& rPos
, SystemTextColorFlags nFlags
)
979 Edit::Draw(pDev
, rPos
, nFlags
);
981 WinBits nFieldStyle
= GetStyle();
982 if ( (nFlags
& SystemTextColorFlags::NoControls
) || !( nFieldStyle
& (WB_SPIN
|WB_DROPDOWN
) ) )
985 Point aPos
= pDev
->LogicToPixel( rPos
);
986 Size aSize
= GetSizePixel();
987 AllSettings aOldSettings
= pDev
->GetSettings();
992 tools::Rectangle aDD
, aUp
, aDown
;
993 ImplCalcButtonAreas(pDev
, aSize
, aDD
, aUp
, aDown
);
994 aDD
.Move(aPos
.X(), aPos
.Y());
995 aUp
.Move(aPos
.X(), aPos
.Y());
997 aDown
.Move(aPos
.X(), aPos
.Y());
999 Color aButtonTextColor
;
1000 if (nFlags
& SystemTextColorFlags::Mono
)
1001 aButtonTextColor
= COL_BLACK
;
1003 aButtonTextColor
= GetSettings().GetStyleSettings().GetButtonTextColor();
1005 if (GetStyle() & WB_DROPDOWN
)
1007 DecorationView
aView( pDev
);
1008 tools::Rectangle aInnerRect
= aView
.DrawButton( aDD
, DrawButtonFlags::NoLightBorder
);
1009 DrawSymbolFlags nSymbolStyle
= IsEnabled() ? DrawSymbolFlags::NONE
: DrawSymbolFlags::Disable
;
1010 aView
.DrawSymbol(aInnerRect
, SymbolType::SPIN_DOWN
, aButtonTextColor
, nSymbolStyle
);
1013 if (GetStyle() & WB_SPIN
)
1015 ImplDrawSpinButton(*pDev
, this, aUp
, aDown
, false, false);
1019 pDev
->SetSettings(aOldSettings
);
1023 FactoryFunction
SpinField::GetUITestFactory() const
1025 return SpinFieldUIObject::create
;
1028 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */