summaryrefslogtreecommitdiff
path: root/vcl/source/control/spinfld.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/control/spinfld.cxx')
-rw-r--r--vcl/source/control/spinfld.cxx1091
1 files changed, 1091 insertions, 0 deletions
diff --git a/vcl/source/control/spinfld.cxx b/vcl/source/control/spinfld.cxx
new file mode 100644
index 000000000000..754270e9012f
--- /dev/null
+++ b/vcl/source/control/spinfld.cxx
@@ -0,0 +1,1091 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "tools/rc.h"
+#include "vcl/event.hxx"
+#include "vcl/decoview.hxx"
+#include "vcl/spin.h"
+#include "vcl/spinfld.hxx"
+#include "vcl/controldata.hxx"
+#include "vcl/svdata.hxx"
+
+// =======================================================================
+
+void ImplGetSpinbuttonValue( Window *pWin, const Rectangle& rUpperRect,
+ const Rectangle& rLowerRect,
+ BOOL bUpperIn, BOOL bLowerIn,
+ BOOL bUpperEnabled, BOOL bLowerEnabled, BOOL bHorz,
+ SpinbuttonValue& rValue )
+{
+ // convert spinbutton data to a SpinbuttonValue structure for native painting
+
+ rValue.maUpperRect = rUpperRect;
+ rValue.maLowerRect = rLowerRect;
+
+ Point aPointerPos = pWin->GetPointerPosPixel();
+
+ ControlState nState = CTRL_STATE_ENABLED;
+ if ( bUpperIn )
+ nState |= CTRL_STATE_PRESSED;
+ if ( !pWin->IsEnabled() || !bUpperEnabled )
+ nState &= ~CTRL_STATE_ENABLED;
+ if ( pWin->HasFocus() )
+ nState |= CTRL_STATE_FOCUSED;
+ if( pWin->IsMouseOver() && rUpperRect.IsInside( aPointerPos ) )
+ nState |= CTRL_STATE_ROLLOVER;
+ rValue.mnUpperState = nState;
+
+ nState = CTRL_STATE_ENABLED;
+ if ( bLowerIn )
+ nState |= CTRL_STATE_PRESSED;
+ if ( !pWin->IsEnabled() || !bLowerEnabled )
+ nState &= ~CTRL_STATE_ENABLED;
+ if ( pWin->HasFocus() )
+ nState |= CTRL_STATE_FOCUSED;
+ // for overlapping spins: highlight only one
+ if( pWin->IsMouseOver() && rLowerRect.IsInside( aPointerPos ) &&
+ !rUpperRect.IsInside( aPointerPos ) )
+ nState |= CTRL_STATE_ROLLOVER;
+ rValue.mnLowerState = nState;
+
+ rValue.mnUpperPart = bHorz ? PART_BUTTON_LEFT : PART_BUTTON_UP;
+ rValue.mnLowerPart = bHorz ? PART_BUTTON_RIGHT : PART_BUTTON_DOWN;
+}
+
+
+BOOL ImplDrawNativeSpinfield( Window *pWin, const SpinbuttonValue& rSpinbuttonValue )
+{
+ BOOL bNativeOK = FALSE;
+
+ if( pWin->IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) &&
+ // there is just no useful native support for spinfields with dropdown
+ !(pWin->GetStyle() & WB_DROPDOWN) )
+ {
+ if( pWin->IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnUpperPart) &&
+ pWin->IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnLowerPart) )
+ {
+ // only paint the embedded spin buttons, all buttons are painted at once
+ bNativeOK = pWin->DrawNativeControl( CTRL_SPINBOX, PART_ALL_BUTTONS, Rectangle(), CTRL_STATE_ENABLED,
+ rSpinbuttonValue, rtl::OUString() );
+ }
+ else
+ {
+ // paint the spinbox as a whole, use borderwindow to have proper clipping
+ Window *pBorder = pWin->GetWindow( WINDOW_BORDER );
+
+ // to not overwrite everything, set the button region as clipregion to the border window
+ Rectangle aClipRect( rSpinbuttonValue.maLowerRect );
+ aClipRect.Union( rSpinbuttonValue.maUpperRect );
+
+ // convert from screen space to borderwin space
+ aClipRect.SetPos( pBorder->ScreenToOutputPixel(pWin->OutputToScreenPixel(aClipRect.TopLeft())) );
+
+ Region oldRgn( pBorder->GetClipRegion() );
+ pBorder->SetClipRegion( Region( aClipRect ) );
+
+ Point aPt;
+ Size aSize( pBorder->GetOutputSizePixel() ); // the size of the border window, i.e., the whole control
+ Rectangle aBound, aContent;
+ Rectangle aNatRgn( aPt, aSize );
+ if( pBorder->GetNativeControlRegion(CTRL_SPINBOX, PART_ENTIRE_CONTROL,
+ aNatRgn, 0, rSpinbuttonValue, rtl::OUString(), aBound, aContent) )
+ {
+ aSize = aContent.GetSize();
+ }
+
+ Rectangle aRgn( aPt, aSize );
+ bNativeOK = pBorder->DrawNativeControl( CTRL_SPINBOX, PART_ENTIRE_CONTROL, aRgn, CTRL_STATE_ENABLED,
+ rSpinbuttonValue, rtl::OUString() );
+
+ pBorder->SetClipRegion( oldRgn );
+ }
+ }
+ return bNativeOK;
+}
+
+BOOL ImplDrawNativeSpinbuttons( Window *pWin, const SpinbuttonValue& rSpinbuttonValue )
+{
+ BOOL bNativeOK = FALSE;
+
+ if( pWin->IsNativeControlSupported(CTRL_SPINBUTTONS, PART_ENTIRE_CONTROL) )
+ {
+ // only paint the standalone spin buttons, all buttons are painted at once
+ bNativeOK = pWin->DrawNativeControl( CTRL_SPINBUTTONS, PART_ALL_BUTTONS, Rectangle(), CTRL_STATE_ENABLED,
+ rSpinbuttonValue, rtl::OUString() );
+ }
+ return bNativeOK;
+}
+
+void ImplDrawSpinButton( OutputDevice* pOutDev,
+ const Rectangle& rUpperRect,
+ const Rectangle& rLowerRect,
+ BOOL bUpperIn, BOOL bLowerIn,
+ BOOL bUpperEnabled, BOOL bLowerEnabled, BOOL bHorz, BOOL bMirrorHorz )
+{
+ DecorationView aDecoView( pOutDev );
+
+ USHORT nStyle = BUTTON_DRAW_NOLEFTLIGHTBORDER;
+ USHORT nSymStyle = 0;
+
+ SymbolType eType1, eType2;
+
+ const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings();
+ if ( rStyleSettings.GetOptions() & STYLE_OPTION_SPINARROW )
+ {
+ // arrows are only use in OS/2 look
+ if ( bHorz )
+ {
+ eType1 = bMirrorHorz ? SYMBOL_ARROW_RIGHT : SYMBOL_ARROW_LEFT;
+ eType2 = bMirrorHorz ? SYMBOL_ARROW_LEFT : SYMBOL_ARROW_RIGHT;
+ }
+ else
+ {
+ eType1 = SYMBOL_ARROW_UP;
+ eType2 = SYMBOL_ARROW_DOWN;
+ }
+ }
+ else
+ {
+ if ( bHorz )
+ {
+ eType1 = bMirrorHorz ? SYMBOL_SPIN_RIGHT : SYMBOL_SPIN_LEFT;
+ eType2 = bMirrorHorz ? SYMBOL_SPIN_LEFT : SYMBOL_SPIN_RIGHT;
+ }
+ else
+ {
+ eType1 = SYMBOL_SPIN_UP;
+ eType2 = SYMBOL_SPIN_DOWN;
+ }
+ }
+
+ // Oberen/linken Button malen
+ USHORT nTempStyle = nStyle;
+ if ( bUpperIn )
+ nTempStyle |= BUTTON_DRAW_PRESSED;
+
+ BOOL bNativeOK = FALSE;
+ Rectangle aUpRect;
+
+ if( pOutDev->GetOutDevType() == OUTDEV_WINDOW )
+ {
+ Window *pWin = (Window*) pOutDev;
+
+ // are we drawing standalone spin buttons or members of a spinfield ?
+ ControlType aControl = CTRL_SPINBUTTONS;
+ switch( pWin->GetType() )
+ {
+ case WINDOW_EDIT:
+ case WINDOW_MULTILINEEDIT:
+ case WINDOW_PATTERNFIELD:
+ case WINDOW_METRICFIELD:
+ case WINDOW_CURRENCYFIELD:
+ case WINDOW_DATEFIELD:
+ case WINDOW_TIMEFIELD:
+ case WINDOW_LONGCURRENCYFIELD:
+ case WINDOW_NUMERICFIELD:
+ case WINDOW_SPINFIELD:
+ aControl = CTRL_SPINBOX;
+ break;
+ default:
+ aControl = CTRL_SPINBUTTONS;
+ break;
+ }
+
+ SpinbuttonValue aValue;
+ ImplGetSpinbuttonValue( pWin, rUpperRect, rLowerRect,
+ bUpperIn, bLowerIn, bUpperEnabled, bLowerEnabled,
+ bHorz, aValue );
+
+ if( aControl == CTRL_SPINBOX )
+ bNativeOK = ImplDrawNativeSpinfield( pWin, aValue );
+ else if( aControl == CTRL_SPINBUTTONS )
+ bNativeOK = ImplDrawNativeSpinbuttons( pWin, aValue );
+ }
+
+ if( !bNativeOK )
+ aUpRect = aDecoView.DrawButton( rUpperRect, nTempStyle );
+
+ // Unteren/rechten Button malen
+ if ( bLowerIn )
+ nStyle |= BUTTON_DRAW_PRESSED;
+ Rectangle aLowRect;
+ if( !bNativeOK )
+ aLowRect = aDecoView.DrawButton( rLowerRect, nStyle );
+
+ // Zusaetzliche Default-Kante wollen wir auch ausnutzen
+ aUpRect.Left()--;
+ aUpRect.Top()--;
+ aUpRect.Right()++;
+ aUpRect.Bottom()++;
+ aLowRect.Left()--;
+ aLowRect.Top()--;
+ aLowRect.Right()++;
+ aLowRect.Bottom()++;
+
+ // Wir malen auch in die Kante rein, damit man etwas erkennen kann,
+ // wenn das Rechteck zu klein ist
+ if ( aUpRect.GetHeight() < 4 )
+ {
+ aUpRect.Right()++;
+ aUpRect.Bottom()++;
+ aLowRect.Right()++;
+ aLowRect.Bottom()++;
+ }
+
+ // Symbolgroesse berechnen
+ long nTempSize1 = aUpRect.GetWidth();
+ long nTempSize2 = aLowRect.GetWidth();
+ if ( Abs( nTempSize1-nTempSize2 ) == 1 )
+ {
+ if ( nTempSize1 > nTempSize2 )
+ aUpRect.Left()++;
+ else
+ aLowRect.Left()++;
+ }
+ nTempSize1 = aUpRect.GetHeight();
+ nTempSize2 = aLowRect.GetHeight();
+ if ( Abs( nTempSize1-nTempSize2 ) == 1 )
+ {
+ if ( nTempSize1 > nTempSize2 )
+ aUpRect.Top()++;
+ else
+ aLowRect.Top()++;
+ }
+
+ nTempStyle = nSymStyle;
+ if ( !bUpperEnabled )
+ nTempStyle |= SYMBOL_DRAW_DISABLE;
+ if( !bNativeOK )
+ aDecoView.DrawSymbol( aUpRect, eType1, rStyleSettings.GetButtonTextColor(), nTempStyle );
+
+ if ( !bLowerEnabled )
+ nSymStyle |= SYMBOL_DRAW_DISABLE;
+ if( !bNativeOK )
+ aDecoView.DrawSymbol( aLowRect, eType2, rStyleSettings.GetButtonTextColor(), nSymStyle );
+}
+
+// =======================================================================
+
+void SpinField::ImplInitSpinFieldData()
+{
+ mpEdit = NULL;
+ mbSpin = FALSE;
+ mbRepeat = FALSE;
+ mbUpperIn = FALSE;
+ mbLowerIn = FALSE;
+ mbInitialUp = FALSE;
+ mbInitialDown = FALSE;
+ mbNoSelect = FALSE;
+ mbInDropDown = FALSE;
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::ImplInit( Window* pParent, WinBits nWinStyle )
+{
+ Edit::ImplInit( pParent, nWinStyle );
+
+ if ( nWinStyle & (WB_SPIN|WB_DROPDOWN) )
+ {
+ mbSpin = TRUE;
+
+ // Some themes want external spin buttons, therefore the main
+ // spinfield should not overdraw the border between its encapsulated
+ // edit field and the spin buttons
+ if ( (nWinStyle & WB_SPIN) && ImplUseNativeBorder( nWinStyle ) )
+ {
+ SetBackground();
+ mpEdit = new Edit( this, WB_NOBORDER );
+ mpEdit->SetBackground();
+ }
+ else
+ mpEdit = new Edit( this, WB_NOBORDER );
+
+ mpEdit->EnableRTL( FALSE );
+ mpEdit->SetPosPixel( Point() );
+ mpEdit->Show();
+ SetSubEdit( mpEdit );
+
+ maRepeatTimer.SetTimeoutHdl( LINK( this, SpinField, ImplTimeout ) );
+ maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
+ if ( nWinStyle & WB_REPEAT )
+ mbRepeat = TRUE;
+
+ SetCompoundControl( TRUE );
+ }
+}
+
+// --------------------------------------------------------------------
+
+SpinField::SpinField( WindowType nTyp ) :
+ Edit( nTyp )
+{
+ ImplInitSpinFieldData();
+}
+
+// --------------------------------------------------------------------
+
+SpinField::SpinField( Window* pParent, WinBits nWinStyle ) :
+ Edit( WINDOW_SPINFIELD )
+{
+ ImplInitSpinFieldData();
+ ImplInit( pParent, nWinStyle );
+}
+
+// --------------------------------------------------------------------
+
+SpinField::SpinField( Window* pParent, const ResId& rResId ) :
+ Edit( WINDOW_SPINFIELD )
+{
+ ImplInitSpinFieldData();
+ rResId.SetRT( RSC_SPINFIELD );
+ WinBits nStyle = ImplInitRes( rResId );
+ ImplInit( pParent, nStyle );
+ ImplLoadRes( rResId );
+
+ if ( !(nStyle & WB_HIDE) )
+ Show();
+}
+
+// --------------------------------------------------------------------
+
+SpinField::~SpinField()
+{
+ delete mpEdit;
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::Up()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_UP, maUpHdlLink, this );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::Down()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_DOWN, maDownHdlLink, this );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::First()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_FIRST, maFirstHdlLink, this );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::Last()
+{
+ ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_LAST, maLastHdlLink, this );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if ( !HasFocus() && ( !mpEdit || !mpEdit->HasFocus() ) )
+ {
+ mbNoSelect = TRUE;
+ GrabFocus();
+ }
+
+ if ( !IsReadOnly() )
+ {
+ if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) )
+ {
+ mbUpperIn = TRUE;
+ mbInitialUp = TRUE;
+ Invalidate( maUpperRect );
+ }
+ else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) )
+ {
+ mbLowerIn = TRUE;
+ mbInitialDown = TRUE;
+ Invalidate( maLowerRect );
+ }
+ else if ( maDropDownRect.IsInside( rMEvt.GetPosPixel() ) )
+ {
+ // Rechts daneben liegt der DropDownButton:
+ mbInDropDown = ShowDropDown( mbInDropDown ? FALSE : TRUE );
+ Paint( Rectangle( Point(), GetOutputSizePixel() ) );
+ }
+
+ if ( mbUpperIn || mbLowerIn )
+ {
+ Update();
+ CaptureMouse();
+ if ( mbRepeat )
+ maRepeatTimer.Start();
+ return;
+ }
+ }
+
+ Edit::MouseButtonDown( rMEvt );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ ReleaseMouse();
+ mbInitialUp = mbInitialDown = FALSE;
+ maRepeatTimer.Stop();
+ maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
+
+ if ( mbUpperIn )
+ {
+ mbUpperIn = FALSE;
+ Invalidate( maUpperRect );
+ Update();
+ Up();
+ }
+ else if ( mbLowerIn )
+ {
+ mbLowerIn = FALSE;
+ Invalidate( maLowerRect );
+ Update();
+ Down();
+ }
+
+ Edit::MouseButtonUp( rMEvt );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::MouseMove( const MouseEvent& rMEvt )
+{
+ if ( rMEvt.IsLeft() )
+ {
+ if ( mbInitialUp )
+ {
+ BOOL bNewUpperIn = maUpperRect.IsInside( rMEvt.GetPosPixel() );
+ if ( bNewUpperIn != mbUpperIn )
+ {
+ if ( bNewUpperIn )
+ {
+ if ( mbRepeat )
+ maRepeatTimer.Start();
+ }
+ else
+ maRepeatTimer.Stop();
+
+ mbUpperIn = bNewUpperIn;
+ Invalidate( maUpperRect );
+ Update();
+ }
+ }
+ else if ( mbInitialDown )
+ {
+ BOOL bNewLowerIn = maLowerRect.IsInside( rMEvt.GetPosPixel() );
+ if ( bNewLowerIn != mbLowerIn )
+ {
+ if ( bNewLowerIn )
+ {
+ if ( mbRepeat )
+ maRepeatTimer.Start();
+ }
+ else
+ maRepeatTimer.Stop();
+
+ mbLowerIn = bNewLowerIn;
+ Invalidate( maLowerRect );
+ Update();
+ }
+ }
+ }
+
+ Edit::MouseMove( rMEvt );
+}
+
+// --------------------------------------------------------------------
+
+long SpinField::Notify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ if( rNEvt.GetType() == EVENT_KEYINPUT )
+ {
+ const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
+ if ( !IsReadOnly() )
+ {
+ USHORT nMod = rKEvt.GetKeyCode().GetModifier();
+ switch ( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_UP:
+ {
+ if ( !nMod )
+ {
+ Up();
+ nDone = 1;
+ }
+ }
+ break;
+ case KEY_DOWN:
+ {
+ if ( !nMod )
+ {
+ Down();
+ nDone = 1;
+ }
+ else if ( ( nMod == KEY_MOD2 ) && !mbInDropDown && ( GetStyle() & WB_DROPDOWN ) )
+ {
+ mbInDropDown = ShowDropDown( TRUE );
+ Paint( Rectangle( Point(), GetOutputSizePixel() ) );
+ nDone = 1;
+ }
+ }
+ break;
+ case KEY_PAGEUP:
+ {
+ if ( !nMod )
+ {
+ Last();
+ nDone = 1;
+ }
+ }
+ break;
+ case KEY_PAGEDOWN:
+ {
+ if ( !nMod )
+ {
+ First();
+ nDone = 1;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if ( rNEvt.GetType() == EVENT_COMMAND )
+ {
+ if ( ( rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL ) && !IsReadOnly() )
+ {
+ USHORT nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() );
+ if ( ( nWheelBehavior == MOUSE_WHEEL_ALWAYS )
+ || ( ( nWheelBehavior == MOUSE_WHEEL_FOCUS_ONLY )
+ && HasChildPathFocus()
+ )
+ )
+ {
+ const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
+ if ( pData->GetMode() == COMMAND_WHEEL_SCROLL )
+ {
+ if ( pData->GetDelta() < 0L )
+ Down();
+ else
+ Up();
+ nDone = 1;
+ }
+ }
+ else
+ nDone = 0; // don't eat this event, let the default handling happen (i.e. scroll the context)
+ }
+ }
+
+ return nDone ? nDone : Edit::Notify( rNEvt );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::Command( const CommandEvent& rCEvt )
+{
+ Edit::Command( rCEvt );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::FillLayoutData() const
+{
+ if( mbSpin )
+ {
+ mpControlData->mpLayoutData = new vcl::ControlLayoutData();
+ AppendLayoutData( *GetSubEdit() );
+ GetSubEdit()->SetLayoutDataParent( this );
+ }
+ else
+ Edit::FillLayoutData();
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::Paint( const Rectangle& rRect )
+{
+ if ( mbSpin )
+ {
+ BOOL bEnable = IsEnabled();
+ ImplDrawSpinButton( this, maUpperRect, maLowerRect,
+ mbUpperIn, mbLowerIn, bEnable, bEnable );
+ }
+
+ if ( GetStyle() & WB_DROPDOWN )
+ {
+ DecorationView aView( this );
+
+ USHORT nStyle = BUTTON_DRAW_NOLIGHTBORDER;
+ if ( mbInDropDown )
+ nStyle |= BUTTON_DRAW_PRESSED;
+ Rectangle aInnerRect = aView.DrawButton( maDropDownRect, nStyle );
+
+ SymbolType eSymbol = SYMBOL_SPIN_DOWN;
+ if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
+ eSymbol = SYMBOL_SPIN_UPDOWN;
+
+ nStyle = IsEnabled() ? 0 : SYMBOL_DRAW_DISABLE;
+ aView.DrawSymbol( aInnerRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle );
+ }
+
+ Edit::Paint( rRect );
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::ImplCalcButtonAreas( OutputDevice* pDev, const Size& rOutSz, Rectangle& rDDArea, Rectangle& rSpinUpArea, Rectangle& rSpinDownArea )
+{
+ const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings();
+
+ Size aSize = rOutSz;
+ Size aDropDownSize;
+
+ if ( GetStyle() & WB_DROPDOWN )
+ {
+ long nW = rStyleSettings.GetScrollBarSize();
+ nW = GetDrawPixel( pDev, nW );
+ aDropDownSize = Size( CalcZoom( nW ), aSize.Height() );
+ aSize.Width() -= aDropDownSize.Width();
+ rDDArea = Rectangle( Point( aSize.Width(), 0 ), aDropDownSize );
+ rDDArea.Top()--;
+ }
+ else
+ rDDArea.SetEmpty();
+
+ // Je nach Hoehe, die groessen Berechnen
+ if ( GetStyle() & WB_SPIN )
+ {
+ long nBottom1 = aSize.Height()/2;
+ long nBottom2 = aSize.Height()-1;
+ long nTop2 = nBottom1;
+ long nTop1 = 0;
+ if ( !(aSize.Height() & 0x01) )
+ nBottom1--;
+
+ BOOL bNativeRegionOK = FALSE;
+ Rectangle aContentUp, aContentDown;
+
+ if ( (pDev->GetOutDevType() == OUTDEV_WINDOW) &&
+ // there is just no useful native support for spinfields with dropdown
+ ! (GetStyle() & WB_DROPDOWN) &&
+ IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) )
+ {
+ Window *pWin = (Window*) pDev;
+ Window *pBorder = pWin->GetWindow( WINDOW_BORDER );
+
+ // get the system's spin button size
+ ImplControlValue aControlValue;
+ Rectangle aBound;
+ Point aPoint;
+
+ // use the full extent of the control
+ Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
+
+ bNativeRegionOK =
+ pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_UP,
+ aArea, 0, aControlValue, rtl::OUString(), aBound, aContentUp) &&
+ pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_DOWN,
+ aArea, 0, aControlValue, rtl::OUString(), aBound, aContentDown);
+
+ if( bNativeRegionOK )
+ {
+ // convert back from border space to local coordinates
+ aPoint = pBorder->ScreenToOutputPixel( pWin->OutputToScreenPixel( aPoint ) );
+ aContentUp.Move(-aPoint.X(), -aPoint.Y());
+ aContentDown.Move(-aPoint.X(), -aPoint.Y());
+ }
+ }
+
+ if( bNativeRegionOK )
+ {
+ rSpinUpArea = aContentUp;
+ rSpinDownArea = aContentDown;
+ }
+ else
+ {
+ aSize.Width() -= CalcZoom( GetDrawPixel( pDev, rStyleSettings.GetSpinSize() ) );
+
+ rSpinUpArea = Rectangle( aSize.Width(), nTop1, rOutSz.Width()-aDropDownSize.Width()-1, nBottom1 );
+ rSpinDownArea = Rectangle( rSpinUpArea.Left(), nTop2, rSpinUpArea.Right(), nBottom2 );
+ }
+ }
+ else
+ {
+ rSpinUpArea.SetEmpty();
+ rSpinDownArea.SetEmpty();
+ }
+}
+
+// --------------------------------------------------------------------
+
+void SpinField::Resize()
+{
+ if ( mbSpin )
+ {
+ Control::Resize();
+ Size aSize = GetOutputSizePixel();
+ bool bSubEditPositioned = false;
+
+ if ( GetStyle() & (WB_SPIN|WB_DROPDOWN) )
+ {
+ ImplCalcButtonAreas( this, aSize, maDropDownRect, maUpperRect, maLowerRect );
+
+ ImplControlValue aControlValue;
+ Point aPoint;
+ Rectangle aContent, aBound;
+
+ // use the full extent of the control
+ Window *pBorder = GetWindow( WINDOW_BORDER );
+ Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() );
+
+ // adjust position and size of the edit field
+ if ( GetNativeControlRegion(CTRL_SPINBOX, PART_SUB_EDIT,
+ aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) )
+ {
+ // convert back from border space to local coordinates
+ aPoint = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aPoint ) );
+ aContent.Move(-aPoint.X(), -aPoint.Y());
+
+ // use the themes drop down size
+ mpEdit->SetPosPixel( aContent.TopLeft() );
+ bSubEditPositioned = true;
+ aSize = aContent.GetSize();
+ }
+ else
+ {
+ if ( maUpperRect.IsEmpty() )
+ {
+ DBG_ASSERT( !maDropDownRect.IsEmpty(), "SpinField::Resize: SPIN && DROPDOWN, but all empty rects?" );
+ aSize.Width() = maDropDownRect.Left();
+ }
+ else
+ aSize.Width() = maUpperRect.Left();
+ }
+ }
+
+ if( ! bSubEditPositioned )
+ {
+ // this moves our sub edit if RTL gets switched
+ mpEdit->SetPosPixel( Point() );
+ }
+ mpEdit->SetSizePixel( aSize );
+
+ if ( GetStyle() & WB_SPIN )
+ Invalidate( Rectangle( maUpperRect.TopLeft(), maLowerRect.BottomRight() ) );
+ if ( GetStyle() & WB_DROPDOWN )
+ Invalidate( maDropDownRect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SpinField::StateChanged( StateChangedType nType )
+{
+ Edit::StateChanged( nType );
+
+ if ( nType == STATE_CHANGE_ENABLE )
+ {
+ if ( mbSpin || ( GetStyle() & WB_DROPDOWN ) )
+ {
+ mpEdit->Enable( IsEnabled() );
+
+ if ( mbSpin )
+ {
+ Invalidate( maLowerRect );
+ Invalidate( maUpperRect );
+ }
+ if ( GetStyle() & WB_DROPDOWN )
+ Invalidate( maDropDownRect );
+ }
+ }
+ else if ( nType == STATE_CHANGE_STYLE )
+ {
+ if ( GetStyle() & WB_REPEAT )
+ mbRepeat = TRUE;
+ else
+ mbRepeat = FALSE;
+ }
+ else if ( nType == STATE_CHANGE_ZOOM )
+ {
+ Resize();
+ if ( mpEdit )
+ mpEdit->SetZoom( GetZoom() );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFONT )
+ {
+ if ( mpEdit )
+ mpEdit->SetControlFont( GetControlFont() );
+ ImplInitSettings( TRUE, FALSE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
+ {
+ if ( mpEdit )
+ mpEdit->SetControlForeground( GetControlForeground() );
+ ImplInitSettings( FALSE, TRUE, FALSE );
+ Invalidate();
+ }
+ else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
+ {
+ if ( mpEdit )
+ mpEdit->SetControlBackground( GetControlBackground() );
+ ImplInitSettings( FALSE, FALSE, TRUE );
+ Invalidate();
+ }
+ else if( nType == STATE_CHANGE_MIRRORING )
+ {
+ if( mpEdit )
+ mpEdit->StateChanged( STATE_CHANGE_MIRRORING );
+ Resize();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SpinField::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Edit::DataChanged( rDCEvt );
+
+ if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
+ (rDCEvt.GetFlags() & SETTINGS_STYLE) )
+ {
+ Resize();
+ Invalidate();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Rectangle* SpinField::ImplFindPartRect( const Point& rPt )
+{
+ if( maUpperRect.IsInside( rPt ) )
+ return &maUpperRect;
+ else if( maLowerRect.IsInside( rPt ) )
+ return &maLowerRect;
+ else
+ return NULL;
+}
+
+long SpinField::PreNotify( NotifyEvent& rNEvt )
+{
+ long nDone = 0;
+ const MouseEvent* pMouseEvt = NULL;
+
+ if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
+ {
+ if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
+ {
+ // trigger redraw if mouse over state has changed
+ if( IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) ||
+ IsNativeControlSupported(CTRL_SPINBOX, PART_ALL_BUTTONS) )
+ {
+ Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
+ Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
+ if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
+ {
+ // FIXME: this is currently only on aqua
+ // check for other platforms that need similar handling
+ if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
+ IsNativeWidgetEnabled() &&
+ IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
+ {
+ ImplInvalidateOutermostBorder( this );
+ }
+ else
+ {
+ // paint directly
+ Region aRgn( GetActiveClipRegion() );
+ if( pLastRect )
+ {
+ SetClipRegion( *pLastRect );
+ Paint( *pLastRect );
+ SetClipRegion( aRgn );
+ }
+ if( pRect )
+ {
+ SetClipRegion( *pRect );
+ Paint( *pRect );
+ SetClipRegion( aRgn );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return nDone ? nDone : Edit::PreNotify(rNEvt);
+}
+
+// -----------------------------------------------------------------------
+
+void SpinField::EndDropDown()
+{
+ mbInDropDown = FALSE;
+ Paint( Rectangle( Point(), GetOutputSizePixel() ) );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL SpinField::ShowDropDown( BOOL )
+{
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+Size SpinField::CalcMinimumSize() const
+{
+ Size aSz = Edit::CalcMinimumSize();
+
+ if ( GetStyle() & WB_DROPDOWN )
+ aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
+ if ( GetStyle() & WB_SPIN )
+ aSz.Width() += maUpperRect.GetWidth();
+
+ return aSz;
+}
+
+// -----------------------------------------------------------------------
+
+Size SpinField::GetOptimalSize(WindowSizeType eType) const
+{
+ switch (eType) {
+ case WINDOWSIZE_MINIMUM:
+ return CalcMinimumSize();
+ default:
+ return Edit::GetOptimalSize( eType );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+Size SpinField::CalcSize( USHORT nChars ) const
+{
+ Size aSz = Edit::CalcSize( nChars );
+
+ if ( GetStyle() & WB_DROPDOWN )
+ aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize();
+ if ( GetStyle() & WB_SPIN )
+ aSz.Width() += GetSettings().GetStyleSettings().GetSpinSize();
+
+ return aSz;
+}
+
+// --------------------------------------------------------------------
+
+IMPL_LINK( SpinField, ImplTimeout, Timer*, pTimer )
+{
+ if ( pTimer->GetTimeout() == GetSettings().GetMouseSettings().GetButtonStartRepeat() )
+ {
+ pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
+ pTimer->Start();
+ }
+ else
+ {
+ if ( mbInitialUp )
+ Up();
+ else
+ Down();
+ }
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void SpinField::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags )
+{
+ Edit::Draw( pDev, rPos, rSize, nFlags );
+
+ WinBits nFieldStyle = GetStyle();
+ if ( !(nFlags & WINDOW_DRAW_NOCONTROLS ) && ( nFieldStyle & (WB_SPIN|WB_DROPDOWN) ) )
+ {
+ Point aPos = pDev->LogicToPixel( rPos );
+ Size aSize = pDev->LogicToPixel( rSize );
+ OutDevType eOutDevType = pDev->GetOutDevType();
+ AllSettings aOldSettings = pDev->GetSettings();
+
+ pDev->Push();
+ pDev->SetMapMode();
+
+ if ( eOutDevType == OUTDEV_PRINTER )
+ {
+ StyleSettings aStyleSettings = aOldSettings.GetStyleSettings();
+ aStyleSettings.SetFaceColor( COL_LIGHTGRAY );
+ aStyleSettings.SetButtonTextColor( COL_BLACK );
+ AllSettings aSettings( aOldSettings );
+ aSettings.SetStyleSettings( aStyleSettings );
+ pDev->SetSettings( aSettings );
+ }
+
+ Rectangle aDD, aUp, aDown;
+ ImplCalcButtonAreas( pDev, aSize, aDD, aUp, aDown );
+ aDD.Move( aPos.X(), aPos.Y() );
+ aUp.Move( aPos.X(), aPos.Y() );
+ aUp.Top()++;
+ aDown.Move( aPos.X(), aPos.Y() );
+
+ Color aButtonTextColor;
+ if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
+ aButtonTextColor = Color( COL_BLACK );
+ else
+ aButtonTextColor = GetSettings().GetStyleSettings().GetButtonTextColor();
+
+ if ( GetStyle() & WB_DROPDOWN )
+ {
+ DecorationView aView( pDev );
+ USHORT nStyle = BUTTON_DRAW_NOLIGHTBORDER;
+ Rectangle aInnerRect = aView.DrawButton( aDD, nStyle );
+ SymbolType eSymbol = SYMBOL_SPIN_DOWN;
+ if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN )
+ eSymbol = SYMBOL_SPIN_UPDOWN;
+
+ nStyle = ( IsEnabled() || ( nFlags & WINDOW_DRAW_NODISABLE ) ) ? 0 : SYMBOL_DRAW_DISABLE;
+ aView.DrawSymbol( aInnerRect, eSymbol, aButtonTextColor, nStyle );
+ }
+
+ if ( GetStyle() & WB_SPIN )
+ {
+ ImplDrawSpinButton( pDev, aUp, aDown, FALSE, FALSE, TRUE, TRUE );
+ }
+
+ pDev->Pop();
+ pDev->SetSettings( aOldSettings );
+ }
+}