bump product version to 4.1.6.2
[LibreOffice.git] / vcl / source / control / spinfld.cxx
blobb6aa626d4c1c3c37c6d460f14e3d5337d7dfc9ad
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include "tools/rc.h"
23 #include "vcl/event.hxx"
24 #include "vcl/decoview.hxx"
25 #include "vcl/spin.h"
26 #include "vcl/spinfld.hxx"
28 #include "controldata.hxx"
29 #include "svdata.hxx"
31 // =======================================================================
33 namespace {
35 void ImplGetSpinbuttonValue( Window *pWin, const Rectangle& rUpperRect,
36 const Rectangle& rLowerRect,
37 sal_Bool bUpperIn, sal_Bool bLowerIn,
38 sal_Bool bUpperEnabled, sal_Bool bLowerEnabled, sal_Bool bHorz,
39 SpinbuttonValue& rValue )
41 // convert spinbutton data to a SpinbuttonValue structure for native painting
43 rValue.maUpperRect = rUpperRect;
44 rValue.maLowerRect = rLowerRect;
46 Point aPointerPos = pWin->GetPointerPosPixel();
48 ControlState nState = CTRL_STATE_ENABLED;
49 if ( bUpperIn )
50 nState |= CTRL_STATE_PRESSED;
51 if ( !pWin->IsEnabled() || !bUpperEnabled )
52 nState &= ~CTRL_STATE_ENABLED;
53 if ( pWin->HasFocus() )
54 nState |= CTRL_STATE_FOCUSED;
55 if( pWin->IsMouseOver() && rUpperRect.IsInside( aPointerPos ) )
56 nState |= CTRL_STATE_ROLLOVER;
57 rValue.mnUpperState = nState;
59 nState = CTRL_STATE_ENABLED;
60 if ( bLowerIn )
61 nState |= CTRL_STATE_PRESSED;
62 if ( !pWin->IsEnabled() || !bLowerEnabled )
63 nState &= ~CTRL_STATE_ENABLED;
64 if ( pWin->HasFocus() )
65 nState |= CTRL_STATE_FOCUSED;
66 // for overlapping spins: highlight only one
67 if( pWin->IsMouseOver() && rLowerRect.IsInside( aPointerPos ) &&
68 !rUpperRect.IsInside( aPointerPos ) )
69 nState |= CTRL_STATE_ROLLOVER;
70 rValue.mnLowerState = nState;
72 rValue.mnUpperPart = bHorz ? PART_BUTTON_LEFT : PART_BUTTON_UP;
73 rValue.mnLowerPart = bHorz ? PART_BUTTON_RIGHT : PART_BUTTON_DOWN;
77 sal_Bool ImplDrawNativeSpinfield( Window *pWin, const SpinbuttonValue& rSpinbuttonValue )
79 sal_Bool bNativeOK = sal_False;
81 if( pWin->IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) &&
82 // there is just no useful native support for spinfields with dropdown
83 !(pWin->GetStyle() & WB_DROPDOWN) )
85 if( pWin->IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnUpperPart) &&
86 pWin->IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnLowerPart) )
88 // only paint the embedded spin buttons, all buttons are painted at once
89 bNativeOK = pWin->DrawNativeControl( CTRL_SPINBOX, PART_ALL_BUTTONS, Rectangle(), CTRL_STATE_ENABLED,
90 rSpinbuttonValue, OUString() );
92 else
94 // paint the spinbox as a whole, use borderwindow to have proper clipping
95 Window *pBorder = pWin->GetWindow( WINDOW_BORDER );
97 // to not overwrite everything, set the button region as clipregion to the border window
98 Rectangle aClipRect( rSpinbuttonValue.maLowerRect );
99 aClipRect.Union( rSpinbuttonValue.maUpperRect );
101 // convert from screen space to borderwin space
102 aClipRect.SetPos( pBorder->ScreenToOutputPixel(pWin->OutputToScreenPixel(aClipRect.TopLeft())) );
104 Region oldRgn( pBorder->GetClipRegion() );
105 pBorder->SetClipRegion( Region( aClipRect ) );
107 Point aPt;
108 Size aSize( pBorder->GetOutputSizePixel() ); // the size of the border window, i.e., the whole control
109 Rectangle aBound, aContent;
110 Rectangle aNatRgn( aPt, aSize );
111 if( ! ImplGetSVData()->maNWFData.mbCanDrawWidgetAnySize &&
112 pBorder->GetNativeControlRegion( CTRL_SPINBOX, PART_ENTIRE_CONTROL,
113 aNatRgn, 0, rSpinbuttonValue, OUString(), aBound, aContent) )
115 aSize = aContent.GetSize();
118 Rectangle aRgn( aPt, aSize );
119 bNativeOK = pBorder->DrawNativeControl( CTRL_SPINBOX, PART_ENTIRE_CONTROL, aRgn, CTRL_STATE_ENABLED,
120 rSpinbuttonValue, OUString() );
122 pBorder->SetClipRegion(Region(oldRgn));
125 return bNativeOK;
128 sal_Bool ImplDrawNativeSpinbuttons( Window *pWin, const SpinbuttonValue& rSpinbuttonValue )
130 sal_Bool bNativeOK = sal_False;
132 if( pWin->IsNativeControlSupported(CTRL_SPINBUTTONS, PART_ENTIRE_CONTROL) )
134 // only paint the standalone spin buttons, all buttons are painted at once
135 bNativeOK = pWin->DrawNativeControl( CTRL_SPINBUTTONS, PART_ALL_BUTTONS, Rectangle(), CTRL_STATE_ENABLED,
136 rSpinbuttonValue, OUString() );
138 return bNativeOK;
143 void ImplDrawSpinButton( OutputDevice* pOutDev,
144 const Rectangle& rUpperRect,
145 const Rectangle& rLowerRect,
146 sal_Bool bUpperIn, sal_Bool bLowerIn,
147 sal_Bool bUpperEnabled, sal_Bool bLowerEnabled, sal_Bool bHorz, sal_Bool bMirrorHorz )
149 DecorationView aDecoView( pOutDev );
151 sal_uInt16 nStyle = BUTTON_DRAW_NOLEFTLIGHTBORDER;
152 sal_uInt16 nSymStyle = 0;
154 SymbolType eType1, eType2;
156 const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings();
157 if ( rStyleSettings.GetOptions() & STYLE_OPTION_SPINARROW )
159 // arrows are only use in OS/2 look
160 if ( bHorz )
162 eType1 = bMirrorHorz ? SYMBOL_ARROW_RIGHT : SYMBOL_ARROW_LEFT;
163 eType2 = bMirrorHorz ? SYMBOL_ARROW_LEFT : SYMBOL_ARROW_RIGHT;
165 else
167 eType1 = SYMBOL_ARROW_UP;
168 eType2 = SYMBOL_ARROW_DOWN;
171 else
173 if ( bHorz )
175 eType1 = bMirrorHorz ? SYMBOL_SPIN_RIGHT : SYMBOL_SPIN_LEFT;
176 eType2 = bMirrorHorz ? SYMBOL_SPIN_LEFT : SYMBOL_SPIN_RIGHT;
178 else
180 eType1 = SYMBOL_SPIN_UP;
181 eType2 = SYMBOL_SPIN_DOWN;
185 // draw upper/left Button
186 sal_uInt16 nTempStyle = nStyle;
187 if ( bUpperIn )
188 nTempStyle |= BUTTON_DRAW_PRESSED;
190 sal_Bool bNativeOK = sal_False;
191 Rectangle aUpRect;
193 if( pOutDev->GetOutDevType() == OUTDEV_WINDOW )
195 Window *pWin = (Window*) pOutDev;
197 // are we drawing standalone spin buttons or members of a spinfield ?
198 ControlType aControl = CTRL_SPINBUTTONS;
199 switch( pWin->GetType() )
201 case WINDOW_EDIT:
202 case WINDOW_MULTILINEEDIT:
203 case WINDOW_PATTERNFIELD:
204 case WINDOW_METRICFIELD:
205 case WINDOW_CURRENCYFIELD:
206 case WINDOW_DATEFIELD:
207 case WINDOW_TIMEFIELD:
208 case WINDOW_LONGCURRENCYFIELD:
209 case WINDOW_NUMERICFIELD:
210 case WINDOW_SPINFIELD:
211 aControl = CTRL_SPINBOX;
212 break;
213 default:
214 aControl = CTRL_SPINBUTTONS;
215 break;
218 SpinbuttonValue aValue;
219 ImplGetSpinbuttonValue( pWin, rUpperRect, rLowerRect,
220 bUpperIn, bLowerIn, bUpperEnabled, bLowerEnabled,
221 bHorz, aValue );
223 if( aControl == CTRL_SPINBOX )
224 bNativeOK = ImplDrawNativeSpinfield( pWin, aValue );
225 else if( aControl == CTRL_SPINBUTTONS )
226 bNativeOK = ImplDrawNativeSpinbuttons( pWin, aValue );
229 if( !bNativeOK )
230 aUpRect = aDecoView.DrawButton( rUpperRect, nTempStyle );
232 // draw lower/right Button
233 if ( bLowerIn )
234 nStyle |= BUTTON_DRAW_PRESSED;
235 Rectangle aLowRect;
236 if( !bNativeOK )
237 aLowRect = aDecoView.DrawButton( rLowerRect, nStyle );
239 // make use of additional default edge
240 aUpRect.Left()--;
241 aUpRect.Top()--;
242 aUpRect.Right()++;
243 aUpRect.Bottom()++;
244 aLowRect.Left()--;
245 aLowRect.Top()--;
246 aLowRect.Right()++;
247 aLowRect.Bottom()++;
249 // draw into the edge, so that something is visible if the rectangle is too small
250 if ( aUpRect.GetHeight() < 4 )
252 aUpRect.Right()++;
253 aUpRect.Bottom()++;
254 aLowRect.Right()++;
255 aLowRect.Bottom()++;
258 // calculate Symbol size
259 long nTempSize1 = aUpRect.GetWidth();
260 long nTempSize2 = aLowRect.GetWidth();
261 if ( std::abs( nTempSize1-nTempSize2 ) == 1 )
263 if ( nTempSize1 > nTempSize2 )
264 aUpRect.Left()++;
265 else
266 aLowRect.Left()++;
268 nTempSize1 = aUpRect.GetHeight();
269 nTempSize2 = aLowRect.GetHeight();
270 if ( std::abs( nTempSize1-nTempSize2 ) == 1 )
272 if ( nTempSize1 > nTempSize2 )
273 aUpRect.Top()++;
274 else
275 aLowRect.Top()++;
278 nTempStyle = nSymStyle;
279 if ( !bUpperEnabled )
280 nTempStyle |= SYMBOL_DRAW_DISABLE;
281 if( !bNativeOK )
282 aDecoView.DrawSymbol( aUpRect, eType1, rStyleSettings.GetButtonTextColor(), nTempStyle );
284 if ( !bLowerEnabled )
285 nSymStyle |= SYMBOL_DRAW_DISABLE;
286 if( !bNativeOK )
287 aDecoView.DrawSymbol( aLowRect, eType2, rStyleSettings.GetButtonTextColor(), nSymStyle );
290 // =======================================================================
292 void SpinField::ImplInitSpinFieldData()
294 mpEdit = NULL;
295 mbSpin = sal_False;
296 mbRepeat = sal_False;
297 mbUpperIn = sal_False;
298 mbLowerIn = sal_False;
299 mbInitialUp = sal_False;
300 mbInitialDown = sal_False;
301 mbNoSelect = sal_False;
302 mbInDropDown = sal_False;
305 // --------------------------------------------------------------------
307 void SpinField::ImplInit( Window* pParent, WinBits nWinStyle )
309 Edit::ImplInit( pParent, nWinStyle );
311 if ( nWinStyle & (WB_SPIN|WB_DROPDOWN) )
313 mbSpin = sal_True;
315 // Some themes want external spin buttons, therefore the main
316 // spinfield should not overdraw the border between its encapsulated
317 // edit field and the spin buttons
318 if ( (nWinStyle & WB_SPIN) && ImplUseNativeBorder( nWinStyle ) )
320 SetBackground();
321 mpEdit = new Edit( this, WB_NOBORDER );
322 mpEdit->SetBackground();
324 else
325 mpEdit = new Edit( this, WB_NOBORDER );
327 mpEdit->EnableRTL( sal_False );
328 mpEdit->SetPosPixel( Point() );
329 mpEdit->Show();
330 SetSubEdit( mpEdit );
332 maRepeatTimer.SetTimeoutHdl( LINK( this, SpinField, ImplTimeout ) );
333 maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
334 if ( nWinStyle & WB_REPEAT )
335 mbRepeat = sal_True;
337 SetCompoundControl( sal_True );
341 // --------------------------------------------------------------------
343 SpinField::SpinField( WindowType nTyp ) :
344 Edit( nTyp )
346 ImplInitSpinFieldData();
349 // --------------------------------------------------------------------
351 SpinField::SpinField( Window* pParent, WinBits nWinStyle ) :
352 Edit( WINDOW_SPINFIELD )
354 ImplInitSpinFieldData();
355 ImplInit( pParent, nWinStyle );
358 SpinField::SpinField( Window* pParent, const ResId& rResId ) :
359 Edit( WINDOW_SPINFIELD )
361 ImplInitSpinFieldData();
362 rResId.SetRT( RSC_SPINFIELD );
363 WinBits nStyle = ImplInitRes( rResId );
364 ImplInit( pParent, nStyle );
365 ImplLoadRes( rResId );
367 if ( !(nStyle & WB_HIDE) )
368 Show();
371 // --------------------------------------------------------------------
373 SpinField::~SpinField()
375 delete mpEdit;
378 // --------------------------------------------------------------------
380 void SpinField::Up()
382 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_UP, maUpHdlLink, this );
385 // --------------------------------------------------------------------
387 void SpinField::Down()
389 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_DOWN, maDownHdlLink, this );
392 // --------------------------------------------------------------------
394 void SpinField::First()
396 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_FIRST, maFirstHdlLink, this );
399 // --------------------------------------------------------------------
401 void SpinField::Last()
403 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_LAST, maLastHdlLink, this );
406 // --------------------------------------------------------------------
408 void SpinField::MouseButtonDown( const MouseEvent& rMEvt )
410 if ( !HasFocus() && ( !mpEdit || !mpEdit->HasFocus() ) )
412 mbNoSelect = sal_True;
413 GrabFocus();
416 if ( !IsReadOnly() )
418 if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) )
420 mbUpperIn = sal_True;
421 mbInitialUp = sal_True;
422 Invalidate( maUpperRect );
424 else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) )
426 mbLowerIn = sal_True;
427 mbInitialDown = sal_True;
428 Invalidate( maLowerRect );
430 else if ( maDropDownRect.IsInside( rMEvt.GetPosPixel() ) )
432 // put DropDownButton to the right
433 mbInDropDown = ShowDropDown( mbInDropDown ? sal_False : sal_True );
434 Paint( Rectangle( Point(), GetOutputSizePixel() ) );
437 if ( mbUpperIn || mbLowerIn )
439 Update();
440 CaptureMouse();
441 if ( mbRepeat )
442 maRepeatTimer.Start();
443 return;
447 Edit::MouseButtonDown( rMEvt );
450 // --------------------------------------------------------------------
452 void SpinField::MouseButtonUp( const MouseEvent& rMEvt )
454 ReleaseMouse();
455 mbInitialUp = mbInitialDown = sal_False;
456 maRepeatTimer.Stop();
457 maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
459 if ( mbUpperIn )
461 mbUpperIn = sal_False;
462 Invalidate( maUpperRect );
463 Update();
464 Up();
466 else if ( mbLowerIn )
468 mbLowerIn = sal_False;
469 Invalidate( maLowerRect );
470 Update();
471 Down();
474 Edit::MouseButtonUp( rMEvt );
477 // --------------------------------------------------------------------
479 void SpinField::MouseMove( const MouseEvent& rMEvt )
481 if ( rMEvt.IsLeft() )
483 if ( mbInitialUp )
485 sal_Bool bNewUpperIn = maUpperRect.IsInside( rMEvt.GetPosPixel() );
486 if ( bNewUpperIn != mbUpperIn )
488 if ( bNewUpperIn )
490 if ( mbRepeat )
491 maRepeatTimer.Start();
493 else
494 maRepeatTimer.Stop();
496 mbUpperIn = bNewUpperIn;
497 Invalidate( maUpperRect );
498 Update();
501 else if ( mbInitialDown )
503 sal_Bool bNewLowerIn = maLowerRect.IsInside( rMEvt.GetPosPixel() );
504 if ( bNewLowerIn != mbLowerIn )
506 if ( bNewLowerIn )
508 if ( mbRepeat )
509 maRepeatTimer.Start();
511 else
512 maRepeatTimer.Stop();
514 mbLowerIn = bNewLowerIn;
515 Invalidate( maLowerRect );
516 Update();
521 Edit::MouseMove( rMEvt );
524 // --------------------------------------------------------------------
526 long SpinField::Notify( NotifyEvent& rNEvt )
528 long nDone = 0;
529 if( rNEvt.GetType() == EVENT_KEYINPUT )
531 const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
532 if ( !IsReadOnly() )
534 sal_uInt16 nMod = rKEvt.GetKeyCode().GetModifier();
535 switch ( rKEvt.GetKeyCode().GetCode() )
537 case KEY_UP:
539 if ( !nMod )
541 Up();
542 nDone = 1;
545 break;
546 case KEY_DOWN:
548 if ( !nMod )
550 Down();
551 nDone = 1;
553 else if ( ( nMod == KEY_MOD2 ) && !mbInDropDown && ( GetStyle() & WB_DROPDOWN ) )
555 mbInDropDown = ShowDropDown( sal_True );
556 Paint( Rectangle( Point(), GetOutputSizePixel() ) );
557 nDone = 1;
560 break;
561 case KEY_PAGEUP:
563 if ( !nMod )
565 Last();
566 nDone = 1;
569 break;
570 case KEY_PAGEDOWN:
572 if ( !nMod )
574 First();
575 nDone = 1;
578 break;
583 if ( rNEvt.GetType() == EVENT_COMMAND )
585 if ( ( rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL ) && !IsReadOnly() )
587 sal_uInt16 nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
588 if ( ( nWheelBehavior == MOUSE_WHEEL_ALWAYS )
589 || ( ( nWheelBehavior == MOUSE_WHEEL_FOCUS_ONLY )
590 && HasChildPathFocus()
594 const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
595 if ( pData->GetMode() == COMMAND_WHEEL_SCROLL )
597 if ( pData->GetDelta() < 0L )
598 Down();
599 else
600 Up();
601 nDone = 1;
604 else
605 nDone = 0; // don't eat this event, let the default handling happen (i.e. scroll the context)
609 return nDone ? nDone : Edit::Notify( rNEvt );
612 // --------------------------------------------------------------------
614 void SpinField::Command( const CommandEvent& rCEvt )
616 Edit::Command( rCEvt );
619 // --------------------------------------------------------------------
621 void SpinField::FillLayoutData() const
623 if( mbSpin )
625 mpControlData->mpLayoutData = new vcl::ControlLayoutData();
626 AppendLayoutData( *GetSubEdit() );
627 GetSubEdit()->SetLayoutDataParent( this );
629 else
630 Edit::FillLayoutData();
633 // --------------------------------------------------------------------
635 void SpinField::Paint( const Rectangle& rRect )
637 if ( mbSpin )
639 sal_Bool bEnable = IsEnabled();
640 ImplDrawSpinButton( this, maUpperRect, maLowerRect,
641 mbUpperIn, mbLowerIn, bEnable, bEnable );
644 if ( GetStyle() & WB_DROPDOWN )
646 DecorationView aView( this );
648 sal_uInt16 nStyle = BUTTON_DRAW_NOLIGHTBORDER;
649 if ( mbInDropDown )
650 nStyle |= BUTTON_DRAW_PRESSED;
651 Rectangle aInnerRect = aView.DrawButton( maDropDownRect, nStyle );
653 SymbolType eSymbol = SYMBOL_SPIN_DOWN;
654 if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
655 eSymbol = SYMBOL_SPIN_UPDOWN;
657 nStyle = IsEnabled() ? 0 : SYMBOL_DRAW_DISABLE;
658 aView.DrawSymbol( aInnerRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle );
661 Edit::Paint( rRect );
664 // --------------------------------------------------------------------
666 void SpinField::ImplCalcButtonAreas( OutputDevice* pDev, const Size& rOutSz, Rectangle& rDDArea, Rectangle& rSpinUpArea, Rectangle& rSpinDownArea )
668 const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings();
670 Size aSize = rOutSz;
671 Size aDropDownSize;
673 if ( GetStyle() & WB_DROPDOWN )
675 long nW = rStyleSettings.GetScrollBarSize();
676 nW = GetDrawPixel( pDev, nW );
677 aDropDownSize = Size( CalcZoom( nW ), aSize.Height() );
678 aSize.Width() -= aDropDownSize.Width();
679 rDDArea = Rectangle( Point( aSize.Width(), 0 ), aDropDownSize );
680 rDDArea.Top()--;
682 else
683 rDDArea.SetEmpty();
685 // calcuate sizes according to the height
686 if ( GetStyle() & WB_SPIN )
688 long nBottom1 = aSize.Height()/2;
689 long nBottom2 = aSize.Height()-1;
690 long nTop2 = nBottom1;
691 long nTop1 = 0;
692 if ( !(aSize.Height() & 0x01) )
693 nBottom1--;
695 sal_Bool bNativeRegionOK = sal_False;
696 Rectangle aContentUp, aContentDown;
698 if ( (pDev->GetOutDevType() == OUTDEV_WINDOW) &&
699 // there is just no useful native support for spinfields with dropdown
700 ! (GetStyle() & WB_DROPDOWN) &&
701 IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) )
703 Window *pWin = (Window*) pDev;
704 Window *pBorder = pWin->GetWindow( WINDOW_BORDER );
706 // get the system's spin button size
707 ImplControlValue aControlValue;
708 Rectangle aBound;
709 Point aPoint;
711 // use the full extent of the control
712 Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
714 bNativeRegionOK =
715 pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_UP,
716 aArea, 0, aControlValue, OUString(), aBound, aContentUp) &&
717 pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_DOWN,
718 aArea, 0, aControlValue, OUString(), aBound, aContentDown);
720 if( bNativeRegionOK )
722 // convert back from border space to local coordinates
723 aPoint = pBorder->ScreenToOutputPixel( pWin->OutputToScreenPixel( aPoint ) );
724 aContentUp.Move(-aPoint.X(), -aPoint.Y());
725 aContentDown.Move(-aPoint.X(), -aPoint.Y());
729 if( bNativeRegionOK )
731 rSpinUpArea = aContentUp;
732 rSpinDownArea = aContentDown;
734 else
736 aSize.Width() -= CalcZoom( GetDrawPixel( pDev, rStyleSettings.GetSpinSize() ) );
738 rSpinUpArea = Rectangle( aSize.Width(), nTop1, rOutSz.Width()-aDropDownSize.Width()-1, nBottom1 );
739 rSpinDownArea = Rectangle( rSpinUpArea.Left(), nTop2, rSpinUpArea.Right(), nBottom2 );
742 else
744 rSpinUpArea.SetEmpty();
745 rSpinDownArea.SetEmpty();
749 // --------------------------------------------------------------------
751 void SpinField::Resize()
753 if ( mbSpin )
755 Control::Resize();
756 Size aSize = GetOutputSizePixel();
757 bool bSubEditPositioned = false;
759 if ( GetStyle() & (WB_SPIN|WB_DROPDOWN) )
761 ImplCalcButtonAreas( this, aSize, maDropDownRect, maUpperRect, maLowerRect );
763 ImplControlValue aControlValue;
764 Point aPoint;
765 Rectangle aContent, aBound;
767 // use the full extent of the control
768 Window *pBorder = GetWindow( WINDOW_BORDER );
769 Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
771 // adjust position and size of the edit field
772 if ( GetNativeControlRegion(CTRL_SPINBOX, PART_SUB_EDIT,
773 aArea, 0, aControlValue, OUString(), aBound, aContent) )
775 // convert back from border space to local coordinates
776 aPoint = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aPoint ) );
777 aContent.Move(-aPoint.X(), -aPoint.Y());
779 // use the themes drop down size
780 mpEdit->SetPosPixel( aContent.TopLeft() );
781 bSubEditPositioned = true;
782 aSize = aContent.GetSize();
784 else
786 if ( maUpperRect.IsEmpty() )
788 DBG_ASSERT( !maDropDownRect.IsEmpty(), "SpinField::Resize: SPIN && DROPDOWN, but all empty rects?" );
789 aSize.Width() = maDropDownRect.Left();
791 else
792 aSize.Width() = maUpperRect.Left();
796 if( ! bSubEditPositioned )
798 // this moves our sub edit if RTL gets switched
799 mpEdit->SetPosPixel( Point() );
801 mpEdit->SetSizePixel( aSize );
803 if ( GetStyle() & WB_SPIN )
804 Invalidate( Rectangle( maUpperRect.TopLeft(), maLowerRect.BottomRight() ) );
805 if ( GetStyle() & WB_DROPDOWN )
806 Invalidate( maDropDownRect );
810 // -----------------------------------------------------------------------
812 void SpinField::StateChanged( StateChangedType nType )
814 Edit::StateChanged( nType );
816 if ( nType == STATE_CHANGE_ENABLE )
818 if ( mbSpin || ( GetStyle() & WB_DROPDOWN ) )
820 mpEdit->Enable( IsEnabled() );
822 if ( mbSpin )
824 Invalidate( maLowerRect );
825 Invalidate( maUpperRect );
827 if ( GetStyle() & WB_DROPDOWN )
828 Invalidate( maDropDownRect );
831 else if ( nType == STATE_CHANGE_STYLE )
833 if ( GetStyle() & WB_REPEAT )
834 mbRepeat = sal_True;
835 else
836 mbRepeat = sal_False;
838 else if ( nType == STATE_CHANGE_ZOOM )
840 Resize();
841 if ( mpEdit )
842 mpEdit->SetZoom( GetZoom() );
843 Invalidate();
845 else if ( nType == STATE_CHANGE_CONTROLFONT )
847 if ( mpEdit )
848 mpEdit->SetControlFont( GetControlFont() );
849 ImplInitSettings( sal_True, sal_False, sal_False );
850 Invalidate();
852 else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
854 if ( mpEdit )
855 mpEdit->SetControlForeground( GetControlForeground() );
856 ImplInitSettings( sal_False, sal_True, sal_False );
857 Invalidate();
859 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
861 if ( mpEdit )
862 mpEdit->SetControlBackground( GetControlBackground() );
863 ImplInitSettings( sal_False, sal_False, sal_True );
864 Invalidate();
866 else if( nType == STATE_CHANGE_MIRRORING )
868 if( mpEdit )
869 mpEdit->StateChanged( STATE_CHANGE_MIRRORING );
870 Resize();
874 // -----------------------------------------------------------------------
876 void SpinField::DataChanged( const DataChangedEvent& rDCEvt )
878 Edit::DataChanged( rDCEvt );
880 if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
881 (rDCEvt.GetFlags() & SETTINGS_STYLE) )
883 Resize();
884 Invalidate();
888 // -----------------------------------------------------------------------
890 Rectangle* SpinField::ImplFindPartRect( const Point& rPt )
892 if( maUpperRect.IsInside( rPt ) )
893 return &maUpperRect;
894 else if( maLowerRect.IsInside( rPt ) )
895 return &maLowerRect;
896 else
897 return NULL;
900 long SpinField::PreNotify( NotifyEvent& rNEvt )
902 long nDone = 0;
903 const MouseEvent* pMouseEvt = NULL;
905 if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
907 if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
909 // trigger redraw if mouse over state has changed
910 if( IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) ||
911 IsNativeControlSupported(CTRL_SPINBOX, PART_ALL_BUTTONS) )
913 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
914 Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
915 if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
917 // FIXME: this is currently only on aqua
918 // check for other platforms that need similar handling
919 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
920 IsNativeWidgetEnabled() &&
921 IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
923 ImplInvalidateOutermostBorder( this );
925 else
927 // paint directly
928 Region aRgn( GetActiveClipRegion() );
929 if( pLastRect )
931 SetClipRegion(Region(*pLastRect));
932 Paint( *pLastRect );
933 SetClipRegion( aRgn );
935 if( pRect )
937 SetClipRegion(Region(*pRect));
938 Paint( *pRect );
939 SetClipRegion( aRgn );
947 return nDone ? nDone : Edit::PreNotify(rNEvt);
950 // -----------------------------------------------------------------------
952 void SpinField::EndDropDown()
954 mbInDropDown = sal_False;
955 Paint( Rectangle( Point(), GetOutputSizePixel() ) );
958 // -----------------------------------------------------------------------
960 sal_Bool SpinField::ShowDropDown( sal_Bool )
962 return sal_False;
965 Size SpinField::CalcMinimumSizeForText(const OUString &rString) const
967 Size aSz = Edit::CalcMinimumSizeForText(rString);
969 if ( GetStyle() & WB_DROPDOWN )
970 aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
971 if ( GetStyle() & WB_SPIN )
973 ImplControlValue aControlValue;
974 Rectangle aArea( Point(), Size(100, aSz.Height()));
975 Rectangle aEntireBound, aEntireContent, aEditBound, aEditContent;
976 if (
977 GetNativeControlRegion(CTRL_SPINBOX, PART_ENTIRE_CONTROL,
978 aArea, 0, aControlValue, OUString(), aEntireBound, aEntireContent) &&
979 GetNativeControlRegion(CTRL_SPINBOX, PART_SUB_EDIT,
980 aArea, 0, aControlValue, OUString(), aEditBound, aEditContent)
983 aSz.Width() += (aEntireContent.GetWidth() - aEditContent.GetWidth());
985 else
987 aSz.Width() += maUpperRect.GetWidth();
991 return aSz;
994 Size SpinField::CalcMinimumSize() const
996 return CalcMinimumSizeForText(GetText());
999 // -----------------------------------------------------------------------
1001 Size SpinField::GetOptimalSize() const
1003 return CalcMinimumSize();
1006 // -----------------------------------------------------------------------
1008 Size SpinField::CalcSize( sal_uInt16 nChars ) const
1010 Size aSz = Edit::CalcSize( nChars );
1012 if ( GetStyle() & WB_DROPDOWN )
1013 aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
1014 if ( GetStyle() & WB_SPIN )
1015 aSz.Width() += GetSettings().GetStyleSettings().GetSpinSize();
1017 return aSz;
1020 // --------------------------------------------------------------------
1022 IMPL_LINK( SpinField, ImplTimeout, Timer*, pTimer )
1024 if ( pTimer->GetTimeout() == GetSettings().GetMouseSettings().GetButtonStartRepeat() )
1026 pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
1027 pTimer->Start();
1029 else
1031 if ( mbInitialUp )
1032 Up();
1033 else
1034 Down();
1036 return 0;
1039 // -----------------------------------------------------------------------
1041 void SpinField::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags )
1043 Edit::Draw( pDev, rPos, rSize, nFlags );
1045 WinBits nFieldStyle = GetStyle();
1046 if ( !(nFlags & WINDOW_DRAW_NOCONTROLS ) && ( nFieldStyle & (WB_SPIN|WB_DROPDOWN) ) )
1048 Point aPos = pDev->LogicToPixel( rPos );
1049 Size aSize = pDev->LogicToPixel( rSize );
1050 OutDevType eOutDevType = pDev->GetOutDevType();
1051 AllSettings aOldSettings = pDev->GetSettings();
1053 pDev->Push();
1054 pDev->SetMapMode();
1056 if ( eOutDevType == OUTDEV_PRINTER )
1058 StyleSettings aStyleSettings = aOldSettings.GetStyleSettings();
1059 aStyleSettings.SetFaceColor( COL_LIGHTGRAY );
1060 aStyleSettings.SetButtonTextColor( COL_BLACK );
1061 AllSettings aSettings( aOldSettings );
1062 aSettings.SetStyleSettings( aStyleSettings );
1063 pDev->SetSettings( aSettings );
1066 Rectangle aDD, aUp, aDown;
1067 ImplCalcButtonAreas( pDev, aSize, aDD, aUp, aDown );
1068 aDD.Move( aPos.X(), aPos.Y() );
1069 aUp.Move( aPos.X(), aPos.Y() );
1070 aUp.Top()++;
1071 aDown.Move( aPos.X(), aPos.Y() );
1073 Color aButtonTextColor;
1074 if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
1075 aButtonTextColor = Color( COL_BLACK );
1076 else
1077 aButtonTextColor = GetSettings().GetStyleSettings().GetButtonTextColor();
1079 if ( GetStyle() & WB_DROPDOWN )
1081 DecorationView aView( pDev );
1082 sal_uInt16 nStyle = BUTTON_DRAW_NOLIGHTBORDER;
1083 Rectangle aInnerRect = aView.DrawButton( aDD, nStyle );
1084 SymbolType eSymbol = SYMBOL_SPIN_DOWN;
1085 if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
1086 eSymbol = SYMBOL_SPIN_UPDOWN;
1088 nStyle = ( IsEnabled() || ( nFlags & WINDOW_DRAW_NODISABLE ) ) ? 0 : SYMBOL_DRAW_DISABLE;
1089 aView.DrawSymbol( aInnerRect, eSymbol, aButtonTextColor, nStyle );
1092 if ( GetStyle() & WB_SPIN )
1094 ImplDrawSpinButton( pDev, aUp, aDown, sal_False, sal_False, sal_True, sal_True );
1097 pDev->Pop();
1098 pDev->SetSettings( aOldSettings );
1102 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */