ooo33gsl12: #i115107# do not call getNativeControlRegion during paint on gtk
[LibreOffice.git] / vcl / source / control / spinfld.cxx
blobc51ac834f1b4bfc964a7f47a414e8f843d81de71
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
31 #include "tools/rc.h"
32 #include "vcl/event.hxx"
33 #include "vcl/decoview.hxx"
34 #include "vcl/spin.h"
35 #include "vcl/spinfld.hxx"
36 #include "vcl/controldata.hxx"
37 #include "vcl/svdata.hxx"
39 // =======================================================================
41 void ImplGetSpinbuttonValue( Window *pWin, const Rectangle& rUpperRect,
42 const Rectangle& rLowerRect,
43 BOOL bUpperIn, BOOL bLowerIn,
44 BOOL bUpperEnabled, BOOL bLowerEnabled, BOOL bHorz,
45 SpinbuttonValue& rValue )
47 // convert spinbutton data to a SpinbuttonValue structure for native painting
49 rValue.maUpperRect = rUpperRect;
50 rValue.maLowerRect = rLowerRect;
52 Point aPointerPos = pWin->GetPointerPosPixel();
54 ControlState nState = CTRL_STATE_ENABLED;
55 if ( bUpperIn )
56 nState |= CTRL_STATE_PRESSED;
57 if ( !pWin->IsEnabled() || !bUpperEnabled )
58 nState &= ~CTRL_STATE_ENABLED;
59 if ( pWin->HasFocus() )
60 nState |= CTRL_STATE_FOCUSED;
61 if( pWin->IsMouseOver() && rUpperRect.IsInside( aPointerPos ) )
62 nState |= CTRL_STATE_ROLLOVER;
63 rValue.mnUpperState = nState;
65 nState = CTRL_STATE_ENABLED;
66 if ( bLowerIn )
67 nState |= CTRL_STATE_PRESSED;
68 if ( !pWin->IsEnabled() || !bLowerEnabled )
69 nState &= ~CTRL_STATE_ENABLED;
70 if ( pWin->HasFocus() )
71 nState |= CTRL_STATE_FOCUSED;
72 // for overlapping spins: highlight only one
73 if( pWin->IsMouseOver() && rLowerRect.IsInside( aPointerPos ) &&
74 !rUpperRect.IsInside( aPointerPos ) )
75 nState |= CTRL_STATE_ROLLOVER;
76 rValue.mnLowerState = nState;
78 rValue.mnUpperPart = bHorz ? PART_BUTTON_LEFT : PART_BUTTON_UP;
79 rValue.mnLowerPart = bHorz ? PART_BUTTON_RIGHT : PART_BUTTON_DOWN;
83 BOOL ImplDrawNativeSpinfield( Window *pWin, const SpinbuttonValue& rSpinbuttonValue )
85 BOOL bNativeOK = FALSE;
87 if( pWin->IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) &&
88 // there is just no useful native support for spinfields with dropdown
89 !(pWin->GetStyle() & WB_DROPDOWN) )
91 if( pWin->IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnUpperPart) &&
92 pWin->IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnLowerPart) )
94 // only paint the embedded spin buttons, all buttons are painted at once
95 bNativeOK = pWin->DrawNativeControl( CTRL_SPINBOX, PART_ALL_BUTTONS, Rectangle(), CTRL_STATE_ENABLED,
96 rSpinbuttonValue, rtl::OUString() );
98 else
100 // paint the spinbox as a whole, use borderwindow to have proper clipping
101 Window *pBorder = pWin->GetWindow( WINDOW_BORDER );
103 // to not overwrite everything, set the button region as clipregion to the border window
104 Rectangle aClipRect( rSpinbuttonValue.maLowerRect );
105 aClipRect.Union( rSpinbuttonValue.maUpperRect );
107 // convert from screen space to borderwin space
108 aClipRect.SetPos( pBorder->ScreenToOutputPixel(pWin->OutputToScreenPixel(aClipRect.TopLeft())) );
110 Region oldRgn( pBorder->GetClipRegion() );
111 pBorder->SetClipRegion( Region( aClipRect ) );
113 Point aPt;
114 Size aSize( pBorder->GetOutputSizePixel() ); // the size of the border window, i.e., the whole control
115 Rectangle aBound, aContent;
116 Rectangle aNatRgn( aPt, aSize );
117 if( ! ImplGetSVData()->maNWFData.mbCanDrawWidgetAnySize &&
118 pBorder->GetNativeControlRegion( CTRL_SPINBOX, PART_ENTIRE_CONTROL,
119 aNatRgn, 0, rSpinbuttonValue, rtl::OUString(), aBound, aContent) )
121 aSize = aContent.GetSize();
124 Rectangle aRgn( aPt, aSize );
125 bNativeOK = pBorder->DrawNativeControl( CTRL_SPINBOX, PART_ENTIRE_CONTROL, aRgn, CTRL_STATE_ENABLED,
126 rSpinbuttonValue, rtl::OUString() );
128 pBorder->SetClipRegion( oldRgn );
131 return bNativeOK;
134 BOOL ImplDrawNativeSpinbuttons( Window *pWin, const SpinbuttonValue& rSpinbuttonValue )
136 BOOL bNativeOK = FALSE;
138 if( pWin->IsNativeControlSupported(CTRL_SPINBUTTONS, PART_ENTIRE_CONTROL) )
140 // only paint the standalone spin buttons, all buttons are painted at once
141 bNativeOK = pWin->DrawNativeControl( CTRL_SPINBUTTONS, PART_ALL_BUTTONS, Rectangle(), CTRL_STATE_ENABLED,
142 rSpinbuttonValue, rtl::OUString() );
144 return bNativeOK;
147 void ImplDrawSpinButton( OutputDevice* pOutDev,
148 const Rectangle& rUpperRect,
149 const Rectangle& rLowerRect,
150 BOOL bUpperIn, BOOL bLowerIn,
151 BOOL bUpperEnabled, BOOL bLowerEnabled, BOOL bHorz, BOOL bMirrorHorz )
153 DecorationView aDecoView( pOutDev );
155 USHORT nStyle = BUTTON_DRAW_NOLEFTLIGHTBORDER;
156 USHORT nSymStyle = 0;
158 SymbolType eType1, eType2;
160 const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings();
161 if ( rStyleSettings.GetOptions() & STYLE_OPTION_SPINARROW )
163 // arrows are only use in OS/2 look
164 if ( bHorz )
166 eType1 = bMirrorHorz ? SYMBOL_ARROW_RIGHT : SYMBOL_ARROW_LEFT;
167 eType2 = bMirrorHorz ? SYMBOL_ARROW_LEFT : SYMBOL_ARROW_RIGHT;
169 else
171 eType1 = SYMBOL_ARROW_UP;
172 eType2 = SYMBOL_ARROW_DOWN;
175 else
177 if ( bHorz )
179 eType1 = bMirrorHorz ? SYMBOL_SPIN_RIGHT : SYMBOL_SPIN_LEFT;
180 eType2 = bMirrorHorz ? SYMBOL_SPIN_LEFT : SYMBOL_SPIN_RIGHT;
182 else
184 eType1 = SYMBOL_SPIN_UP;
185 eType2 = SYMBOL_SPIN_DOWN;
189 // Oberen/linken Button malen
190 USHORT nTempStyle = nStyle;
191 if ( bUpperIn )
192 nTempStyle |= BUTTON_DRAW_PRESSED;
194 BOOL bNativeOK = FALSE;
195 Rectangle aUpRect;
197 if( pOutDev->GetOutDevType() == OUTDEV_WINDOW )
199 Window *pWin = (Window*) pOutDev;
201 // are we drawing standalone spin buttons or members of a spinfield ?
202 ControlType aControl = CTRL_SPINBUTTONS;
203 switch( pWin->GetType() )
205 case WINDOW_EDIT:
206 case WINDOW_MULTILINEEDIT:
207 case WINDOW_PATTERNFIELD:
208 case WINDOW_METRICFIELD:
209 case WINDOW_CURRENCYFIELD:
210 case WINDOW_DATEFIELD:
211 case WINDOW_TIMEFIELD:
212 case WINDOW_LONGCURRENCYFIELD:
213 case WINDOW_NUMERICFIELD:
214 case WINDOW_SPINFIELD:
215 aControl = CTRL_SPINBOX;
216 break;
217 default:
218 aControl = CTRL_SPINBUTTONS;
219 break;
222 SpinbuttonValue aValue;
223 ImplGetSpinbuttonValue( pWin, rUpperRect, rLowerRect,
224 bUpperIn, bLowerIn, bUpperEnabled, bLowerEnabled,
225 bHorz, aValue );
227 if( aControl == CTRL_SPINBOX )
228 bNativeOK = ImplDrawNativeSpinfield( pWin, aValue );
229 else if( aControl == CTRL_SPINBUTTONS )
230 bNativeOK = ImplDrawNativeSpinbuttons( pWin, aValue );
233 if( !bNativeOK )
234 aUpRect = aDecoView.DrawButton( rUpperRect, nTempStyle );
236 // Unteren/rechten Button malen
237 if ( bLowerIn )
238 nStyle |= BUTTON_DRAW_PRESSED;
239 Rectangle aLowRect;
240 if( !bNativeOK )
241 aLowRect = aDecoView.DrawButton( rLowerRect, nStyle );
243 // Zusaetzliche Default-Kante wollen wir auch ausnutzen
244 aUpRect.Left()--;
245 aUpRect.Top()--;
246 aUpRect.Right()++;
247 aUpRect.Bottom()++;
248 aLowRect.Left()--;
249 aLowRect.Top()--;
250 aLowRect.Right()++;
251 aLowRect.Bottom()++;
253 // Wir malen auch in die Kante rein, damit man etwas erkennen kann,
254 // wenn das Rechteck zu klein ist
255 if ( aUpRect.GetHeight() < 4 )
257 aUpRect.Right()++;
258 aUpRect.Bottom()++;
259 aLowRect.Right()++;
260 aLowRect.Bottom()++;
263 // Symbolgroesse berechnen
264 long nTempSize1 = aUpRect.GetWidth();
265 long nTempSize2 = aLowRect.GetWidth();
266 if ( Abs( nTempSize1-nTempSize2 ) == 1 )
268 if ( nTempSize1 > nTempSize2 )
269 aUpRect.Left()++;
270 else
271 aLowRect.Left()++;
273 nTempSize1 = aUpRect.GetHeight();
274 nTempSize2 = aLowRect.GetHeight();
275 if ( Abs( nTempSize1-nTempSize2 ) == 1 )
277 if ( nTempSize1 > nTempSize2 )
278 aUpRect.Top()++;
279 else
280 aLowRect.Top()++;
283 nTempStyle = nSymStyle;
284 if ( !bUpperEnabled )
285 nTempStyle |= SYMBOL_DRAW_DISABLE;
286 if( !bNativeOK )
287 aDecoView.DrawSymbol( aUpRect, eType1, rStyleSettings.GetButtonTextColor(), nTempStyle );
289 if ( !bLowerEnabled )
290 nSymStyle |= SYMBOL_DRAW_DISABLE;
291 if( !bNativeOK )
292 aDecoView.DrawSymbol( aLowRect, eType2, rStyleSettings.GetButtonTextColor(), nSymStyle );
295 // =======================================================================
297 void SpinField::ImplInitSpinFieldData()
299 mpEdit = NULL;
300 mbSpin = FALSE;
301 mbRepeat = FALSE;
302 mbUpperIn = FALSE;
303 mbLowerIn = FALSE;
304 mbInitialUp = FALSE;
305 mbInitialDown = FALSE;
306 mbNoSelect = FALSE;
307 mbInDropDown = FALSE;
310 // --------------------------------------------------------------------
312 void SpinField::ImplInit( Window* pParent, WinBits nWinStyle )
314 Edit::ImplInit( pParent, nWinStyle );
316 if ( nWinStyle & (WB_SPIN|WB_DROPDOWN) )
318 mbSpin = TRUE;
320 // Some themes want external spin buttons, therefore the main
321 // spinfield should not overdraw the border between its encapsulated
322 // edit field and the spin buttons
323 if ( (nWinStyle & WB_SPIN) && ImplUseNativeBorder( nWinStyle ) )
325 SetBackground();
326 mpEdit = new Edit( this, WB_NOBORDER );
327 mpEdit->SetBackground();
329 else
330 mpEdit = new Edit( this, WB_NOBORDER );
332 mpEdit->EnableRTL( FALSE );
333 mpEdit->SetPosPixel( Point() );
334 mpEdit->Show();
335 SetSubEdit( mpEdit );
337 maRepeatTimer.SetTimeoutHdl( LINK( this, SpinField, ImplTimeout ) );
338 maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
339 if ( nWinStyle & WB_REPEAT )
340 mbRepeat = TRUE;
342 SetCompoundControl( TRUE );
346 // --------------------------------------------------------------------
348 SpinField::SpinField( WindowType nTyp ) :
349 Edit( nTyp )
351 ImplInitSpinFieldData();
354 // --------------------------------------------------------------------
356 SpinField::SpinField( Window* pParent, WinBits nWinStyle ) :
357 Edit( WINDOW_SPINFIELD )
359 ImplInitSpinFieldData();
360 ImplInit( pParent, nWinStyle );
363 // --------------------------------------------------------------------
365 SpinField::SpinField( Window* pParent, const ResId& rResId ) :
366 Edit( WINDOW_SPINFIELD )
368 ImplInitSpinFieldData();
369 rResId.SetRT( RSC_SPINFIELD );
370 WinBits nStyle = ImplInitRes( rResId );
371 ImplInit( pParent, nStyle );
372 ImplLoadRes( rResId );
374 if ( !(nStyle & WB_HIDE) )
375 Show();
378 // --------------------------------------------------------------------
380 SpinField::~SpinField()
382 delete mpEdit;
385 // --------------------------------------------------------------------
387 void SpinField::Up()
389 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_UP, maUpHdlLink, this );
392 // --------------------------------------------------------------------
394 void SpinField::Down()
396 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_DOWN, maDownHdlLink, this );
399 // --------------------------------------------------------------------
401 void SpinField::First()
403 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_FIRST, maFirstHdlLink, this );
406 // --------------------------------------------------------------------
408 void SpinField::Last()
410 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_LAST, maLastHdlLink, this );
413 // --------------------------------------------------------------------
415 void SpinField::MouseButtonDown( const MouseEvent& rMEvt )
417 if ( !HasFocus() && ( !mpEdit || !mpEdit->HasFocus() ) )
419 mbNoSelect = TRUE;
420 GrabFocus();
423 if ( !IsReadOnly() )
425 if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) )
427 mbUpperIn = TRUE;
428 mbInitialUp = TRUE;
429 Invalidate( maUpperRect );
431 else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) )
433 mbLowerIn = TRUE;
434 mbInitialDown = TRUE;
435 Invalidate( maLowerRect );
437 else if ( maDropDownRect.IsInside( rMEvt.GetPosPixel() ) )
439 // Rechts daneben liegt der DropDownButton:
440 mbInDropDown = ShowDropDown( mbInDropDown ? FALSE : TRUE );
441 Paint( Rectangle( Point(), GetOutputSizePixel() ) );
444 if ( mbUpperIn || mbLowerIn )
446 Update();
447 CaptureMouse();
448 if ( mbRepeat )
449 maRepeatTimer.Start();
450 return;
454 Edit::MouseButtonDown( rMEvt );
457 // --------------------------------------------------------------------
459 void SpinField::MouseButtonUp( const MouseEvent& rMEvt )
461 ReleaseMouse();
462 mbInitialUp = mbInitialDown = FALSE;
463 maRepeatTimer.Stop();
464 maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
466 if ( mbUpperIn )
468 mbUpperIn = FALSE;
469 Invalidate( maUpperRect );
470 Update();
471 Up();
473 else if ( mbLowerIn )
475 mbLowerIn = FALSE;
476 Invalidate( maLowerRect );
477 Update();
478 Down();
481 Edit::MouseButtonUp( rMEvt );
484 // --------------------------------------------------------------------
486 void SpinField::MouseMove( const MouseEvent& rMEvt )
488 if ( rMEvt.IsLeft() )
490 if ( mbInitialUp )
492 BOOL bNewUpperIn = maUpperRect.IsInside( rMEvt.GetPosPixel() );
493 if ( bNewUpperIn != mbUpperIn )
495 if ( bNewUpperIn )
497 if ( mbRepeat )
498 maRepeatTimer.Start();
500 else
501 maRepeatTimer.Stop();
503 mbUpperIn = bNewUpperIn;
504 Invalidate( maUpperRect );
505 Update();
508 else if ( mbInitialDown )
510 BOOL bNewLowerIn = maLowerRect.IsInside( rMEvt.GetPosPixel() );
511 if ( bNewLowerIn != mbLowerIn )
513 if ( bNewLowerIn )
515 if ( mbRepeat )
516 maRepeatTimer.Start();
518 else
519 maRepeatTimer.Stop();
521 mbLowerIn = bNewLowerIn;
522 Invalidate( maLowerRect );
523 Update();
528 Edit::MouseMove( rMEvt );
531 // --------------------------------------------------------------------
533 long SpinField::Notify( NotifyEvent& rNEvt )
535 long nDone = 0;
536 if( rNEvt.GetType() == EVENT_KEYINPUT )
538 const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
539 if ( !IsReadOnly() )
541 USHORT nMod = rKEvt.GetKeyCode().GetModifier();
542 switch ( rKEvt.GetKeyCode().GetCode() )
544 case KEY_UP:
546 if ( !nMod )
548 Up();
549 nDone = 1;
552 break;
553 case KEY_DOWN:
555 if ( !nMod )
557 Down();
558 nDone = 1;
560 else if ( ( nMod == KEY_MOD2 ) && !mbInDropDown && ( GetStyle() & WB_DROPDOWN ) )
562 mbInDropDown = ShowDropDown( TRUE );
563 Paint( Rectangle( Point(), GetOutputSizePixel() ) );
564 nDone = 1;
567 break;
568 case KEY_PAGEUP:
570 if ( !nMod )
572 Last();
573 nDone = 1;
576 break;
577 case KEY_PAGEDOWN:
579 if ( !nMod )
581 First();
582 nDone = 1;
585 break;
590 if ( rNEvt.GetType() == EVENT_COMMAND )
592 if ( ( rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL ) && !IsReadOnly() )
594 USHORT nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
595 if ( ( nWheelBehavior == MOUSE_WHEEL_ALWAYS )
596 || ( ( nWheelBehavior == MOUSE_WHEEL_FOCUS_ONLY )
597 && HasChildPathFocus()
601 const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
602 if ( pData->GetMode() == COMMAND_WHEEL_SCROLL )
604 if ( pData->GetDelta() < 0L )
605 Down();
606 else
607 Up();
608 nDone = 1;
611 else
612 nDone = 0; // don't eat this event, let the default handling happen (i.e. scroll the context)
616 return nDone ? nDone : Edit::Notify( rNEvt );
619 // --------------------------------------------------------------------
621 void SpinField::Command( const CommandEvent& rCEvt )
623 Edit::Command( rCEvt );
626 // --------------------------------------------------------------------
628 void SpinField::FillLayoutData() const
630 if( mbSpin )
632 mpControlData->mpLayoutData = new vcl::ControlLayoutData();
633 AppendLayoutData( *GetSubEdit() );
634 GetSubEdit()->SetLayoutDataParent( this );
636 else
637 Edit::FillLayoutData();
640 // --------------------------------------------------------------------
642 void SpinField::Paint( const Rectangle& rRect )
644 if ( mbSpin )
646 BOOL bEnable = IsEnabled();
647 ImplDrawSpinButton( this, maUpperRect, maLowerRect,
648 mbUpperIn, mbLowerIn, bEnable, bEnable );
651 if ( GetStyle() & WB_DROPDOWN )
653 DecorationView aView( this );
655 USHORT nStyle = BUTTON_DRAW_NOLIGHTBORDER;
656 if ( mbInDropDown )
657 nStyle |= BUTTON_DRAW_PRESSED;
658 Rectangle aInnerRect = aView.DrawButton( maDropDownRect, nStyle );
660 SymbolType eSymbol = SYMBOL_SPIN_DOWN;
661 if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
662 eSymbol = SYMBOL_SPIN_UPDOWN;
664 nStyle = IsEnabled() ? 0 : SYMBOL_DRAW_DISABLE;
665 aView.DrawSymbol( aInnerRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle );
668 Edit::Paint( rRect );
671 // --------------------------------------------------------------------
673 void SpinField::ImplCalcButtonAreas( OutputDevice* pDev, const Size& rOutSz, Rectangle& rDDArea, Rectangle& rSpinUpArea, Rectangle& rSpinDownArea )
675 const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings();
677 Size aSize = rOutSz;
678 Size aDropDownSize;
680 if ( GetStyle() & WB_DROPDOWN )
682 long nW = rStyleSettings.GetScrollBarSize();
683 nW = GetDrawPixel( pDev, nW );
684 aDropDownSize = Size( CalcZoom( nW ), aSize.Height() );
685 aSize.Width() -= aDropDownSize.Width();
686 rDDArea = Rectangle( Point( aSize.Width(), 0 ), aDropDownSize );
687 rDDArea.Top()--;
689 else
690 rDDArea.SetEmpty();
692 // Je nach Hoehe, die groessen Berechnen
693 if ( GetStyle() & WB_SPIN )
695 long nBottom1 = aSize.Height()/2;
696 long nBottom2 = aSize.Height()-1;
697 long nTop2 = nBottom1;
698 long nTop1 = 0;
699 if ( !(aSize.Height() & 0x01) )
700 nBottom1--;
702 BOOL bNativeRegionOK = FALSE;
703 Rectangle aContentUp, aContentDown;
705 if ( (pDev->GetOutDevType() == OUTDEV_WINDOW) &&
706 // there is just no useful native support for spinfields with dropdown
707 ! (GetStyle() & WB_DROPDOWN) &&
708 IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) )
710 Window *pWin = (Window*) pDev;
711 Window *pBorder = pWin->GetWindow( WINDOW_BORDER );
713 // get the system's spin button size
714 ImplControlValue aControlValue;
715 Rectangle aBound;
716 Point aPoint;
718 // use the full extent of the control
719 Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
721 bNativeRegionOK =
722 pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_UP,
723 aArea, 0, aControlValue, rtl::OUString(), aBound, aContentUp) &&
724 pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_DOWN,
725 aArea, 0, aControlValue, rtl::OUString(), aBound, aContentDown);
727 if( bNativeRegionOK )
729 // convert back from border space to local coordinates
730 aPoint = pBorder->ScreenToOutputPixel( pWin->OutputToScreenPixel( aPoint ) );
731 aContentUp.Move(-aPoint.X(), -aPoint.Y());
732 aContentDown.Move(-aPoint.X(), -aPoint.Y());
736 if( bNativeRegionOK )
738 rSpinUpArea = aContentUp;
739 rSpinDownArea = aContentDown;
741 else
743 aSize.Width() -= CalcZoom( GetDrawPixel( pDev, rStyleSettings.GetSpinSize() ) );
745 rSpinUpArea = Rectangle( aSize.Width(), nTop1, rOutSz.Width()-aDropDownSize.Width()-1, nBottom1 );
746 rSpinDownArea = Rectangle( rSpinUpArea.Left(), nTop2, rSpinUpArea.Right(), nBottom2 );
749 else
751 rSpinUpArea.SetEmpty();
752 rSpinDownArea.SetEmpty();
756 // --------------------------------------------------------------------
758 void SpinField::Resize()
760 if ( mbSpin )
762 Control::Resize();
763 Size aSize = GetOutputSizePixel();
764 bool bSubEditPositioned = false;
766 if ( GetStyle() & (WB_SPIN|WB_DROPDOWN) )
768 ImplCalcButtonAreas( this, aSize, maDropDownRect, maUpperRect, maLowerRect );
770 ImplControlValue aControlValue;
771 Point aPoint;
772 Rectangle aContent, aBound;
774 // use the full extent of the control
775 Window *pBorder = GetWindow( WINDOW_BORDER );
776 Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
778 // adjust position and size of the edit field
779 if ( GetNativeControlRegion(CTRL_SPINBOX, PART_SUB_EDIT,
780 aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) )
782 // convert back from border space to local coordinates
783 aPoint = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aPoint ) );
784 aContent.Move(-aPoint.X(), -aPoint.Y());
786 // use the themes drop down size
787 mpEdit->SetPosPixel( aContent.TopLeft() );
788 bSubEditPositioned = true;
789 aSize = aContent.GetSize();
791 else
793 if ( maUpperRect.IsEmpty() )
795 DBG_ASSERT( !maDropDownRect.IsEmpty(), "SpinField::Resize: SPIN && DROPDOWN, but all empty rects?" );
796 aSize.Width() = maDropDownRect.Left();
798 else
799 aSize.Width() = maUpperRect.Left();
803 if( ! bSubEditPositioned )
805 // this moves our sub edit if RTL gets switched
806 mpEdit->SetPosPixel( Point() );
808 mpEdit->SetSizePixel( aSize );
810 if ( GetStyle() & WB_SPIN )
811 Invalidate( Rectangle( maUpperRect.TopLeft(), maLowerRect.BottomRight() ) );
812 if ( GetStyle() & WB_DROPDOWN )
813 Invalidate( maDropDownRect );
817 // -----------------------------------------------------------------------
819 void SpinField::StateChanged( StateChangedType nType )
821 Edit::StateChanged( nType );
823 if ( nType == STATE_CHANGE_ENABLE )
825 if ( mbSpin || ( GetStyle() & WB_DROPDOWN ) )
827 mpEdit->Enable( IsEnabled() );
829 if ( mbSpin )
831 Invalidate( maLowerRect );
832 Invalidate( maUpperRect );
834 if ( GetStyle() & WB_DROPDOWN )
835 Invalidate( maDropDownRect );
838 else if ( nType == STATE_CHANGE_STYLE )
840 if ( GetStyle() & WB_REPEAT )
841 mbRepeat = TRUE;
842 else
843 mbRepeat = FALSE;
845 else if ( nType == STATE_CHANGE_ZOOM )
847 Resize();
848 if ( mpEdit )
849 mpEdit->SetZoom( GetZoom() );
850 Invalidate();
852 else if ( nType == STATE_CHANGE_CONTROLFONT )
854 if ( mpEdit )
855 mpEdit->SetControlFont( GetControlFont() );
856 ImplInitSettings( TRUE, FALSE, FALSE );
857 Invalidate();
859 else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
861 if ( mpEdit )
862 mpEdit->SetControlForeground( GetControlForeground() );
863 ImplInitSettings( FALSE, TRUE, FALSE );
864 Invalidate();
866 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
868 if ( mpEdit )
869 mpEdit->SetControlBackground( GetControlBackground() );
870 ImplInitSettings( FALSE, FALSE, TRUE );
871 Invalidate();
873 else if( nType == STATE_CHANGE_MIRRORING )
875 if( mpEdit )
876 mpEdit->StateChanged( STATE_CHANGE_MIRRORING );
877 Resize();
881 // -----------------------------------------------------------------------
883 void SpinField::DataChanged( const DataChangedEvent& rDCEvt )
885 Edit::DataChanged( rDCEvt );
887 if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
888 (rDCEvt.GetFlags() & SETTINGS_STYLE) )
890 Resize();
891 Invalidate();
895 // -----------------------------------------------------------------------
897 Rectangle* SpinField::ImplFindPartRect( const Point& rPt )
899 if( maUpperRect.IsInside( rPt ) )
900 return &maUpperRect;
901 else if( maLowerRect.IsInside( rPt ) )
902 return &maLowerRect;
903 else
904 return NULL;
907 long SpinField::PreNotify( NotifyEvent& rNEvt )
909 long nDone = 0;
910 const MouseEvent* pMouseEvt = NULL;
912 if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
914 if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
916 // trigger redraw if mouse over state has changed
917 if( IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) ||
918 IsNativeControlSupported(CTRL_SPINBOX, PART_ALL_BUTTONS) )
920 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
921 Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
922 if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
924 // FIXME: this is currently only on aqua
925 // check for other platforms that need similar handling
926 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
927 IsNativeWidgetEnabled() &&
928 IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
930 ImplInvalidateOutermostBorder( this );
932 else
934 // paint directly
935 Region aRgn( GetActiveClipRegion() );
936 if( pLastRect )
938 SetClipRegion( *pLastRect );
939 Paint( *pLastRect );
940 SetClipRegion( aRgn );
942 if( pRect )
944 SetClipRegion( *pRect );
945 Paint( *pRect );
946 SetClipRegion( aRgn );
954 return nDone ? nDone : Edit::PreNotify(rNEvt);
957 // -----------------------------------------------------------------------
959 void SpinField::EndDropDown()
961 mbInDropDown = FALSE;
962 Paint( Rectangle( Point(), GetOutputSizePixel() ) );
965 // -----------------------------------------------------------------------
967 BOOL SpinField::ShowDropDown( BOOL )
969 return FALSE;
972 // -----------------------------------------------------------------------
974 Size SpinField::CalcMinimumSize() const
976 Size aSz = Edit::CalcMinimumSize();
978 if ( GetStyle() & WB_DROPDOWN )
979 aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
980 if ( GetStyle() & WB_SPIN )
981 aSz.Width() += maUpperRect.GetWidth();
983 return aSz;
986 // -----------------------------------------------------------------------
988 Size SpinField::GetOptimalSize(WindowSizeType eType) const
990 switch (eType) {
991 case WINDOWSIZE_MINIMUM:
992 return CalcMinimumSize();
993 default:
994 return Edit::GetOptimalSize( eType );
998 // -----------------------------------------------------------------------
1000 Size SpinField::CalcSize( USHORT nChars ) const
1002 Size aSz = Edit::CalcSize( nChars );
1004 if ( GetStyle() & WB_DROPDOWN )
1005 aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
1006 if ( GetStyle() & WB_SPIN )
1007 aSz.Width() += GetSettings().GetStyleSettings().GetSpinSize();
1009 return aSz;
1012 // --------------------------------------------------------------------
1014 IMPL_LINK( SpinField, ImplTimeout, Timer*, pTimer )
1016 if ( pTimer->GetTimeout() == GetSettings().GetMouseSettings().GetButtonStartRepeat() )
1018 pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
1019 pTimer->Start();
1021 else
1023 if ( mbInitialUp )
1024 Up();
1025 else
1026 Down();
1028 return 0;
1031 // -----------------------------------------------------------------------
1033 void SpinField::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags )
1035 Edit::Draw( pDev, rPos, rSize, nFlags );
1037 WinBits nFieldStyle = GetStyle();
1038 if ( !(nFlags & WINDOW_DRAW_NOCONTROLS ) && ( nFieldStyle & (WB_SPIN|WB_DROPDOWN) ) )
1040 Point aPos = pDev->LogicToPixel( rPos );
1041 Size aSize = pDev->LogicToPixel( rSize );
1042 OutDevType eOutDevType = pDev->GetOutDevType();
1043 AllSettings aOldSettings = pDev->GetSettings();
1045 pDev->Push();
1046 pDev->SetMapMode();
1048 if ( eOutDevType == OUTDEV_PRINTER )
1050 StyleSettings aStyleSettings = aOldSettings.GetStyleSettings();
1051 aStyleSettings.SetFaceColor( COL_LIGHTGRAY );
1052 aStyleSettings.SetButtonTextColor( COL_BLACK );
1053 AllSettings aSettings( aOldSettings );
1054 aSettings.SetStyleSettings( aStyleSettings );
1055 pDev->SetSettings( aSettings );
1058 Rectangle aDD, aUp, aDown;
1059 ImplCalcButtonAreas( pDev, aSize, aDD, aUp, aDown );
1060 aDD.Move( aPos.X(), aPos.Y() );
1061 aUp.Move( aPos.X(), aPos.Y() );
1062 aUp.Top()++;
1063 aDown.Move( aPos.X(), aPos.Y() );
1065 Color aButtonTextColor;
1066 if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
1067 aButtonTextColor = Color( COL_BLACK );
1068 else
1069 aButtonTextColor = GetSettings().GetStyleSettings().GetButtonTextColor();
1071 if ( GetStyle() & WB_DROPDOWN )
1073 DecorationView aView( pDev );
1074 USHORT nStyle = BUTTON_DRAW_NOLIGHTBORDER;
1075 Rectangle aInnerRect = aView.DrawButton( aDD, nStyle );
1076 SymbolType eSymbol = SYMBOL_SPIN_DOWN;
1077 if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
1078 eSymbol = SYMBOL_SPIN_UPDOWN;
1080 nStyle = ( IsEnabled() || ( nFlags & WINDOW_DRAW_NODISABLE ) ) ? 0 : SYMBOL_DRAW_DISABLE;
1081 aView.DrawSymbol( aInnerRect, eSymbol, aButtonTextColor, nStyle );
1084 if ( GetStyle() & WB_SPIN )
1086 ImplDrawSpinButton( pDev, aUp, aDown, FALSE, FALSE, TRUE, TRUE );
1089 pDev->Pop();
1090 pDev->SetSettings( aOldSettings );