diff options
Diffstat (limited to 'vcl/source/control/spinfld.cxx')
-rw-r--r-- | vcl/source/control/spinfld.cxx | 1091 |
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 ); + } +} |