merge the formfield patch from ooo-build
[ooovba.git] / vcl / source / control / spinfld.cxx
blob4f2bb716a3b585080932583064aecd2c7713aa5b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: spinfld.cxx,v $
10 * $Revision: 1.28 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include "tools/rc.h"
35 #include "vcl/event.hxx"
36 #include "vcl/decoview.hxx"
37 #include "vcl/spin.h"
38 #include "vcl/spinfld.hxx"
39 #include "vcl/controllayout.hxx"
40 #include "vcl/svdata.hxx"
42 // =======================================================================
44 void ImplGetSpinbuttonValue( Window *pWin, const Rectangle& rUpperRect,
45 const Rectangle& rLowerRect,
46 BOOL bUpperIn, BOOL bLowerIn,
47 BOOL bUpperEnabled, BOOL bLowerEnabled, BOOL bHorz,
48 SpinbuttonValue& rValue )
50 // convert spinbutton data to a SpinbuttonValue structure for native painting
52 rValue.maUpperRect = rUpperRect;
53 rValue.maLowerRect = rLowerRect;
55 Point aPointerPos = pWin->GetPointerPosPixel();
57 ControlState nState = CTRL_STATE_ENABLED;
58 if ( bUpperIn )
59 nState |= CTRL_STATE_PRESSED;
60 if ( !pWin->IsEnabled() || !bUpperEnabled )
61 nState &= ~CTRL_STATE_ENABLED;
62 if ( pWin->HasFocus() )
63 nState |= CTRL_STATE_FOCUSED;
64 if( pWin->IsMouseOver() && rUpperRect.IsInside( aPointerPos ) )
65 nState |= CTRL_STATE_ROLLOVER;
66 rValue.mnUpperState = nState;
68 nState = CTRL_STATE_ENABLED;
69 if ( bLowerIn )
70 nState |= CTRL_STATE_PRESSED;
71 if ( !pWin->IsEnabled() || !bLowerEnabled )
72 nState &= ~CTRL_STATE_ENABLED;
73 if ( pWin->HasFocus() )
74 nState |= CTRL_STATE_FOCUSED;
75 // for overlapping spins: highlight only one
76 if( pWin->IsMouseOver() && rLowerRect.IsInside( aPointerPos ) &&
77 !rUpperRect.IsInside( aPointerPos ) )
78 nState |= CTRL_STATE_ROLLOVER;
79 rValue.mnLowerState = nState;
81 rValue.mnUpperPart = bHorz ? PART_BUTTON_LEFT : PART_BUTTON_UP;
82 rValue.mnLowerPart = bHorz ? PART_BUTTON_RIGHT : PART_BUTTON_DOWN;
86 BOOL ImplDrawNativeSpinfield( Window *pWin, const SpinbuttonValue& rSpinbuttonValue )
88 BOOL bNativeOK = FALSE;
90 if( pWin->IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) &&
91 // there is just no useful native support for spinfields with dropdown
92 !(pWin->GetStyle() & WB_DROPDOWN) )
94 ImplControlValue aControlValue;
95 aControlValue.setOptionalVal( (void*) &rSpinbuttonValue );
97 if( pWin->IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnUpperPart) &&
98 pWin->IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnLowerPart) )
100 // only paint the embedded spin buttons, all buttons are painted at once
101 bNativeOK = pWin->DrawNativeControl( CTRL_SPINBOX, PART_ALL_BUTTONS, Region(), CTRL_STATE_ENABLED,
102 aControlValue, rtl::OUString() );
104 else
106 // paint the spinbox as a whole, use borderwindow to have proper clipping
107 Window *pBorder = pWin->GetWindow( WINDOW_BORDER );
109 // to not overwrite everything, set the button region as clipregion to the border window
110 Rectangle aClipRect( rSpinbuttonValue.maLowerRect );
111 aClipRect.Union( rSpinbuttonValue.maUpperRect );
113 // convert from screen space to borderwin space
114 aClipRect.SetPos( pBorder->ScreenToOutputPixel(pWin->OutputToScreenPixel(aClipRect.TopLeft())) );
116 Region oldRgn( pBorder->GetClipRegion() );
117 pBorder->SetClipRegion( Region( aClipRect ) );
119 Point aPt;
120 Size aSize( pBorder->GetOutputSizePixel() ); // the size of the border window, i.e., the whole control
121 Region aBound, aContent;
122 Region aNatRgn( Rectangle( aPt, aSize ) );
123 if( pBorder->GetNativeControlRegion(CTRL_SPINBOX, PART_ENTIRE_CONTROL,
124 aNatRgn, 0, aControlValue, rtl::OUString(), aBound, aContent) )
126 aSize = aContent.GetBoundRect().GetSize();
129 Region aRgn( Rectangle( aPt, aSize ) );
130 bNativeOK = pBorder->DrawNativeControl( CTRL_SPINBOX, PART_ENTIRE_CONTROL, aRgn, CTRL_STATE_ENABLED,
131 aControlValue, rtl::OUString() );
133 pBorder->SetClipRegion( oldRgn );
136 return bNativeOK;
139 BOOL ImplDrawNativeSpinbuttons( Window *pWin, const SpinbuttonValue& rSpinbuttonValue )
141 BOOL bNativeOK = FALSE;
143 if( pWin->IsNativeControlSupported(CTRL_SPINBUTTONS, PART_ENTIRE_CONTROL) )
145 ImplControlValue aControlValue;
146 aControlValue.setOptionalVal( (void*) &rSpinbuttonValue );
148 // only paint the standalone spin buttons, all buttons are painted at once
149 bNativeOK = pWin->DrawNativeControl( CTRL_SPINBUTTONS, PART_ALL_BUTTONS, Region(), CTRL_STATE_ENABLED,
150 aControlValue, rtl::OUString() );
152 return bNativeOK;
155 void ImplDrawSpinButton( OutputDevice* pOutDev,
156 const Rectangle& rUpperRect,
157 const Rectangle& rLowerRect,
158 BOOL bUpperIn, BOOL bLowerIn,
159 BOOL bUpperEnabled, BOOL bLowerEnabled, BOOL bHorz, BOOL bMirrorHorz )
161 DecorationView aDecoView( pOutDev );
163 USHORT nStyle = BUTTON_DRAW_NOLEFTLIGHTBORDER;
164 USHORT nSymStyle = 0;
166 SymbolType eType1, eType2;
168 const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings();
169 if ( rStyleSettings.GetOptions() & STYLE_OPTION_SPINARROW )
171 // arrows are only use in OS/2 look
172 if ( bHorz )
174 eType1 = bMirrorHorz ? SYMBOL_ARROW_RIGHT : SYMBOL_ARROW_LEFT;
175 eType2 = bMirrorHorz ? SYMBOL_ARROW_LEFT : SYMBOL_ARROW_RIGHT;
177 else
179 eType1 = SYMBOL_ARROW_UP;
180 eType2 = SYMBOL_ARROW_DOWN;
183 else
185 if ( bHorz )
187 eType1 = bMirrorHorz ? SYMBOL_SPIN_RIGHT : SYMBOL_SPIN_LEFT;
188 eType2 = bMirrorHorz ? SYMBOL_SPIN_LEFT : SYMBOL_SPIN_RIGHT;
190 else
192 eType1 = SYMBOL_SPIN_UP;
193 eType2 = SYMBOL_SPIN_DOWN;
197 // Oberen/linken Button malen
198 USHORT nTempStyle = nStyle;
199 if ( bUpperIn )
200 nTempStyle |= BUTTON_DRAW_PRESSED;
202 BOOL bNativeOK = FALSE;
203 Rectangle aUpRect;
205 if( pOutDev->GetOutDevType() == OUTDEV_WINDOW )
207 Window *pWin = (Window*) pOutDev;
209 // are we drawing standalone spin buttons or members of a spinfield ?
210 ControlType aControl = CTRL_SPINBUTTONS;
211 switch( pWin->GetType() )
213 case WINDOW_EDIT:
214 case WINDOW_MULTILINEEDIT:
215 case WINDOW_PATTERNFIELD:
216 case WINDOW_METRICFIELD:
217 case WINDOW_CURRENCYFIELD:
218 case WINDOW_DATEFIELD:
219 case WINDOW_TIMEFIELD:
220 case WINDOW_LONGCURRENCYFIELD:
221 case WINDOW_NUMERICFIELD:
222 case WINDOW_SPINFIELD:
223 aControl = CTRL_SPINBOX;
224 break;
225 default:
226 aControl = CTRL_SPINBUTTONS;
227 break;
230 SpinbuttonValue aValue;
231 ImplGetSpinbuttonValue( pWin, rUpperRect, rLowerRect,
232 bUpperIn, bLowerIn, bUpperEnabled, bLowerEnabled,
233 bHorz, aValue );
235 if( aControl == CTRL_SPINBOX )
236 bNativeOK = ImplDrawNativeSpinfield( pWin, aValue );
237 else if( aControl == CTRL_SPINBUTTONS )
238 bNativeOK = ImplDrawNativeSpinbuttons( pWin, aValue );
241 if( !bNativeOK )
242 aUpRect = aDecoView.DrawButton( rUpperRect, nTempStyle );
244 // Unteren/rechten Button malen
245 if ( bLowerIn )
246 nStyle |= BUTTON_DRAW_PRESSED;
247 Rectangle aLowRect;
248 if( !bNativeOK )
249 aLowRect = aDecoView.DrawButton( rLowerRect, nStyle );
251 // Zusaetzliche Default-Kante wollen wir auch ausnutzen
252 aUpRect.Left()--;
253 aUpRect.Top()--;
254 aUpRect.Right()++;
255 aUpRect.Bottom()++;
256 aLowRect.Left()--;
257 aLowRect.Top()--;
258 aLowRect.Right()++;
259 aLowRect.Bottom()++;
261 // Wir malen auch in die Kante rein, damit man etwas erkennen kann,
262 // wenn das Rechteck zu klein ist
263 if ( aUpRect.GetHeight() < 4 )
265 aUpRect.Right()++;
266 aUpRect.Bottom()++;
267 aLowRect.Right()++;
268 aLowRect.Bottom()++;
271 // Symbolgroesse berechnen
272 long nTempSize1 = aUpRect.GetWidth();
273 long nTempSize2 = aLowRect.GetWidth();
274 if ( Abs( nTempSize1-nTempSize2 ) == 1 )
276 if ( nTempSize1 > nTempSize2 )
277 aUpRect.Left()++;
278 else
279 aLowRect.Left()++;
281 nTempSize1 = aUpRect.GetHeight();
282 nTempSize2 = aLowRect.GetHeight();
283 if ( Abs( nTempSize1-nTempSize2 ) == 1 )
285 if ( nTempSize1 > nTempSize2 )
286 aUpRect.Top()++;
287 else
288 aLowRect.Top()++;
291 nTempStyle = nSymStyle;
292 if ( !bUpperEnabled )
293 nTempStyle |= SYMBOL_DRAW_DISABLE;
294 if( !bNativeOK )
295 aDecoView.DrawSymbol( aUpRect, eType1, rStyleSettings.GetButtonTextColor(), nTempStyle );
297 if ( !bLowerEnabled )
298 nSymStyle |= SYMBOL_DRAW_DISABLE;
299 if( !bNativeOK )
300 aDecoView.DrawSymbol( aLowRect, eType2, rStyleSettings.GetButtonTextColor(), nSymStyle );
303 // =======================================================================
305 void SpinField::ImplInitSpinFieldData()
307 mpEdit = NULL;
308 mbSpin = FALSE;
309 mbRepeat = FALSE;
310 mbUpperIn = FALSE;
311 mbLowerIn = FALSE;
312 mbInitialUp = FALSE;
313 mbInitialDown = FALSE;
314 mbNoSelect = FALSE;
315 mbInDropDown = FALSE;
318 // --------------------------------------------------------------------
320 void SpinField::ImplInit( Window* pParent, WinBits nWinStyle )
322 Edit::ImplInit( pParent, nWinStyle );
324 if ( nWinStyle & (WB_SPIN|WB_DROPDOWN) )
326 mbSpin = TRUE;
328 // Some themes want external spin buttons, therefore the main
329 // spinfield should not overdraw the border between its encapsulated
330 // edit field and the spin buttons
331 if ( (nWinStyle & WB_SPIN) && ImplUseNativeBorder( nWinStyle ) )
333 SetBackground();
334 mpEdit = new Edit( this, WB_NOBORDER );
335 mpEdit->SetBackground();
337 else
338 mpEdit = new Edit( this, WB_NOBORDER );
340 mpEdit->EnableRTL( FALSE );
341 mpEdit->SetPosPixel( Point() );
342 mpEdit->Show();
343 SetSubEdit( mpEdit );
345 maRepeatTimer.SetTimeoutHdl( LINK( this, SpinField, ImplTimeout ) );
346 maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
347 if ( nWinStyle & WB_REPEAT )
348 mbRepeat = TRUE;
350 SetCompoundControl( TRUE );
354 // --------------------------------------------------------------------
356 SpinField::SpinField( WindowType nTyp ) :
357 Edit( nTyp )
359 ImplInitSpinFieldData();
362 // --------------------------------------------------------------------
364 SpinField::SpinField( Window* pParent, WinBits nWinStyle ) :
365 Edit( WINDOW_SPINFIELD )
367 ImplInitSpinFieldData();
368 ImplInit( pParent, nWinStyle );
371 // --------------------------------------------------------------------
373 SpinField::SpinField( Window* pParent, const ResId& rResId ) :
374 Edit( WINDOW_SPINFIELD )
376 ImplInitSpinFieldData();
377 rResId.SetRT( RSC_SPINFIELD );
378 WinBits nStyle = ImplInitRes( rResId );
379 ImplInit( pParent, nStyle );
380 ImplLoadRes( rResId );
382 if ( !(nStyle & WB_HIDE) )
383 Show();
386 // --------------------------------------------------------------------
388 SpinField::~SpinField()
390 delete mpEdit;
393 // --------------------------------------------------------------------
395 void SpinField::Up()
397 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_UP, maUpHdlLink, this );
400 // --------------------------------------------------------------------
402 void SpinField::Down()
404 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_DOWN, maDownHdlLink, this );
407 // --------------------------------------------------------------------
409 void SpinField::First()
411 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_FIRST, maFirstHdlLink, this );
414 // --------------------------------------------------------------------
416 void SpinField::Last()
418 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_LAST, maLastHdlLink, this );
421 // --------------------------------------------------------------------
423 void SpinField::MouseButtonDown( const MouseEvent& rMEvt )
425 if ( !HasFocus() && ( !mpEdit || !mpEdit->HasFocus() ) )
427 mbNoSelect = TRUE;
428 GrabFocus();
431 if ( !IsReadOnly() )
433 if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) )
435 mbUpperIn = TRUE;
436 mbInitialUp = TRUE;
437 Invalidate( maUpperRect );
439 else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) )
441 mbLowerIn = TRUE;
442 mbInitialDown = TRUE;
443 Invalidate( maLowerRect );
445 else if ( maDropDownRect.IsInside( rMEvt.GetPosPixel() ) )
447 // Rechts daneben liegt der DropDownButton:
448 mbInDropDown = ShowDropDown( mbInDropDown ? FALSE : TRUE );
449 Paint( Rectangle( Point(), GetOutputSizePixel() ) );
452 if ( mbUpperIn || mbLowerIn )
454 Update();
455 CaptureMouse();
456 if ( mbRepeat )
457 maRepeatTimer.Start();
458 return;
462 Edit::MouseButtonDown( rMEvt );
465 // --------------------------------------------------------------------
467 void SpinField::MouseButtonUp( const MouseEvent& rMEvt )
469 ReleaseMouse();
470 mbInitialUp = mbInitialDown = FALSE;
471 maRepeatTimer.Stop();
472 maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
474 if ( mbUpperIn )
476 mbUpperIn = FALSE;
477 Invalidate( maUpperRect );
478 Update();
479 Up();
481 else if ( mbLowerIn )
483 mbLowerIn = FALSE;
484 Invalidate( maLowerRect );
485 Update();
486 Down();
489 Edit::MouseButtonUp( rMEvt );
492 // --------------------------------------------------------------------
494 void SpinField::MouseMove( const MouseEvent& rMEvt )
496 if ( rMEvt.IsLeft() )
498 if ( mbInitialUp )
500 BOOL bNewUpperIn = maUpperRect.IsInside( rMEvt.GetPosPixel() );
501 if ( bNewUpperIn != mbUpperIn )
503 if ( bNewUpperIn )
505 if ( mbRepeat )
506 maRepeatTimer.Start();
508 else
509 maRepeatTimer.Stop();
511 mbUpperIn = bNewUpperIn;
512 Invalidate( maUpperRect );
513 Update();
516 else if ( mbInitialDown )
518 BOOL bNewLowerIn = maLowerRect.IsInside( rMEvt.GetPosPixel() );
519 if ( bNewLowerIn != mbLowerIn )
521 if ( bNewLowerIn )
523 if ( mbRepeat )
524 maRepeatTimer.Start();
526 else
527 maRepeatTimer.Stop();
529 mbLowerIn = bNewLowerIn;
530 Invalidate( maLowerRect );
531 Update();
536 Edit::MouseMove( rMEvt );
539 // --------------------------------------------------------------------
541 long SpinField::Notify( NotifyEvent& rNEvt )
543 long nDone = 0;
544 if( rNEvt.GetType() == EVENT_KEYINPUT )
546 const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
547 if ( !IsReadOnly() )
549 USHORT nMod = rKEvt.GetKeyCode().GetModifier();
550 switch ( rKEvt.GetKeyCode().GetCode() )
552 case KEY_UP:
554 if ( !nMod )
556 Up();
557 nDone = 1;
560 break;
561 case KEY_DOWN:
563 if ( !nMod )
565 Down();
566 nDone = 1;
568 else if ( ( nMod == KEY_MOD2 ) && !mbInDropDown && ( GetStyle() & WB_DROPDOWN ) )
570 mbInDropDown = ShowDropDown( TRUE );
571 Paint( Rectangle( Point(), GetOutputSizePixel() ) );
572 nDone = 1;
575 break;
576 case KEY_PAGEUP:
578 if ( !nMod )
580 Last();
581 nDone = 1;
584 break;
585 case KEY_PAGEDOWN:
587 if ( !nMod )
589 First();
590 nDone = 1;
593 break;
598 if ( rNEvt.GetType() == EVENT_COMMAND )
600 if ( ( rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL ) && !IsReadOnly() )
602 USHORT nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
603 if ( ( nWheelBehavior == MOUSE_WHEEL_ALWAYS )
604 || ( ( nWheelBehavior == MOUSE_WHEEL_FOCUS_ONLY )
605 && HasChildPathFocus()
609 const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
610 if ( pData->GetMode() == COMMAND_WHEEL_SCROLL )
612 if ( pData->GetDelta() < 0L )
613 Down();
614 else
615 Up();
616 nDone = 1;
619 else
620 nDone = 0; // don't eat this event, let the default handling happen (i.e. scroll the context)
624 return nDone ? nDone : Edit::Notify( rNEvt );
627 // --------------------------------------------------------------------
629 void SpinField::Command( const CommandEvent& rCEvt )
631 Edit::Command( rCEvt );
634 // --------------------------------------------------------------------
636 void SpinField::FillLayoutData() const
638 if( mbSpin )
640 mpLayoutData = new vcl::ControlLayoutData();
641 AppendLayoutData( *GetSubEdit() );
642 GetSubEdit()->SetLayoutDataParent( this );
644 else
645 Edit::FillLayoutData();
648 // --------------------------------------------------------------------
650 void SpinField::Paint( const Rectangle& rRect )
652 if ( mbSpin )
654 BOOL bEnable = IsEnabled();
655 ImplDrawSpinButton( this, maUpperRect, maLowerRect,
656 mbUpperIn, mbLowerIn, bEnable, bEnable );
659 if ( GetStyle() & WB_DROPDOWN )
661 DecorationView aView( this );
663 USHORT nStyle = BUTTON_DRAW_NOLIGHTBORDER;
664 if ( mbInDropDown )
665 nStyle |= BUTTON_DRAW_PRESSED;
666 Rectangle aInnerRect = aView.DrawButton( maDropDownRect, nStyle );
668 SymbolType eSymbol = SYMBOL_SPIN_DOWN;
669 if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
670 eSymbol = SYMBOL_SPIN_UPDOWN;
672 nStyle = IsEnabled() ? 0 : SYMBOL_DRAW_DISABLE;
673 aView.DrawSymbol( aInnerRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle );
676 Edit::Paint( rRect );
679 // --------------------------------------------------------------------
681 void SpinField::ImplCalcButtonAreas( OutputDevice* pDev, const Size& rOutSz, Rectangle& rDDArea, Rectangle& rSpinUpArea, Rectangle& rSpinDownArea )
683 const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings();
685 Size aSize = rOutSz;
686 Size aDropDownSize;
688 if ( GetStyle() & WB_DROPDOWN )
690 long nW = rStyleSettings.GetScrollBarSize();
691 nW = GetDrawPixel( pDev, nW );
692 aDropDownSize = Size( CalcZoom( nW ), aSize.Height() );
693 aSize.Width() -= aDropDownSize.Width();
694 rDDArea = Rectangle( Point( aSize.Width(), 0 ), aDropDownSize );
695 rDDArea.Top()--;
697 else
698 rDDArea.SetEmpty();
700 // Je nach Hoehe, die groessen Berechnen
701 if ( GetStyle() & WB_SPIN )
703 long nBottom1 = aSize.Height()/2;
704 long nBottom2 = aSize.Height()-1;
705 long nTop2 = nBottom1;
706 long nTop1 = 0;
707 if ( !(aSize.Height() & 0x01) )
708 nBottom1--;
710 BOOL bNativeRegionOK = FALSE;
711 Region aContentUp, aContentDown;
713 if ( (pDev->GetOutDevType() == OUTDEV_WINDOW) &&
714 // there is just no useful native support for spinfields with dropdown
715 ! (GetStyle() & WB_DROPDOWN) &&
716 IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) )
718 Window *pWin = (Window*) pDev;
719 Window *pBorder = pWin->GetWindow( WINDOW_BORDER );
721 // get the system's spin button size
722 ImplControlValue aControlValue;
723 Region aBound;
724 Point aPoint;
726 // use the full extent of the control
727 Region aArea( Rectangle( aPoint, pBorder->GetOutputSizePixel() ) );
729 bNativeRegionOK =
730 pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_UP,
731 aArea, 0, aControlValue, rtl::OUString(), aBound, aContentUp) &&
732 pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_DOWN,
733 aArea, 0, aControlValue, rtl::OUString(), aBound, aContentDown);
735 if( bNativeRegionOK )
737 // convert back from border space to local coordinates
738 aPoint = pBorder->ScreenToOutputPixel( pWin->OutputToScreenPixel( aPoint ) );
739 aContentUp.Move(-aPoint.X(), -aPoint.Y());
740 aContentDown.Move(-aPoint.X(), -aPoint.Y());
744 if( bNativeRegionOK )
746 rSpinUpArea = aContentUp.GetBoundRect();
747 rSpinDownArea = aContentDown.GetBoundRect();
749 else
751 aSize.Width() -= CalcZoom( GetDrawPixel( pDev, rStyleSettings.GetSpinSize() ) );
753 rSpinUpArea = Rectangle( aSize.Width(), nTop1, rOutSz.Width()-aDropDownSize.Width()-1, nBottom1 );
754 rSpinDownArea = Rectangle( rSpinUpArea.Left(), nTop2, rSpinUpArea.Right(), nBottom2 );
757 else
759 rSpinUpArea.SetEmpty();
760 rSpinDownArea.SetEmpty();
764 // --------------------------------------------------------------------
766 void SpinField::Resize()
768 if ( mbSpin )
770 Control::Resize();
771 Size aSize = GetOutputSizePixel();
772 bool bSubEditPositioned = false;
774 if ( GetStyle() & (WB_SPIN|WB_DROPDOWN) )
776 ImplCalcButtonAreas( this, aSize, maDropDownRect, maUpperRect, maLowerRect );
778 ImplControlValue aControlValue;
779 Point aPoint;
780 Region aContent, aBound;
782 // use the full extent of the control
783 Window *pBorder = GetWindow( WINDOW_BORDER );
784 Region aArea( Rectangle(aPoint, pBorder->GetOutputSizePixel()) );
786 // adjust position and size of the edit field
787 if ( GetNativeControlRegion(CTRL_SPINBOX, PART_SUB_EDIT,
788 aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) )
790 // convert back from border space to local coordinates
791 aPoint = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aPoint ) );
792 aContent.Move(-aPoint.X(), -aPoint.Y());
794 // use the themes drop down size
795 Rectangle aContentRect = aContent.GetBoundRect();
796 mpEdit->SetPosPixel( aContentRect.TopLeft() );
797 bSubEditPositioned = true;
798 aSize = aContentRect.GetSize();
800 else
802 if ( maUpperRect.IsEmpty() )
804 DBG_ASSERT( !maDropDownRect.IsEmpty(), "SpinField::Resize: SPIN && DROPDOWN, but all empty rects?" );
805 aSize.Width() = maDropDownRect.Left();
807 else
808 aSize.Width() = maUpperRect.Left();
812 if( ! bSubEditPositioned )
814 // this moves our sub edit if RTL gets switched
815 mpEdit->SetPosPixel( Point() );
817 mpEdit->SetSizePixel( aSize );
819 if ( GetStyle() & WB_SPIN )
820 Invalidate( Rectangle( maUpperRect.TopLeft(), maLowerRect.BottomRight() ) );
821 if ( GetStyle() & WB_DROPDOWN )
822 Invalidate( maDropDownRect );
826 // -----------------------------------------------------------------------
828 void SpinField::StateChanged( StateChangedType nType )
830 Edit::StateChanged( nType );
832 if ( nType == STATE_CHANGE_ENABLE )
834 if ( mbSpin || ( GetStyle() & WB_DROPDOWN ) )
836 mpEdit->Enable( IsEnabled() );
838 if ( mbSpin )
840 Invalidate( maLowerRect );
841 Invalidate( maUpperRect );
843 if ( GetStyle() & WB_DROPDOWN )
844 Invalidate( maDropDownRect );
847 else if ( nType == STATE_CHANGE_STYLE )
849 if ( GetStyle() & WB_REPEAT )
850 mbRepeat = TRUE;
851 else
852 mbRepeat = FALSE;
854 else if ( nType == STATE_CHANGE_ZOOM )
856 Resize();
857 if ( mpEdit )
858 mpEdit->SetZoom( GetZoom() );
859 Invalidate();
861 else if ( nType == STATE_CHANGE_CONTROLFONT )
863 if ( mpEdit )
864 mpEdit->SetControlFont( GetControlFont() );
865 ImplInitSettings( TRUE, FALSE, FALSE );
866 Invalidate();
868 else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
870 if ( mpEdit )
871 mpEdit->SetControlForeground( GetControlForeground() );
872 ImplInitSettings( FALSE, TRUE, FALSE );
873 Invalidate();
875 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
877 if ( mpEdit )
878 mpEdit->SetControlBackground( GetControlBackground() );
879 ImplInitSettings( FALSE, FALSE, TRUE );
880 Invalidate();
882 else if( nType == STATE_CHANGE_MIRRORING )
884 if( mpEdit )
885 mpEdit->StateChanged( STATE_CHANGE_MIRRORING );
886 Resize();
890 // -----------------------------------------------------------------------
892 void SpinField::DataChanged( const DataChangedEvent& rDCEvt )
894 Edit::DataChanged( rDCEvt );
896 if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
897 (rDCEvt.GetFlags() & SETTINGS_STYLE) )
899 Resize();
900 Invalidate();
904 // -----------------------------------------------------------------------
906 Rectangle* SpinField::ImplFindPartRect( const Point& rPt )
908 if( maUpperRect.IsInside( rPt ) )
909 return &maUpperRect;
910 else if( maLowerRect.IsInside( rPt ) )
911 return &maLowerRect;
912 else
913 return NULL;
916 long SpinField::PreNotify( NotifyEvent& rNEvt )
918 long nDone = 0;
919 const MouseEvent* pMouseEvt = NULL;
921 if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
923 if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
925 // trigger redraw if mouse over state has changed
926 if( IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) ||
927 IsNativeControlSupported(CTRL_SPINBOX, PART_ALL_BUTTONS) )
929 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
930 Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
931 if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
933 // FIXME: this is currently only on aqua
934 // check for other platforms that need similar handling
935 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
936 IsNativeWidgetEnabled() &&
937 IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
939 ImplInvalidateOutermostBorder( this );
941 else
943 // paint directly
944 Region aRgn( GetActiveClipRegion() );
945 if( pLastRect )
947 SetClipRegion( *pLastRect );
948 Paint( *pLastRect );
949 SetClipRegion( aRgn );
951 if( pRect )
953 SetClipRegion( *pRect );
954 Paint( *pRect );
955 SetClipRegion( aRgn );
963 return nDone ? nDone : Edit::PreNotify(rNEvt);
966 // -----------------------------------------------------------------------
968 void SpinField::EndDropDown()
970 mbInDropDown = FALSE;
971 Paint( Rectangle( Point(), GetOutputSizePixel() ) );
974 // -----------------------------------------------------------------------
976 BOOL SpinField::ShowDropDown( BOOL )
978 return FALSE;
981 // -----------------------------------------------------------------------
983 Size SpinField::CalcMinimumSize() const
985 Size aSz = Edit::CalcMinimumSize();
987 if ( GetStyle() & WB_DROPDOWN )
988 aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
989 if ( GetStyle() & WB_SPIN )
990 aSz.Width() += maUpperRect.GetWidth();
992 return aSz;
995 // -----------------------------------------------------------------------
997 Size SpinField::GetOptimalSize(WindowSizeType eType) const
999 switch (eType) {
1000 case WINDOWSIZE_MINIMUM:
1001 return CalcMinimumSize();
1002 default:
1003 return Edit::GetOptimalSize( eType );
1007 // -----------------------------------------------------------------------
1009 Size SpinField::CalcSize( USHORT nChars ) const
1011 Size aSz = Edit::CalcSize( nChars );
1013 if ( GetStyle() & WB_DROPDOWN )
1014 aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
1015 if ( GetStyle() & WB_SPIN )
1016 aSz.Width() += GetSettings().GetStyleSettings().GetSpinSize();
1018 return aSz;
1021 // --------------------------------------------------------------------
1023 IMPL_LINK( SpinField, ImplTimeout, Timer*, pTimer )
1025 if ( pTimer->GetTimeout() == GetSettings().GetMouseSettings().GetButtonStartRepeat() )
1027 pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
1028 pTimer->Start();
1030 else
1032 if ( mbInitialUp )
1033 Up();
1034 else
1035 Down();
1037 return 0;
1040 // -----------------------------------------------------------------------
1042 void SpinField::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags )
1044 Edit::Draw( pDev, rPos, rSize, nFlags );
1046 WinBits nFieldStyle = GetStyle();
1047 if ( !(nFlags & WINDOW_DRAW_NOCONTROLS ) && ( nFieldStyle & (WB_SPIN|WB_DROPDOWN) ) )
1049 Point aPos = pDev->LogicToPixel( rPos );
1050 Size aSize = pDev->LogicToPixel( rSize );
1051 OutDevType eOutDevType = pDev->GetOutDevType();
1052 AllSettings aOldSettings = pDev->GetSettings();
1054 pDev->Push();
1055 pDev->SetMapMode();
1057 if ( eOutDevType == OUTDEV_PRINTER )
1059 StyleSettings aStyleSettings = aOldSettings.GetStyleSettings();
1060 aStyleSettings.SetFaceColor( COL_LIGHTGRAY );
1061 aStyleSettings.SetButtonTextColor( COL_BLACK );
1062 AllSettings aSettings( aOldSettings );
1063 aSettings.SetStyleSettings( aStyleSettings );
1064 pDev->SetSettings( aSettings );
1067 Rectangle aDD, aUp, aDown;
1068 ImplCalcButtonAreas( pDev, aSize, aDD, aUp, aDown );
1069 aDD.Move( aPos.X(), aPos.Y() );
1070 aUp.Move( aPos.X(), aPos.Y() );
1071 aUp.Top()++;
1072 aDown.Move( aPos.X(), aPos.Y() );
1074 Color aButtonTextColor;
1075 if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
1076 aButtonTextColor = Color( COL_BLACK );
1077 else
1078 aButtonTextColor = GetSettings().GetStyleSettings().GetButtonTextColor();
1080 if ( GetStyle() & WB_DROPDOWN )
1082 DecorationView aView( pDev );
1083 USHORT nStyle = BUTTON_DRAW_NOLIGHTBORDER;
1084 Rectangle aInnerRect = aView.DrawButton( aDD, nStyle );
1085 SymbolType eSymbol = SYMBOL_SPIN_DOWN;
1086 if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
1087 eSymbol = SYMBOL_SPIN_UPDOWN;
1089 nStyle = ( IsEnabled() || ( nFlags & WINDOW_DRAW_NODISABLE ) ) ? 0 : SYMBOL_DRAW_DISABLE;
1090 aView.DrawSymbol( aInnerRect, eSymbol, aButtonTextColor, nStyle );
1093 if ( GetStyle() & WB_SPIN )
1095 ImplDrawSpinButton( pDev, aUp, aDown, FALSE, FALSE, TRUE, TRUE );
1098 pDev->Pop();
1099 pDev->SetSettings( aOldSettings );