diff -r 57d4cdd99204 -r edfc90759b9f imageeditor/plugins/RedEyePlugin/src/ImageEditorRedEyeReductionControl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imageeditor/plugins/RedEyePlugin/src/ImageEditorRedEyeReductionControl.cpp Fri Jan 29 13:53:17 2010 +0200 @@ -0,0 +1,1530 @@ +/* +* Copyright (c) 2010 Ixonos Plc. +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - Initial contribution +* +* Contributors: +* Ixonos Plc +* +* Description: +* Control class for RedEyeReduction plugin. +* +*/ + + +// INCLUDES +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +#include +#include +#include +#include +#include + +#ifdef RD_TACTILE_FEEDBACK +#include +#endif /* RD_TACTILE_FEEDBACK */ + +#include "ImageEditorUI.hrh" +#include "ImageEditorPluginBase.hrh" +#include "RedEyeReduction.hrh" +#include "DrawUtils.h" +#include "PluginInfo.h" +#include "SystemParameters.h" +#include "ImageEditorUids.hrh" + +#include "ImageEditorRedEyeReductionControl.h" +#include "ImageEditorUIDefs.h" +#include "iepb.h" +#include "definitions.def" + +// DEBUG LOG +#include "imageeditordebugutils.h" +_LIT(KRedEyeReductionPluginLogFile, "RedEyeReductionPlugin.log"); + +// CONSTANTS +const TReal KPosParamMin = 0.0; +const TReal KPosParamMax = 1.0; +const TReal KPosParamStep = 0.01; +const TReal KPosParamDef = 0.5; + +const TReal KRadiusParamMin = 0.0; +const TReal KRadiusParamMax = 0.4; +const TReal KRadiusParamStep = 0.0025; +const TReal KRadiusParamDef = 0.05; + +const TInt KMoveSelectionIndex = 0; +const TInt KResizeSelectionIndex = 1; + +// Default values from CPreviewControlBase not used +const TInt KRedEyeFastKeyTimerDelayInMicroseconds = 500000; +const TInt KRedEyeFastKeyTimerIntervalInMicroseconds = 50000; +const TInt KRedEyeFastKeyTimerMultiplyThresholdInTicks = 9; +const TInt KRedEyeBigNavigationStepMultiplier = 3; + +// Touch constants +const TInt KTouchScaleMaxStepCount = 50; + +// Panic category +_LIT (KComponentName, "ImageEditorRedEyeReduction" ); + +// Resource file name +_LIT (KPgnResourceFile, "redeyereduction.rsc"); + +//============================================================================= +TInt CImageEditorRedEyeReductionControl::DancingAntzCallback (TAny * aPtr) +{ + ((CImageEditorRedEyeReductionControl *)aPtr)->OnDancingAntzCallBack(); + return KErrNone; +} + +//============================================================================= +TInt CImageEditorRedEyeReductionControl::FastKeyCallback (TAny * aPtr) +{ + TRAPD( err, ((CImageEditorRedEyeReductionControl *)aPtr)->OnFastKeyCallBackL() ); + return err; +} + +//============================================================================= +CImageEditorRedEyeReductionControl * CImageEditorRedEyeReductionControl::NewL ( + const TRect & aRect, + CCoeControl * aParent + ) +{ + CImageEditorRedEyeReductionControl * self = new (ELeave) CImageEditorRedEyeReductionControl; + CleanupStack::PushL (self); + self->ConstructL (aRect, aParent); + CleanupStack::Pop (); // self + return self; +} + +//============================================================================= +CImageEditorRedEyeReductionControl::CImageEditorRedEyeReductionControl () : +iState( ERedEyeReductionStateMin ), +iX( KPosParamDef ), +iY( KPosParamDef ), +iR( KRadiusParamDef ), +iHandleEventKeys (ETrue), +iTickCount (0), +iNaviStepMultiplier (KDefaultSmallNavigationStepMultiplier), +iReadyToRender(ETrue), +iDoNotUpdateParameters(EFalse), +iCursorDragEnabled( EFalse ) +{ + +} + +//============================================================================= +CImageEditorRedEyeReductionControl::~CImageEditorRedEyeReductionControl () +{ + delete iCrossHair; + delete iCrossHairMask; + iUndoArray.Close(); + if( iTimer ) + { + iTimer->Cancel(); + } + delete iTimer; + iVisibleImageRectPrev = NULL; + iVisibleImageRect = NULL; + iEditorView = NULL; + iItem = NULL; + + delete iPopupController; + delete iTooltipLocate; + delete iTooltipOutline; + +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::ConstructL ( + const TRect & /*aRect*/, + CCoeControl * aParent + ) +{ + LOG_INIT(KRedEyeReductionPluginLogFile); + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::ConstructL" ); + + // Set parent window + SetContainerWindowL (*aParent); + + // Create timer for fast keys and dancing ants + iTimer = CPeriodic::NewL (CActive::EPriorityStandard); + + // Create CROSSHAIR image + SDrawUtils::GetIndicatorBitmapL( + iCrossHair, + iCrossHairMask, + EMbmImageeditoruiQgn_indi_imed_cursor_super, // cross-hair + EMbmImageeditoruiQgn_indi_imed_cursor_super_mask + ); + + iPopupController = CAknInfoPopupNoteController::NewL(); + + TFileName resourcefile; + resourcefile.Append(KPgnResourcePath); + resourcefile.Append(KPgnResourceFile); + User::LeaveIfError( CompleteWithAppPath( resourcefile ) ); + + // Read tooltip resources + // (RConeResourceLoader selects the language using BaflUtils::NearestLanguageFile) + RConeResourceLoader resLoader ( *CEikonEnv::Static() ); + CleanupClosePushL ( resLoader ); + resLoader.OpenL ( resourcefile ); + + iTooltipLocate = CEikonEnv::Static()->AllocReadResourceL(R_TOOLTIP_REDEYE_LOCATE); + iTooltipOutline = CEikonEnv::Static()->AllocReadResourceL(R_TOOLTIP_REDEYE_OUTLINE); + + CleanupStack::PopAndDestroy(); // resLoader + +#ifdef RD_TACTILE_FEEDBACK + iTouchFeedBack = MTouchFeedback::Instance(); +#endif /* RD_TACTILE_FEEDBACK */ + + // Activate control + ActivateL(); + + EnableDragEvents(); +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::SetView (CAknView * aView) +{ + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::SetView" ); + + iEditorView = aView; +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::SetSelectedUiItemL (CPluginInfo * aItem) +{ + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::SetSelectedUiItemL" ); + + iItem = aItem; +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::PrepareL () +{ + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::PrepareL" ); + +#ifdef __TOUCH_ONLY_DEVICE_RER_PLUGIN_ACTION__ + // The whole crosshair set state is skipped totally in touch-only devices + ToResizeStateL(); +#else + ToMoveStateL(); +#endif + + // Store parameters for the initial filter. + // This is a special case. For the other filters, the parameters + // are stored implicitly when calling + iEditorView->HandleCommandL (EImageEditorStoreParameters); +} + +//============================================================================= +TKeyResponse CImageEditorRedEyeReductionControl::OfferKeyEventL ( + const TKeyEvent & aKeyEvent, + TEventCode aType + ) +{ + TKeyResponse response = EKeyWasNotConsumed; + + // If busy, do not handle anything + if ( Busy() ) + { + response = EKeyWasConsumed; + } + + // EEventKey + else if (EEventKey == aType && iHandleEventKeys) + { + + switch (aKeyEvent.iCode) + { + + case EKeyDownArrow: + { + // Adjust crop point + NaviDown(); + DrawNow(); + response = EKeyWasConsumed; + break; + } + + case EKeyUpArrow: + { + // Adjust crop point + NaviUp(); + DrawNow(); + response = EKeyWasConsumed; + break; + } + + case EKeyRightArrow: + { + // Adjust crop point + NaviRight(); + DrawNow(); + response = EKeyWasConsumed; + break; + } + + case EKeyLeftArrow: + { + // Adjust crop point + NaviLeft(); + DrawNow(); + response = EKeyWasConsumed; + break; + } + + case EKeyOK: + case EKeyEnter: + { + KeyOkL(); + DrawNow(); + response = EKeyWasConsumed; + break; + } + + default: + { + break; + } + } + } + + else if (EEventKey == aType && !iHandleEventKeys) + { + response = EKeyWasConsumed; + } + + // EEventKeyDown + else if (EEventKeyDown == aType) + { + switch (aKeyEvent.iScanCode) + { + case EStdKeyLeftArrow: + case EStdKeyRightArrow: + case EStdKeyUpArrow: + case EStdKeyDownArrow: + { + iPressedKeyScanCode = aKeyEvent.iScanCode; + StartFastKeyTimer(); + response = EKeyWasConsumed; + break; + } + default: + break; + } + } + + // EEventKeyUp + else if (EEventKeyUp == aType) + { + if (aKeyEvent.iScanCode == iPressedKeyScanCode) + { + iHandleEventKeys = ETrue; + if (iState == ERedEyeReductionStateResizeSelection) + { + StartDancingAntzTimer(); + } + else if( iTimer ) + { + iTimer->Cancel(); + } + response = EKeyWasConsumed; + + ShowTooltip(); + } + } + + return response; +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::SizeChanged() +{ +} + +//============================================================================= +TRect CImageEditorRedEyeReductionControl::GetParam () +{ + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::GetParam" ); + if (iUndoArray.Count() == 0 || iDoNotUpdateParameters) + { + LOG( KRedEyeReductionPluginLogFile, "\tiRedEyeRect: (0,0), (0,0)" ); + return TRect(); + } + else + { + LOGFMT4( KRedEyeReductionPluginLogFile, "\tiRedEyeRect: (%d,%d), (%d,%d)", iRedEyeRect.iTl.iX, iRedEyeRect.iTl.iY, iRedEyeRect.iBr.iX, iRedEyeRect.iBr.iY ); + ComputeParams(); + return iRedEyeRect; + } +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::SetSystemParameters (const CSystemParameters * aPars) +{ + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::SetSystemParameters" ); + + iVisibleImageRect = &(aPars->VisibleImageRect()); + iVisibleImageRectPrev = &(aPars->VisibleImageRectPrev()); + iSysPars = aPars; + + __ASSERT_ALWAYS( iVisibleImageRectPrev && iVisibleImageRectPrev, User::Panic(KComponentName, KErrNotReady) ); + LOGFMT4( KRedEyeReductionPluginLogFile, "\tiVisibleImageRect: (%d,%d), (%d,%d)", iVisibleImageRect->iTl.iX, iVisibleImageRect->iTl.iY, iVisibleImageRect->iBr.iX, iVisibleImageRect->iBr.iY ); + LOGFMT2( KRedEyeReductionPluginLogFile, "\tVisible image rect size: %d,%d", (iVisibleImageRect->iBr.iX - iVisibleImageRect->iTl.iX) + 1, (iVisibleImageRect->iBr.iY - iVisibleImageRect->iTl.iY) + 1 ); + LOGFMT2( KRedEyeReductionPluginLogFile, "\tSize(): %d,%d", Size().iWidth, Size().iHeight ); + LOGFMT4( KRedEyeReductionPluginLogFile, "\tiVisibleImageRectPrev: (%d,%d), (%d,%d)", iVisibleImageRectPrev->iTl.iX, iVisibleImageRectPrev->iTl.iY, iVisibleImageRectPrev->iBr.iX, iVisibleImageRectPrev->iBr.iY ); + LOGFMT2( KRedEyeReductionPluginLogFile, "\tiVisibleImageRectPrev size: %d,%d", iVisibleImageRectPrev->Width(), iVisibleImageRectPrev->Height() ); +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::HandlePluginCommandL (const TInt aCommand) +{ + LOGFMT( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::HandlePluginCommandL: %d", aCommand ); + + switch (aCommand) + { + case EImageEditorFocusGained: + { + if (iState == ERedEyeReductionStateResizeSelection) + { + StartDancingAntzTimer(); + } + break; + } + case EImageEditorFocusLost: + { + if (iTimer) + { + iTimer->Cancel(); + } + break; + } + case EPgnSoftkeyIdCancel: + { + CancelPluginL(); + break; + } + case EPgnSoftkeyIdDone: + { + iDoNotUpdateParameters = ETrue; + iEditorView->HandleCommandL (EImageEditorApplyPlugin); + break; + } + case ERedEyeReductionPgnMenuCmdSet: + case EPgnSoftkeyIdSet: + { + KeyOkL(); + DrawNow(); + break; + } + case ERedEyeReductionPgnMenuCmdReduceRed: + case EPgnSoftkeyIdReduceRed: + { + KeyOkL(); + DrawNow(); + break; + } + case ERedEyeReductionPgnMenuCmdUndo: + { + UndoL(); + iEditorView->HandleCommandL (EImageEditorUpdateSoftkeys); + break; + } + case ERedEyeReductionPgnMenuCmdCancel: + { + CancelPluginL(); + break; + } + case EImageEditorPreGlobalZoomChange: + case EImageEditorPreGlobalPanChange: + { + iDoNotUpdateParameters = ETrue; + break; + } + case EImageEditorGlobalZoomChanged: + case EImageEditorGlobalPanChanged: + { + iDoNotUpdateParameters = EFalse; + DrawNow(); + break; + } + + case EImageEditorPreScreenModeChange: + { + TReal relscale = iSysPars->RelScale(); + TRect virect = *iVisibleImageRect; + virect.iTl.iX = (TInt)((virect.iTl.iX / relscale) + 0.5); + virect.iTl.iY = (TInt)((virect.iTl.iY / relscale) + 0.5); + virect.iBr.iX = (TInt)((virect.iBr.iX / relscale) + 0.5); + virect.iBr.iY = (TInt)((virect.iBr.iY / relscale) + 0.5); + iLockPoint.iX = virect.iTl.iX + iX * virect.Width(); + iLockPoint.iY = virect.iTl.iY + iY * virect.Height(); + break; + } + case EImageEditorPostScreenModeChange: + { + TReal relscale = iSysPars->RelScale(); + TRect virect = *iVisibleImageRect; + virect.iTl.iX = (TInt)((virect.iTl.iX / relscale) + 0.5); + virect.iTl.iY = (TInt)((virect.iTl.iY / relscale) + 0.5); + virect.iBr.iX = (TInt)((virect.iBr.iX / relscale) + 0.5); + virect.iBr.iY = (TInt)((virect.iBr.iY / relscale) + 0.5); + iX = (TReal)(iLockPoint.iX - virect.iTl.iX) / virect.Width(); + iY = (TReal)(iLockPoint.iY - virect.iTl.iY) / virect.Height(); + ClipPosition(); + DrawNow(); + break; + } + + default: + { + break; + } + } +} + +//============================================================================= +TInt CImageEditorRedEyeReductionControl::GetSoftkeyIndexL() +{ + + TInt index = -1; + if ( iState == ERedEyeReductionStateResizeSelection ) + { + if ( !iUndoArray.Count() ) + { + index = 3; + } + else + { + index = 1; + } + } + else if ( iState == ERedEyeReductionStateMoveCrosshair ) + { + if ( !iUndoArray.Count() ) + { + index = 0; + } + else + { + index = 2; + } + } + + + + LOGFMT( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::GetSoftkeyIndexL: %d", index ); + + return index; +} + +//============================================================================= +TBitField CImageEditorRedEyeReductionControl::GetDimmedMenuItems() +{ + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::GetDimmedMenuItems" ); + + TBitField dimmedMenuItems; + TInt count = iItem->MenuItems().Count(); + + switch (iState) + { + case ERedEyeReductionStateMoveCrosshair: + { + // Dim the command ERedEyeReductionPgnMenuCmdReduceRed, and also + // ERedEyeReductionPgnMenuCmdUndo if selecting the first eye. + for ( TInt i = 0; i < count; i++) + { + // get the menu item id + TInt menuItem = iItem->MenuItems().At(i).iCommandId; + if ( menuItem == ERedEyeReductionPgnMenuCmdReduceRed || + ( iUndoArray.Count() == 0 && menuItem == ERedEyeReductionPgnMenuCmdUndo) + ) + { + dimmedMenuItems.SetBit( i ); + } + } + break; + } + case ERedEyeReductionStateResizeSelection: + { + // Dim the command ERedEyeReductionPgnMenuCmdSet. + for ( TInt i = 0; i < count; i++) + { + // get the menu item id + TInt menuItem = iItem->MenuItems().At(i).iCommandId; + +#ifdef __TOUCH_ONLY_DEVICE_RER_PLUGIN_ACTION__ + if ( menuItem == ERedEyeReductionPgnMenuCmdSet || + ( iUndoArray.Count() == 0 && menuItem == ERedEyeReductionPgnMenuCmdUndo)) + { + dimmedMenuItems.SetBit( i ); + } +#else + if ( menuItem == ERedEyeReductionPgnMenuCmdSet ) + { + dimmedMenuItems.SetBit( i ); + } +#endif + + } + break; + } + default: + { + ASSERT( EFalse ); + break; + } + } + return dimmedMenuItems; +} + +//============================================================================= +TPtrC CImageEditorRedEyeReductionControl::GetNaviPaneTextL ( + TBool& aLeftNaviPaneScrollButtonVisibile, + TBool& aRightNaviPaneScrollButtonVisible ) +{ + aLeftNaviPaneScrollButtonVisibile = EFalse; + aRightNaviPaneScrollButtonVisible = EFalse; + return iNaviPaneText; +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::Draw (const TRect & aRect) const +{ + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::Draw()" ); + + CPreviewControlBase::DrawPreviewImage (aRect); + +#ifdef VERBOSE + LOGFMT4( KRedEyeReductionPluginLogFile, "\tiVisibleImageRect: (%d,%d), (%d,%d)", iVisibleImageRect->iTl.iX, iVisibleImageRect->iTl.iY, iVisibleImageRect->iBr.iX, iVisibleImageRect->iBr.iY ); + LOGFMT2( KRedEyeReductionPluginLogFile, "\tVisible image rect size: %d,%d", (iVisibleImageRect->iBr.iX - iVisibleImageRect->iTl.iX) + 1, (iVisibleImageRect->iBr.iY - iVisibleImageRect->iTl.iY) + 1 ); + LOGFMT2( KRedEyeReductionPluginLogFile, "\tSize(): %d,%d", Size().iWidth, Size().iHeight ); + LOGFMT4( KRedEyeReductionPluginLogFile, "\tiVisibleImageRectPrev: (%d,%d), (%d,%d)", iVisibleImageRectPrev->iTl.iX, iVisibleImageRectPrev->iTl.iY, iVisibleImageRectPrev->iBr.iX, iVisibleImageRectPrev->iBr.iY ); + LOGFMT2( KRedEyeReductionPluginLogFile, "\tiVisibleImageRectPrev size: %d,%d", iVisibleImageRectPrev->Width(), iVisibleImageRectPrev->Height() ); +#endif + + // In move state draw the crosshair + if ( iState == ERedEyeReductionStateMoveCrosshair ) + { + // Get graphics context + CWindowGc & gc = SystemGc(); + + gc.SetPenStyle (CGraphicsContext::ENullPen); + gc.SetBrushStyle (CGraphicsContext::ENullBrush); + + TSize chSize = iCrossHair->SizeInPixels(); + TPoint center = CursorLocation(); + gc.BitBltMasked ( + TPoint(center.iX - (chSize.iWidth >> 1), center.iY - (chSize.iHeight >> 1)), + iCrossHair, + TRect (chSize), + iCrossHairMask, + EFalse + ); + } + + // In resize state draw the selection circle + else if ( iState == ERedEyeReductionStateResizeSelection ) + { + DrawDancingAntz(Rect()); + } +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::DrawDancingAntz (const TRect & /*aRect*/) const +{ + // Get graphics context + CWindowGc & gc = SystemGc(); + + // Compute center point of the area + TPoint center = CursorLocation(); + + // Compute selection rectangle + TRect rect ( SelectionRect( center ) ); + + // Draw the "dancing ants" ellipse + gc.SetDrawMode (CGraphicsContext::EDrawModePEN); + gc.SetBrushStyle (CGraphicsContext::ENullBrush); + gc.SetBrushColor (KRgbBlack); + + // Draw + gc.SetPenStyle (CGraphicsContext::ESolidPen); + gc.SetPenColor ((iAntFlag) ? (KRgbBlack) : (KRgbWhite)); + gc.DrawEllipse (rect); + + // Draw dashed line + gc.SetPenStyle (CGraphicsContext::EDashedPen); + gc.SetPenColor ((iAntFlag) ? (KRgbWhite) : (KRgbBlack)); + gc.DrawEllipse (rect); + +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::UndoL() + { + TInt count = iUndoArray.Count(); + + LOGFMT( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::UndoL(): iUndoArray.Count() == %d", count ); + + switch (iState) + { + case ERedEyeReductionStateMoveCrosshair: + { + if ( count > 0 ) + { + // Remove the latest selected red eye area + // (It would be possible to set the cursor back to the point + // which was the location of the previous eye, but that + // depends also on the zoom and pan values, which are not + // available for plugins) + iUndoArray.Remove( count - 1 ); + + // Undo the filter + iEditorView->HandleCommandL (EImageEditorUndoFilter); + + if ( iUndoArray.Count() == 0) + { + // One filter is added already when opening the plugin. If + // this initial filter is undone, we need to create a new one. + iEditorView->HandleCommandL (EImageEditorStoreParameters); + iEditorView->HandleCommandL (EImageEditorAddFilterToEngine); + + } + else + { + // Restore parameters + iRedEyeRect = iUndoArray[ count - 2 ]; + } + } + break; + } + case ERedEyeReductionStateResizeSelection: + { + +#ifdef __TOUCH_ONLY_DEVICE_RER_PLUGIN_ACTION__ + // in touch-only device do the same thing here in resize state as + // in non-touch device in move state->remove/undo filter + if ( count > 0 ) + { + + iUndoArray.Remove( count - 1 ); + + // Undo the filter + iEditorView->HandleCommandL (EImageEditorUndoFilter); + + if ( iUndoArray.Count() == 0) + { + // One filter is added already when opening the plugin. If this + // initial filter is undone, we need to create a new one. + iEditorView->HandleCommandL (EImageEditorStoreParameters); + iEditorView->HandleCommandL (EImageEditorAddFilterToEngine); + + } + else + { + // Restore parameters + iRedEyeRect = iUndoArray[ count - 2 ]; + } + } + +#else + + // In the resize state consider that undo means + // going back to the move crosshair state (non-touch) + ToMoveStateL(); +#endif + + break; + } + + default: + { + ASSERT( EFalse ); + break; + } + } + + DrawNow(); + } + + +//============================================================================= +void CImageEditorRedEyeReductionControl::NaviDown() +{ + switch (iState) + { + case ERedEyeReductionStateMoveCrosshair: + { + iY += (KPosParamStep * iNaviStepMultiplier); + if (iY > KPosParamMax) + { + iY = KPosParamMax; + } + break; + } + case ERedEyeReductionStateResizeSelection: + { + iR -= (KRadiusParamStep * iNaviStepMultiplier); + if (iR < KRadiusParamMin) + { + iR = KRadiusParamMin; + } + break; + } + default: + { + ASSERT( EFalse ); + break; + } + } +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::NaviUp() +{ + switch (iState) + { + case ERedEyeReductionStateMoveCrosshair: + { + iY -= (KPosParamStep * iNaviStepMultiplier); + if (iY < KPosParamMin) + { + iY = KPosParamMin; + } + break; + } + case ERedEyeReductionStateResizeSelection: + { + iR += (KRadiusParamStep * iNaviStepMultiplier); + if (iR > KRadiusParamMax) + { + iR = KRadiusParamMax; + } + break; + } + default: + { + break; + } + } +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::NaviRight() +{ + switch (iState) + { + case ERedEyeReductionStateMoveCrosshair: + { + iX += (KPosParamStep * iNaviStepMultiplier); + if (iX > KPosParamMax) + { + iX = KPosParamMax; + } + break; + } + case ERedEyeReductionStateResizeSelection: + { + iR += (KRadiusParamStep * iNaviStepMultiplier); + if (iR > KRadiusParamMax) + { + iR = KRadiusParamMax; + } + break; + } + default: + { + break; + } + } +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::NaviLeft() +{ + switch (iState) + { + case ERedEyeReductionStateMoveCrosshair: + { + iX -= (KPosParamStep * iNaviStepMultiplier); + if (iX < KPosParamMin) + { + iX = KPosParamMin; + } + break; + } + case ERedEyeReductionStateResizeSelection: + { + iR -= (KRadiusParamStep * iNaviStepMultiplier); + if (iR < KRadiusParamMin) + { + iR = KRadiusParamMin; + } + break; + } + default: + { + break; + } + } +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::KeyOkL() +{ + switch (iState) + { + case ERedEyeReductionStateMoveCrosshair: + { + ToResizeStateL(); + break; + } + case ERedEyeReductionStateResizeSelection: + { + if ( iUndoArray.Count() > 0) + { + AddFilterToEngineL(); + } + else + { + + // Update the filter parameters + ComputeParams(); + + // Store coodinates + iUndoArray.Append( iRedEyeRect ); + + // Render + iEditorView->HandleCommandL (EImageEditorCmdRender); + } + + +#ifdef __TOUCH_ONLY_DEVICE_RER_PLUGIN_ACTION__ + // Loop only inside Resize state in touch-only devices + ToResizeStateL(); + +#else + + // Go back to move state (non-touch) + ToMoveStateL(); +#endif + + break; + } + + case ERedEyeReductionStateDone: + { + if ( iUndoArray.Count() > 0) + { + AddFilterToEngineL(); + } + else + { + // Update the filter parameters + ComputeParams(); + + // Store coodinates + iUndoArray.Append( iRedEyeRect ); + + // Render + iEditorView->HandleCommandL (EImageEditorCmdRender); + + } + break; + } + + default: + { + break; + } + } +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::CancelPluginL() +{ + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::CancelPluginL" ); + + iState = ERedEyeReductionStateMin; + + // Undo all the filters exept for the first one, + // which is cancelled by the framework. + TInt count = iUndoArray.Count(); + while ( count > 1) + { + iEditorView->HandleCommandL (EImageEditorUndoFilter); + count--; + } + + iEditorView->HandleCommandL (EImageEditorCancelPlugin); +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::ToMoveStateL() +{ + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::ToMoveState" ); + + // Stop dancing antz timer + if (iTimer) + { + iTimer->Cancel(); + } + + // Update navi pane text + iState = ERedEyeReductionStateMoveCrosshair; + iNaviPaneText.Copy ( iItem->Parameters()[KMoveSelectionIndex] ); + iEditorView->HandleCommandL (EImageEditorUpdateNavipane); + // Update softkeys + iEditorView->HandleCommandL (EImageEditorUpdateSoftkeys); + + ShowTooltip(); +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::ToResizeStateL() +{ + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::ToResizeState" ); + + // Start the timer + StartDancingAntzTimer(); + + // Reset the selection radius + iR = KRadiusParamDef; + + // Update navi pane text + iState = ERedEyeReductionStateResizeSelection; + iNaviPaneText.Copy ( iItem->Parameters()[KResizeSelectionIndex] ); + iEditorView->HandleCommandL (EImageEditorUpdateNavipane); + + // Update softkeys + iEditorView->HandleCommandL (EImageEditorUpdateSoftkeys); + + ShowTooltip(); +} + +//============================================================================= +TPoint CImageEditorRedEyeReductionControl::CursorLocation() const +{ + __ASSERT_ALWAYS( iVisibleImageRectPrev, User::Panic(KComponentName, KErrNotReady) ); + TInt x = (TInt) (iX * (iVisibleImageRectPrev->Width())) + iVisibleImageRectPrev->iTl.iX; + TInt y = (TInt) (iY * (iVisibleImageRectPrev->Height())) + iVisibleImageRectPrev->iTl.iY; + return TPoint( x, y ); +} + +//============================================================================= +TRect CImageEditorRedEyeReductionControl::SelectionRect( const TPoint& aCenter ) const +{ + __ASSERT_ALWAYS( iVisibleImageRectPrev, User::Panic(KComponentName, KErrNotReady) ); + + // Radius iR is relative to the real image's x dimension. + // To obtain a circe, y-dimenson must be scaled accordingly. + TInt vpWidth = (iVisibleImageRect->iBr.iX - iVisibleImageRect->iTl.iX); + TInt vpHeight = (iVisibleImageRect->iBr.iY - iVisibleImageRect->iTl.iY); + TReal xyRatio = (TReal) vpHeight / vpWidth; + + // Compute rectangle inside the image area + TInt width = iVisibleImageRectPrev->Width(); + TInt height = iVisibleImageRectPrev->Height(); + + TInt ulc = aCenter.iX - (TInt)( iR * width + 0.5 ); // upper left corner x + TInt ulr = aCenter.iY - (TInt)( iR * height / xyRatio + 0.5); // upper left corner y + TInt lrc = aCenter.iX + (TInt)( iR * width + 0.5 ); // lower right corner x + TInt lrr = aCenter.iY + (TInt)( iR * height / xyRatio + 0.5); // lower right corner y + + return TRect ( ulc, ulr, lrc, lrr ); +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::ComputeParams() +{ + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::ComputeParams()" ); + + __ASSERT_ALWAYS( iVisibleImageRect, User::Panic(KComponentName, KErrNotReady) ); + + // Compute the coordinates + + TInt vpWidth = iVisibleImageRect->iBr.iX - iVisibleImageRect->iTl.iX; + TInt vpHeight = iVisibleImageRect->iBr.iY - iVisibleImageRect->iTl.iY; + + TInt r = (TInt) (iR * vpWidth + 0.5); + TInt ulc = (TInt) (iX * vpWidth + 0.5 ) - r; + TInt ulr = (TInt) (iY * vpHeight + 0.5 ) - r; + TInt side = (TInt) (2 * iR * vpWidth + 0.5); + + // Set the filter parameters. + // The coordinates iX and iR are relative to the viewport image, + // whereas the filter parameters are relative to the source image. + iRedEyeRect.iTl.iX = iVisibleImageRect->iTl.iX + ulc; + iRedEyeRect.iTl.iY = iVisibleImageRect->iTl.iY + ulr; + iRedEyeRect.iBr.iX = iRedEyeRect.iTl.iX + side; + iRedEyeRect.iBr.iY = iRedEyeRect.iTl.iY + side; + + iReadyToRender = ETrue; +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::AddFilterToEngineL() +{ + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::AddFilterToEngineL" ); + + // Update the filter parameters + ComputeParams(); + + // Store coodinates for undo + iUndoArray.Append( iRedEyeRect ); + + // Force adding the filter to the engine. This includes setting the undo point. + iEditorView->HandleCommandL (EImageEditorAddFilterToEngine); + iEditorView->HandleCommandL (EImageEditorStoreParameters); + + // Render + iEditorView->HandleCommandL (EImageEditorCmdRender); +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::StartDancingAntzTimer() +{ + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::StartDancingAntzTimer()" ); + + iNaviStepMultiplier = KDefaultSmallNavigationStepMultiplier; + + if (iTimer) + { + iTimer->Cancel(); + iTimer->Start( + TTimeIntervalMicroSeconds32 (KDancingAntzTimerDelayInMicroseconds), + TTimeIntervalMicroSeconds32 (KDancingAntzTimerIntervalInMicroseconds), + TCallBack (DancingAntzCallback, this) + ); + } +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::StartFastKeyTimer() +{ + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::StartFastKeyTimer()" ); + + iNaviStepMultiplier = KDefaultSmallNavigationStepMultiplier; + iTickCount = 0; + + if (iTimer) + { + iTimer->Cancel(); + iTimer->Start( + TTimeIntervalMicroSeconds32 (KRedEyeFastKeyTimerDelayInMicroseconds), + TTimeIntervalMicroSeconds32 (KRedEyeFastKeyTimerIntervalInMicroseconds), + TCallBack (FastKeyCallback, this) + ); + } +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::OnDancingAntzCallBack() +{ + iAntFlag = !iAntFlag; + ActivateGc(); + DrawDancingAntz (Rect()); + DeactivateGc(); +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::OnFastKeyCallBackL() +{ +#ifdef VERBOSE + LOGFMT2( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::OnFastKeyCallBackL: iNaviStepMultiplier: %d, iTickCount: %d", iNaviStepMultiplier, iTickCount ); +#endif + + if (iTickCount > KRedEyeFastKeyTimerMultiplyThresholdInTicks) + { + iNaviStepMultiplier = KRedEyeBigNavigationStepMultiplier; + LOG( KRedEyeReductionPluginLogFile, "CImageEditorRedEyeReductionControl::OnFastKeyCallBackL: switching to big steps" ); + } + else + { + iTickCount++; + } + + iHandleEventKeys = EFalse; + + switch (iPressedKeyScanCode) + { + case EStdKeyDownArrow: + { + NaviDown(); + break; + } + case EStdKeyUpArrow: + { + NaviUp(); + break; + } + case EStdKeyLeftArrow: + { + NaviLeft(); + break; + } + case EStdKeyRightArrow: + { + NaviRight(); + break; + } + default: + break; + } + DrawNow(); +} + +//============================================================================= +TBool CImageEditorRedEyeReductionControl::IsReadyToRender() const +{ + return iReadyToRender; +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::GetHelpContext(TCoeHelpContext& aContext) const +{ + aContext.iMajor = TUid::Uid(UID_IMAGE_EDITOR); + aContext.iContext = KSIE_HLP_REDEYE; +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::ClipPosition() +{ + if (iX < KPosParamMin) + { + iX = KPosParamMin; + } + else if (iX > KPosParamMax) + { + iX = KPosParamMax; + } + + if (iY < KPosParamMin) + { + iY = KPosParamMin; + } + else if (iY > KPosParamMax) + { + iY = KPosParamMax; + } +} + +//============================================================================= +void CImageEditorRedEyeReductionControl::HandlePointerEventL( + const TPointerEvent &aPointerEvent) + { + if( AknLayoutUtils::PenEnabled() ) + { + TBool drawNow ( EFalse ); + switch( aPointerEvent.iType ) + { + case TPointerEvent::EButton1Down: + { + iPopupController->HideInfoPopupNote(); + // Enable dragging if in cursor area tapped + // (both move and resize cases) + if ( CursorTapped( aPointerEvent.iPosition ) ) + { + iCursorDragEnabled = ETrue; + drawNow = EFalse; + } + else if ( iState == ERedEyeReductionStateResizeSelection ) + { + // Tapping outside cursor area just stores the pointer + // position + if ( !CursorTapped( aPointerEvent.iPosition ) ) + { + iPointerPosition = aPointerEvent.iPosition; + drawNow = EFalse; + } + } + +#ifdef RD_TACTILE_FEEDBACK + if ( iTouchFeedBack ) + { + iTouchFeedBack->InstantFeedback( ETouchFeedbackBasic ); + RDebug::Printf( "ImageEditor::ImageEditorRedEyeReductionControl: ETouchFeedback" ); + } +#endif /* RD_TACTILE_FEEDBACK */ + + break; + } + case TPointerEvent::EDrag: + { + // Sets the new cursor position when drag is enabled + // (i.e. EButton1Down has happened in cursor area) + if ( ( iState == ERedEyeReductionStateMoveCrosshair || + iState ==ERedEyeReductionStateResizeSelection ) + && iCursorDragEnabled ) + { + SetCursorPosition( aPointerEvent.iPosition ); + // prevents user to move cursor outside image area + ClipPosition(); + drawNow = ETrue; + } + + // Selection cursor can be grown or made smaller moving + // pen up and down outside the cursor area + if ( iState == ERedEyeReductionStateResizeSelection && + !iCursorDragEnabled ) + { + if ( CalculateResize( iPointerPosition, + aPointerEvent.iPosition ) ) + { + iPointerPosition = aPointerEvent.iPosition; + drawNow = ETrue; + } + else + { + drawNow = EFalse; + } + } + + break; + } + case TPointerEvent::EButton1Up: + { + // Sets crosshair cursor to a new position + if ( iState == ERedEyeReductionStateMoveCrosshair ) + { + SetCursorPosition( aPointerEvent.iPosition ); + ClipPosition(); + drawNow = ETrue; + } + + ShowTooltip(); + + iCursorDragEnabled = EFalse; + break; + } + + default: + { + break; + } + } + + CCoeControl::HandlePointerEventL( aPointerEvent ); + + if ( drawNow ) + { + DrawNow(); + } + } + } + +//============================================================================= +void CImageEditorRedEyeReductionControl::SetCursorPosition( TPoint aNewPosition ) + { + //Set new x value + iX = TReal( aNewPosition.iX - iVisibleImageRectPrev->iTl.iX ) / + ( iVisibleImageRectPrev->iBr.iX - iVisibleImageRectPrev->iTl.iX ); + + //Set new y value + iY = TReal( aNewPosition.iY - iVisibleImageRectPrev->iTl.iY ) / + ( iVisibleImageRectPrev->iBr.iY - iVisibleImageRectPrev->iTl.iY ); + } + + +//============================================================================= +TRect CImageEditorRedEyeReductionControl::CrossHairCursorRect() const + { + + TSize chSize = iCrossHair->SizeInPixels(); + TPoint center = CursorLocation(); + TPoint topLeftCorner(center.iX - (chSize.iWidth >> 1), + center.iY - (chSize.iHeight >> 1)); + + TRect moveCursorRect( topLeftCorner, chSize ); + + return moveCursorRect; + + } + +//============================================================================= +TBool CImageEditorRedEyeReductionControl::CursorTapped( TPoint aTappedPosition ) const + { + TBool cursorTapped( EFalse ); + TRect cursorRect; + + if ( iState == ERedEyeReductionStateMoveCrosshair ) + { + cursorRect = CrossHairCursorRect(); + + TPoint newTLCorner = TPoint( cursorRect.iTl.iX - ( cursorRect.Width() / 2 ), + cursorRect.iTl.iY - ( cursorRect.Height() / 2 ) ); + TPoint newBRCorner = TPoint( cursorRect.iBr.iX + ( cursorRect.Width() / 2 ), + cursorRect.iBr.iY + ( cursorRect.Height() / 2 )); + + // Make tappable rect double sized to crosshair rect + TRect doubleCursorRect = TRect( newTLCorner, newBRCorner ); + + cursorTapped = doubleCursorRect.Contains( aTappedPosition ); + } + else if ( iState == ERedEyeReductionStateResizeSelection ) + { + cursorRect = SelectionRect( CursorLocation() ); + cursorTapped = cursorRect.Contains( aTappedPosition ); + } + + return cursorTapped; + } + +//============================================================================= +void CImageEditorRedEyeReductionControl::ShowTooltip() + { + iPopupController->HideInfoPopupNote(); + + if ( iState == ERedEyeReductionStateMoveCrosshair ) + { + TPoint center = CursorLocation(); + SDrawUtils::ShowToolTip( iPopupController, + this, + center, + EHLeftVBottom, + *iTooltipLocate ); + } + else if ( iState == ERedEyeReductionStateResizeSelection ) + { + TRect circleRect ( SelectionRect( CursorLocation() ) ); + TPoint center( circleRect.Center() ); + + SDrawUtils::ShowToolTip( iPopupController, + this, + center, + EHLeftVBottom, + *iTooltipOutline ); + } + } + +//============================================================================= +TBool CImageEditorRedEyeReductionControl::CalculateResize( TPoint aStartPoint, + TPoint aEndPoint ) + { + // Whether bubble is resized in this function or not + TBool radiusChanged( EFalse ); + // Store old scale value + TReal oldRadius = iR; + TReal changeThreshold( 0.001 ); + + // Get system parameters + TRect visibleImageRectPrev( iSysPars->VisibleImageRectPrev() ); + + // Compute change on the screen + TInt deltaX = aEndPoint.iX - aStartPoint.iX; + TInt deltaY = aEndPoint.iY - aStartPoint.iY; + + // Use bigger dimension + TInt maxChangeInPixels; + if ( visibleImageRectPrev.Height() > visibleImageRectPrev.Width() ) + { + maxChangeInPixels = visibleImageRectPrev.Height(); + } + else + { + maxChangeInPixels = visibleImageRectPrev.Width(); + } + + TInt oneStepInPixels = maxChangeInPixels / KTouchScaleMaxStepCount; + TReal scaleStep = ( KRadiusParamMax - KRadiusParamMin ) / KTouchScaleMaxStepCount; + + // Relates to second and fourth corners. Defines how steep/gentle the + // moving angle has to be in order to scale. + TInt slopeAngleFactor = 3; + + // The first quarter (movement towards upper-right corner) + if( ( deltaX > 0 && deltaY <= 0 ) || ( deltaX >= 0 && deltaY < 0 ) ) + { + // use bigger value + if (Abs( deltaX ) >= Abs( deltaY) ) + { + iR += scaleStep * ( Abs( deltaX ) / oneStepInPixels ); + } + else + { + iR += scaleStep * ( Abs( deltaY ) / oneStepInPixels ); + } + } + // The second (movement towards lower-right corner) + else if( ( deltaX > 0 && deltaY >= 0 ) || ( deltaX >= 0 && deltaY > 0 ) ) + { + if( deltaX > slopeAngleFactor * deltaY ) + { + iR += scaleStep * ( Abs( deltaX ) / oneStepInPixels ); + } + + else if ( slopeAngleFactor * deltaX < deltaY ) + { + iR -= scaleStep * ( Abs( deltaY ) / oneStepInPixels ); + } + } + // The third (movement towards lower-left corner) + else if( ( deltaX < 0 && deltaY >= 0 ) || ( deltaX <= 0 && deltaY > 0 ) ) + { + if (Abs( deltaX ) >= Abs( deltaY) ) + { + iR -= scaleStep * ( Abs( deltaX ) / oneStepInPixels ); + } + else + { + iR -= scaleStep * ( Abs( deltaY ) / oneStepInPixels ); + } + } + // The fourth (movement towards upper-left corner) + else if( ( deltaX < 0 && deltaY <= 0 ) || ( deltaX <= 0 && deltaY < 0 ) ) + { + if( slopeAngleFactor * Abs( deltaX ) < Abs( deltaY ) ) + { + iR += scaleStep * ( Abs( deltaY ) / oneStepInPixels ); + } + else if ( Abs( deltaX ) > slopeAngleFactor * Abs( deltaY ) ) + { + iR -= scaleStep * ( Abs( deltaX ) / oneStepInPixels ); + } + } + + // Check the limits + if (iR > KRadiusParamMax) + { + iR = KRadiusParamMax; + radiusChanged = ETrue; + } + + if (iR < KRadiusParamMin) + { + iR = KRadiusParamMin; + radiusChanged = ETrue; + } + + if ( Abs( oldRadius - iR ) > changeThreshold ) + { + radiusChanged = ETrue; + } + + return radiusChanged; + + } +// End of File