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 .
22 #include <vcl/event.hxx>
23 #include <vcl/decoview.hxx>
24 #include <vcl/spinfld.hxx>
25 #include <vcl/settings.hxx>
26 #include <vcl/uitest/uiobject.hxx>
28 #include "controldata.hxx"
34 void ImplGetSpinbuttonValue(vcl::Window
* pWin
,
35 const Rectangle
& rUpperRect
, const 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
* 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 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 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 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 Rectangle aBound
, aContent
;
116 if (!ImplGetSVData()->maNWFData
.mbCanDrawWidgetAnySize
&&
117 pContext
->GetNativeControlRegion(ControlType::Spinbox
, ControlPart::Entire
,
118 aNatRgn
, ControlState::NONE
, rSpinbuttonValue
,
119 OUString(), aBound
, aContent
))
121 aSize
= aContent
.GetSize();
124 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(vcl::Region(oldRgn
));
141 bool ImplDrawNativeSpinbuttons(vcl::RenderContext
& rRenderContext
, const SpinbuttonValue
& rSpinbuttonValue
)
143 bool bNativeOK
= false;
145 if (rRenderContext
.IsNativeControlSupported(ControlType::SpinButtons
, ControlPart::Entire
))
147 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 Rectangle
& rUpperRect
, const 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())
171 case WINDOW_MULTILINEEDIT
:
172 case WINDOW_PATTERNFIELD
:
173 case WINDOW_METRICFIELD
:
174 case WINDOW_CURRENCYFIELD
:
175 case WINDOW_DATEFIELD
:
176 case WINDOW_TIMEFIELD
:
177 case WINDOW_LONGCURRENCYFIELD
:
178 case WINDOW_NUMERICFIELD
:
179 case WINDOW_SPINFIELD
:
180 aControl
= ControlType::Spinbox
;
183 aControl
= ControlType::SpinButtons
;
187 SpinbuttonValue aValue
;
188 ImplGetSpinbuttonValue(pWindow
, rUpperRect
, rLowerRect
,
189 bUpperIn
, bLowerIn
, bUpperEnabled
, bLowerEnabled
,
192 if( aControl
== ControlType::Spinbox
)
193 bNativeOK
= ImplDrawNativeSpinfield(rRenderContext
, pWindow
, aValue
);
194 else if( aControl
== ControlType::SpinButtons
)
195 bNativeOK
= ImplDrawNativeSpinbuttons(rRenderContext
, aValue
);
201 ImplDrawUpDownButtons(rRenderContext
,
202 rUpperRect
, rLowerRect
,
203 bUpperIn
, bLowerIn
, bUpperEnabled
, bLowerEnabled
,
207 void ImplDrawUpDownButtons(vcl::RenderContext
& rRenderContext
,
208 const Rectangle
& rUpperRect
, const Rectangle
& rLowerRect
,
209 bool bUpperIn
, bool bLowerIn
, bool bUpperEnabled
, bool bLowerEnabled
,
210 bool bHorz
, bool bMirrorHorz
)
212 DecorationView
aDecoView(&rRenderContext
);
214 SymbolType eType1
, eType2
;
218 eType1
= bMirrorHorz
? SymbolType::SPIN_RIGHT
: SymbolType::SPIN_LEFT
;
219 eType2
= bMirrorHorz
? SymbolType::SPIN_LEFT
: SymbolType::SPIN_RIGHT
;
223 eType1
= SymbolType::SPIN_UP
;
224 eType2
= SymbolType::SPIN_DOWN
;
227 DrawButtonFlags nStyle
= DrawButtonFlags::NoLeftLightBorder
;
228 // draw upper/left Button
230 nStyle
|= DrawButtonFlags::Pressed
;
232 Rectangle aUpRect
= aDecoView
.DrawButton(rUpperRect
, nStyle
);
234 nStyle
= DrawButtonFlags::NoLeftLightBorder
;
235 // draw lower/right Button
237 nStyle
|= DrawButtonFlags::Pressed
;
239 Rectangle aLowRect
= aDecoView
.DrawButton(rLowerRect
, nStyle
);
241 // make use of additional default edge
251 // draw into the edge, so that something is visible if the rectangle is too small
252 if (aUpRect
.GetHeight() < 4)
260 // calculate Symbol size
261 long nTempSize1
= aUpRect
.GetWidth();
262 long nTempSize2
= aLowRect
.GetWidth();
263 if (std::abs( nTempSize1
-nTempSize2
) == 1)
265 if (nTempSize1
> nTempSize2
)
270 nTempSize1
= aUpRect
.GetHeight();
271 nTempSize2
= aLowRect
.GetHeight();
272 if (std::abs(nTempSize1
- nTempSize2
) == 1)
274 if (nTempSize1
> nTempSize2
)
280 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
282 DrawSymbolFlags nSymStyle
= DrawSymbolFlags::NONE
;
284 nSymStyle
|= DrawSymbolFlags::Disable
;
285 aDecoView
.DrawSymbol(aUpRect
, eType1
, rStyleSettings
.GetButtonTextColor(), nSymStyle
);
287 nSymStyle
= DrawSymbolFlags::NONE
;
289 nSymStyle
|= DrawSymbolFlags::Disable
;
290 aDecoView
.DrawSymbol(aLowRect
, eType2
, rStyleSettings
.GetButtonTextColor(), nSymStyle
);
293 void SpinField::ImplInitSpinFieldData()
295 mpEdit
.disposeAndClear();
301 mbInitialDown
= false;
303 mbInDropDown
= false;
306 void SpinField::ImplInit(vcl::Window
* pParent
, WinBits nWinStyle
)
308 Edit::ImplInit( pParent
, nWinStyle
);
310 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(*this, 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
.SetTimeoutHdl(LINK( this, SpinField
, ImplTimeout
));
333 maRepeatTimer
.SetTimeout(GetSettings().GetMouseSettings().GetButtonStartRepeat());
334 if (nWinStyle
& WB_REPEAT
)
337 SetCompoundControl(true);
341 SpinField::SpinField(vcl::Window
* pParent
, WinBits nWinStyle
) :
342 Edit(WINDOW_SPINFIELD
)
344 ImplInitSpinFieldData();
345 ImplInit(pParent
, nWinStyle
);
348 SpinField::~SpinField()
353 void SpinField::dispose()
355 mpEdit
.disposeAndClear();
362 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_UP
, [this] () { maUpHdlLink
.Call(*this); } );
365 void SpinField::Down()
367 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_DOWN
, [this] () { maDownHdlLink
.Call(*this); } );
370 void SpinField::First()
372 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_FIRST
, [this] () { maFirstHdlLink
.Call(*this); } );
375 void SpinField::Last()
377 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_LAST
, [this] () { maLastHdlLink
.Call(*this); } );
380 void SpinField::MouseButtonDown( const MouseEvent
& rMEvt
)
382 if (!HasFocus() && (!mpEdit
|| !mpEdit
->HasFocus()))
390 if (maUpperRect
.IsInside(rMEvt
.GetPosPixel()))
394 Invalidate(maUpperRect
);
396 else if (maLowerRect
.IsInside(rMEvt
.GetPosPixel()))
399 mbInitialDown
= true;
400 Invalidate(maLowerRect
);
402 else if (maDropDownRect
.IsInside(rMEvt
.GetPosPixel()))
404 // put DropDownButton to the right
405 mbInDropDown
= ShowDropDown( !mbInDropDown
);
406 Invalidate(Rectangle(Point(), GetOutputSizePixel()));
409 if (mbUpperIn
|| mbLowerIn
)
414 maRepeatTimer
.Start();
419 Edit::MouseButtonDown(rMEvt
);
422 void SpinField::MouseButtonUp(const MouseEvent
& rMEvt
)
425 mbInitialUp
= mbInitialDown
= false;
426 maRepeatTimer
.Stop();
427 maRepeatTimer
.SetTimeout(GetSettings().GetMouseSettings().GetButtonStartRepeat());
432 Invalidate(maUpperRect
);
439 Invalidate(maLowerRect
);
444 Edit::MouseButtonUp(rMEvt
);
447 void SpinField::MouseMove(const MouseEvent
& rMEvt
)
453 bool bNewUpperIn
= maUpperRect
.IsInside(rMEvt
.GetPosPixel());
454 if (bNewUpperIn
!= mbUpperIn
)
459 maRepeatTimer
.Start();
462 maRepeatTimer
.Stop();
464 mbUpperIn
= bNewUpperIn
;
465 Invalidate(maUpperRect
);
469 else if (mbInitialDown
)
471 bool bNewLowerIn
= maLowerRect
.IsInside(rMEvt
.GetPosPixel());
472 if (bNewLowerIn
!= mbLowerIn
)
477 maRepeatTimer
.Start();
480 maRepeatTimer
.Stop();
482 mbLowerIn
= bNewLowerIn
;
483 Invalidate(maLowerRect
);
489 Edit::MouseMove(rMEvt
);
492 bool SpinField::EventNotify(NotifyEvent
& rNEvt
)
495 if (rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
)
497 const KeyEvent
& rKEvt
= *rNEvt
.GetKeyEvent();
500 sal_uInt16 nMod
= rKEvt
.GetKeyCode().GetModifier();
501 switch (rKEvt
.GetKeyCode().GetCode())
519 else if ((nMod
== KEY_MOD2
) && !mbInDropDown
&& (GetStyle() & WB_DROPDOWN
))
521 mbInDropDown
= ShowDropDown(true);
522 Invalidate(Rectangle(Point(), GetOutputSizePixel()));
549 if (rNEvt
.GetType() == MouseNotifyEvent::COMMAND
)
551 if ((rNEvt
.GetCommandEvent()->GetCommand() == CommandEventId::Wheel
) && !IsReadOnly())
553 MouseWheelBehaviour
nWheelBehavior(GetSettings().GetMouseSettings().GetWheelBehavior());
554 if (nWheelBehavior
== MouseWheelBehaviour::ALWAYS
555 || (nWheelBehavior
== MouseWheelBehaviour::FocusOnly
&& HasChildPathFocus()))
557 const CommandWheelData
* pData
= rNEvt
.GetCommandEvent()->GetWheelData();
558 if (pData
->GetMode() == CommandWheelMode::SCROLL
)
560 if (pData
->GetDelta() < 0)
568 bDone
= false; // don't eat this event, let the default handling happen (i.e. scroll the context)
572 return bDone
|| Edit::EventNotify(rNEvt
);
575 void SpinField::FillLayoutData() const
579 mpControlData
->mpLayoutData
.reset( new vcl::ControlLayoutData
);
580 AppendLayoutData(*GetSubEdit());
581 GetSubEdit()->SetLayoutDataParent(this);
584 Edit::FillLayoutData();
587 void SpinField::Paint(vcl::RenderContext
& rRenderContext
, const Rectangle
& rRect
)
591 bool bEnable
= IsEnabled();
592 ImplDrawSpinButton(rRenderContext
, this, maUpperRect
, maLowerRect
,
593 mbUpperIn
, mbLowerIn
, bEnable
, bEnable
);
596 if (GetStyle() & WB_DROPDOWN
)
598 DecorationView
aView(&rRenderContext
);
600 DrawButtonFlags nStyle
= DrawButtonFlags::NoLightBorder
;
602 nStyle
|= DrawButtonFlags::Pressed
;
603 Rectangle aInnerRect
= aView
.DrawButton(maDropDownRect
, nStyle
);
605 SymbolType eSymbol
= SymbolType::SPIN_DOWN
;
606 DrawSymbolFlags nSymbolStyle
= IsEnabled() ? DrawSymbolFlags::NONE
: DrawSymbolFlags::Disable
;
607 aView
.DrawSymbol(aInnerRect
, eSymbol
, rRenderContext
.GetSettings().GetStyleSettings().GetButtonTextColor(), nSymbolStyle
);
610 Edit::Paint(rRenderContext
, rRect
);
613 void SpinField::ImplCalcButtonAreas(OutputDevice
* pDev
, const Size
& rOutSz
, Rectangle
& rDDArea
,
614 Rectangle
& rSpinUpArea
, Rectangle
& rSpinDownArea
)
616 const StyleSettings
& rStyleSettings
= pDev
->GetSettings().GetStyleSettings();
621 if (GetStyle() & WB_DROPDOWN
)
623 long nW
= rStyleSettings
.GetScrollBarSize();
624 nW
= GetDrawPixel( pDev
, nW
);
625 aDropDownSize
= Size( CalcZoom( nW
), aSize
.Height() );
626 aSize
.Width() -= aDropDownSize
.Width();
627 rDDArea
= Rectangle( Point( aSize
.Width(), 0 ), aDropDownSize
);
633 // calcuate sizes according to the height
634 if (GetStyle() & WB_SPIN
)
636 long nBottom1
= aSize
.Height()/2;
637 long nBottom2
= aSize
.Height()-1;
638 long nTop2
= nBottom1
;
639 if ( !(aSize
.Height() & 0x01) )
642 bool bNativeRegionOK
= false;
643 Rectangle aContentUp
, aContentDown
;
645 if ((pDev
->GetOutDevType() == OUTDEV_WINDOW
) &&
646 // there is just no useful native support for spinfields with dropdown
647 ! (GetStyle() & WB_DROPDOWN
) &&
648 IsNativeControlSupported(ControlType::Spinbox
, ControlPart::Entire
))
650 vcl::Window
*pWin
= static_cast<vcl::Window
*>(pDev
);
651 vcl::Window
*pBorder
= pWin
->GetWindow( GetWindowType::Border
);
653 // get the system's spin button size
654 ImplControlValue aControlValue
;
658 // use the full extent of the control
659 Rectangle
aArea( aPoint
, pBorder
->GetOutputSizePixel() );
662 pWin
->GetNativeControlRegion(ControlType::Spinbox
, ControlPart::ButtonUp
,
663 aArea
, ControlState::NONE
, aControlValue
, OUString(), aBound
, aContentUp
) &&
664 pWin
->GetNativeControlRegion(ControlType::Spinbox
, ControlPart::ButtonDown
,
665 aArea
, ControlState::NONE
, aControlValue
, OUString(), aBound
, aContentDown
);
669 // convert back from border space to local coordinates
670 aPoint
= pBorder
->ScreenToOutputPixel( pWin
->OutputToScreenPixel( aPoint
) );
671 aContentUp
.Move(-aPoint
.X(), -aPoint
.Y());
672 aContentDown
.Move(-aPoint
.X(), -aPoint
.Y());
678 rSpinUpArea
= aContentUp
;
679 rSpinDownArea
= aContentDown
;
683 aSize
.Width() -= CalcZoom( GetDrawPixel( pDev
, rStyleSettings
.GetSpinSize() ) );
685 rSpinUpArea
= Rectangle( aSize
.Width(), 0, rOutSz
.Width()-aDropDownSize
.Width()-1, nBottom1
);
686 rSpinDownArea
= Rectangle( rSpinUpArea
.Left(), nTop2
, rSpinUpArea
.Right(), nBottom2
);
691 rSpinUpArea
.SetEmpty();
692 rSpinDownArea
.SetEmpty();
696 void SpinField::Resize()
701 Size aSize
= GetOutputSizePixel();
702 bool bSubEditPositioned
= false;
704 if (GetStyle() & (WB_SPIN
| WB_DROPDOWN
))
706 ImplCalcButtonAreas( this, aSize
, maDropDownRect
, maUpperRect
, maLowerRect
);
708 ImplControlValue aControlValue
;
710 Rectangle aContent
, aBound
;
712 // use the full extent of the control
713 vcl::Window
*pBorder
= GetWindow( GetWindowType::Border
);
714 Rectangle
aArea( aPoint
, pBorder
->GetOutputSizePixel() );
716 // adjust position and size of the edit field
717 if (GetNativeControlRegion(ControlType::Spinbox
, ControlPart::SubEdit
, aArea
, ControlState::NONE
,
718 aControlValue
, OUString(), aBound
, aContent
) &&
719 // there is just no useful native support for spinfields with dropdown
720 !(GetStyle() & WB_DROPDOWN
))
722 // convert back from border space to local coordinates
723 aPoint
= pBorder
->ScreenToOutputPixel(OutputToScreenPixel(aPoint
));
724 aContent
.Move(-aPoint
.X(), -aPoint
.Y());
726 // use the themes drop down size
727 mpEdit
->SetPosPixel( aContent
.TopLeft() );
728 bSubEditPositioned
= true;
729 aSize
= aContent
.GetSize();
733 if (maUpperRect
.IsEmpty())
735 SAL_WARN_IF( maDropDownRect
.IsEmpty(), "vcl", "SpinField::Resize: SPIN && DROPDOWN, but all empty rects?" );
736 aSize
.Width() = maDropDownRect
.Left();
739 aSize
.Width() = maUpperRect
.Left();
743 if (!bSubEditPositioned
)
745 // this moves our sub edit if RTL gets switched
746 mpEdit
->SetPosPixel(Point());
748 mpEdit
->SetSizePixel(aSize
);
750 if (GetStyle() & WB_SPIN
)
751 Invalidate(Rectangle(maUpperRect
.TopLeft(), maLowerRect
.BottomRight()));
752 if (GetStyle() & WB_DROPDOWN
)
753 Invalidate(maDropDownRect
);
757 void SpinField::StateChanged(StateChangedType nType
)
759 Edit::StateChanged(nType
);
761 if (nType
== StateChangedType::Enable
)
763 if (mbSpin
|| (GetStyle() & WB_DROPDOWN
))
765 mpEdit
->Enable(IsEnabled());
769 Invalidate(maLowerRect
);
770 Invalidate(maUpperRect
);
772 if (GetStyle() & WB_DROPDOWN
)
773 Invalidate(maDropDownRect
);
776 else if (nType
== StateChangedType::Style
)
778 if (GetStyle() & WB_REPEAT
)
783 else if (nType
== StateChangedType::Zoom
)
787 mpEdit
->SetZoom(GetZoom());
790 else if (nType
== StateChangedType::ControlFont
)
793 mpEdit
->SetControlFont(GetControlFont());
796 else if (nType
== StateChangedType::ControlForeground
)
799 mpEdit
->SetControlForeground(GetControlForeground());
802 else if (nType
== StateChangedType::ControlBackground
)
805 mpEdit
->SetControlBackground(GetControlBackground());
808 else if( nType
== StateChangedType::Mirroring
)
811 mpEdit
->CompatStateChanged(StateChangedType::Mirroring
);
816 void SpinField::DataChanged( const DataChangedEvent
& rDCEvt
)
818 Edit::DataChanged(rDCEvt
);
820 if ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
821 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))
828 Rectangle
* SpinField::ImplFindPartRect(const Point
& rPt
)
830 if (maUpperRect
.IsInside(rPt
))
832 else if (maLowerRect
.IsInside(rPt
))
838 bool SpinField::PreNotify(NotifyEvent
& rNEvt
)
840 const MouseEvent
* pMouseEvt
= nullptr;
842 if ((rNEvt
.GetType() == MouseNotifyEvent::MOUSEMOVE
) && (pMouseEvt
= rNEvt
.GetMouseEvent()) != nullptr)
844 if (!pMouseEvt
->GetButtons() && !pMouseEvt
->IsSynthetic() && !pMouseEvt
->IsModifierChanged())
846 // trigger redraw if mouse over state has changed
847 if( IsNativeControlSupported(ControlType::Spinbox
, ControlPart::Entire
) ||
848 IsNativeControlSupported(ControlType::Spinbox
, ControlPart::AllButtons
) )
850 Rectangle
* pRect
= ImplFindPartRect( GetPointerPosPixel() );
851 Rectangle
* pLastRect
= ImplFindPartRect( GetLastPointerPosPixel() );
852 if( pRect
!= pLastRect
|| (pMouseEvt
->IsLeaveWindow() || pMouseEvt
->IsEnterWindow()) )
854 // FIXME: this is currently only on OS X
855 // check for other platforms that need similar handling
856 if (ImplGetSVData()->maNWFData
.mbNoFocusRects
&& IsNativeWidgetEnabled() &&
857 IsNativeControlSupported(ControlType::Editbox
, ControlPart::Entire
))
859 ImplInvalidateOutermostBorder(this);
864 vcl::Region
aRgn( GetActiveClipRegion() );
867 SetClipRegion(vcl::Region(*pLastRect
));
868 Invalidate(*pLastRect
);
869 SetClipRegion( aRgn
);
873 SetClipRegion(vcl::Region(*pRect
));
875 SetClipRegion( aRgn
);
883 return Edit::PreNotify(rNEvt
);
886 void SpinField::EndDropDown()
888 mbInDropDown
= false;
889 Invalidate(Rectangle(Point(), GetOutputSizePixel()));
892 bool SpinField::ShowDropDown( bool )
897 Size
SpinField::CalcMinimumSizeForText(const OUString
&rString
) const
899 Size aSz
= Edit::CalcMinimumSizeForText(rString
);
901 if ( GetStyle() & WB_DROPDOWN
)
902 aSz
.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
903 if ( GetStyle() & WB_SPIN
)
905 ImplControlValue aControlValue
;
906 Rectangle
aArea( Point(), Size(100, aSz
.Height()));
907 Rectangle aEntireBound
, aEntireContent
, aEditBound
, aEditContent
;
909 GetNativeControlRegion(ControlType::Spinbox
, ControlPart::Entire
,
910 aArea
, ControlState::NONE
, aControlValue
, OUString(), aEntireBound
, aEntireContent
) &&
911 GetNativeControlRegion(ControlType::Spinbox
, ControlPart::SubEdit
,
912 aArea
, ControlState::NONE
, aControlValue
, OUString(), aEditBound
, aEditContent
)
915 aSz
.Width() += (aEntireContent
.GetWidth() - aEditContent
.GetWidth());
919 aSz
.Width() += maUpperRect
.GetWidth();
926 Size
SpinField::CalcMinimumSize() const
928 return CalcMinimumSizeForText(GetText());
931 Size
SpinField::GetOptimalSize() const
933 return CalcMinimumSize();
936 Size
SpinField::CalcSize(sal_Int32 nChars
) const
938 Size aSz
= Edit::CalcSize( nChars
);
940 if ( GetStyle() & WB_DROPDOWN
)
941 aSz
.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
942 if ( GetStyle() & WB_SPIN
)
943 aSz
.Width() += GetSettings().GetStyleSettings().GetSpinSize();
948 IMPL_LINK( SpinField
, ImplTimeout
, Timer
*, pTimer
, void )
950 if ( pTimer
->GetTimeout() == GetSettings().GetMouseSettings().GetButtonStartRepeat() )
952 pTimer
->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
964 void SpinField::Draw(OutputDevice
* pDev
, const Point
& rPos
, const Size
& rSize
, DrawFlags nFlags
)
966 Edit::Draw(pDev
, rPos
, rSize
, nFlags
);
968 WinBits nFieldStyle
= GetStyle();
969 if ( !(nFlags
& DrawFlags::NoControls
) && ( nFieldStyle
& (WB_SPIN
|WB_DROPDOWN
) ) )
971 Point aPos
= pDev
->LogicToPixel( rPos
);
972 Size aSize
= pDev
->LogicToPixel( rSize
);
973 OutDevType eOutDevType
= pDev
->GetOutDevType();
974 AllSettings aOldSettings
= pDev
->GetSettings();
979 if (eOutDevType
== OUTDEV_PRINTER
)
981 StyleSettings aStyleSettings
= aOldSettings
.GetStyleSettings();
982 aStyleSettings
.SetFaceColor(COL_LIGHTGRAY
);
983 aStyleSettings
.SetButtonTextColor(COL_BLACK
);
984 AllSettings
aSettings(aOldSettings
);
985 aSettings
.SetStyleSettings(aStyleSettings
);
986 pDev
->SetSettings(aSettings
);
989 Rectangle aDD
, aUp
, aDown
;
990 ImplCalcButtonAreas(pDev
, aSize
, aDD
, aUp
, aDown
);
991 aDD
.Move(aPos
.X(), aPos
.Y());
992 aUp
.Move(aPos
.X(), aPos
.Y());
994 aDown
.Move(aPos
.X(), aPos
.Y());
996 Color aButtonTextColor
;
997 if ((nFlags
& DrawFlags::Mono
) || (eOutDevType
== OUTDEV_PRINTER
))
998 aButtonTextColor
= Color( COL_BLACK
);
1000 aButtonTextColor
= GetSettings().GetStyleSettings().GetButtonTextColor();
1002 if (GetStyle() & WB_DROPDOWN
)
1004 DecorationView
aView( pDev
);
1005 DrawButtonFlags nStyle
= DrawButtonFlags::NoLightBorder
;
1006 Rectangle aInnerRect
= aView
.DrawButton( aDD
, nStyle
);
1007 SymbolType eSymbol
= SymbolType::SPIN_DOWN
;
1008 DrawSymbolFlags nSymbolStyle
= (IsEnabled() || (nFlags
& DrawFlags::NoDisable
)) ? DrawSymbolFlags::NONE
: DrawSymbolFlags::Disable
;
1009 aView
.DrawSymbol(aInnerRect
, eSymbol
, aButtonTextColor
, nSymbolStyle
);
1012 if (GetStyle() & WB_SPIN
)
1014 ImplDrawSpinButton(*pDev
, this, aUp
, aDown
, false, false);
1018 pDev
->SetSettings(aOldSettings
);
1022 FactoryFunction
SpinField::GetUITestFactory() const
1024 return SpinFieldUIObject::create
;
1027 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */