--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/uiacceltk/hitchcock/coretoolkit/src/HuiImageVisual.cpp Tue Feb 02 07:56:43 2010 +0200
@@ -0,0 +1,650 @@
+/*
+* Copyright (c) 2006-2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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:
+*
+* Description: Implementation of CHuiImageVisual. CHuiImageVisual is a visual
+* that is able to display images.
+*
+*/
+
+
+
+#include "uiacceltk/HuiImageVisual.h" // Class definition
+#include "uiacceltk/HuiStatic.h"
+#include "HuiRenderPlugin.h"
+#include "uiacceltk/HuiDrawing.h"
+#include "uiacceltk/HuiControl.h"
+#include "uiacceltk/HuiUtil.h"
+#include "uiacceltk/huifixmath.h"
+#include "HuiMatrixStack.h"
+
+#include "uiacceltk/huidropshadow.h"
+#include "uiacceltk/HuiDisplay.h"
+
+#include "HuiRosterImpl.h"
+
+
+EXPORT_C CHuiImageVisual* CHuiImageVisual::AddNewL(CHuiControl& aOwnerControl,
+ CHuiLayout* aParentLayout)
+ {
+ CHuiImageVisual* image = static_cast<CHuiImageVisual*>(
+ aOwnerControl.AppendVisualL(EHuiVisualTypeImage, aParentLayout));
+ return image;
+ }
+
+
+CHuiImageVisual::CHuiImageVisual(MHuiVisualOwner& aOwner)
+ : CHuiVisual(aOwner), iScaleMode(EScaleFit),
+ iStretchMode(CHuiGc::EStretchVertical), iColor(KRgbWhite),
+ iScale(1.f),iOffset(.5f,.5f),iDropShadow(0)
+ {
+ iSecondaryAlpha.SetStyle(EHuiTimedValueStyleLinear);
+ }
+
+
+void CHuiImageVisual::ConstructL()
+ {
+ CHuiVisual::ConstructL();
+ }
+
+
+CHuiImageVisual::~CHuiImageVisual()
+ {
+ }
+
+
+EXPORT_C void CHuiImageVisual::SetScaleMode(TScaleMode aScaleMode)
+ {
+ iScaleMode = aScaleMode;
+ SetChanged();
+ }
+
+
+EXPORT_C void CHuiImageVisual::SetStretch(TInt aTop, TInt aBottom)
+ {
+ iTopStretch = aTop;
+ iBottomStretch = aBottom;
+ SetChanged();
+ }
+
+
+EXPORT_C void CHuiImageVisual::SetStretchMode(CHuiGc::TStretchMode aStretchMode)
+ {
+ iStretchMode = aStretchMode;
+ SetChanged();
+ }
+
+// deprecated
+EXPORT_C void CHuiImageVisual::SetDropShadow(TInt aShadowDistance)
+ {
+ SetDropShadow(THuiXYMetric(aShadowDistance));
+ }
+
+EXPORT_C void CHuiImageVisual::SetDropShadow(const THuiMetric& aShadowDistance)
+ {
+ SetDropShadow(THuiXYMetric(aShadowDistance));
+ }
+
+EXPORT_C void CHuiImageVisual::SetDropShadow(const THuiXYMetric& aShadowDistance)
+ {
+ iDropShadow = aShadowDistance;
+ SetChanged();
+
+ if(!HuiUtil::RealCompare(iDropShadow.iX.iMagnitude,0.f) || !HuiUtil::RealCompare(iDropShadow.iY.iMagnitude,0.f))
+ {
+ TRAP_IGNORE( EnableDropShadowL( ETrue ) );
+ }
+ else
+ {
+ TRAP_IGNORE( EnableDropShadowL( EFalse ) );
+ }
+
+ }
+
+
+EXPORT_C void CHuiImageVisual::SetImage(const THuiImage& aImage)
+ {
+ iImage = aImage;
+ SetChanged();
+ }
+
+
+EXPORT_C void CHuiImageVisual::SetSecondaryImage(const THuiImage& aImage)
+ {
+ iSecondaryImage = aImage;
+ SetChanged();
+ }
+
+
+EXPORT_C const THuiImage& CHuiImageVisual::Image() const
+ {
+ return iImage;
+ }
+
+
+EXPORT_C void CHuiImageVisual::SetColor(const TRgb& aColor)
+ {
+ iColor = aColor;
+ SetChanged();
+ }
+
+
+EXPORT_C void CHuiImageVisual::SetColorMode(TColorMode aColorMode, TReal32 aParam) __SOFTFP
+ {
+ iColorMode = aColorMode;
+ iColorParam = aParam;
+ SetChanged();
+ }
+
+TBool CHuiImageVisual::PrepareDrawL()
+ {
+ if (Flags() & EHuiVisualFlagDrawOnlyAsExternalContent)
+ {
+ // This is used only as external content visual. Return now if we are not currently drawing
+ // external content.
+ if (!Display() || !Display()->RosterImpl().IsDrawingExternalContent())
+ {
+ return ETrue;
+ }
+ }
+
+ if ( iImage.HasTexture() )
+ {
+ CHuiDropShadow* shadowHandler = DropShadowHandler();
+ if ( shadowHandler && shadowHandler->IsShadowVisible() )
+ {
+ CHuiTexture* shadowTextureSource = shadowHandler->ShadowedTextureInstance( *iImage.ImageTexture() );
+ if ( shadowTextureSource )
+ {
+ const TInt requestedBlurredSize = HUI_ROUND_FLOAT_TO_INT( 2*DropShadowHandler()->iRadius.Now() );
+ shadowTextureSource->CreateShadowTextureL( requestedBlurredSize, EHuiTextureShadowStyleIcon );
+ }
+ }
+ }
+ return ETrue;
+ }
+
+void CHuiImageVisual::DrawSelf(CHuiGc& aGc, const TRect& /*aDisplayRect*/) const
+ {
+ TReal32 effectiveOpacity = EffectiveOpacity();
+
+ THuiRealRect content = DisplayRect();
+ content.Shrink(PaddingInPixels());
+
+ if(!iImage.HasTexture() || effectiveOpacity <= 0)
+ {
+ aGc.NotifyImagePreferredSize(iImage, content);
+ return;
+ }
+
+ if(content.Width() <= 0 || content.Height() <= 0)
+ {
+ // Too small to see.
+ return;
+ }
+
+ aGc.Enable(CHuiGc::EFeatureBlending);
+
+ TReal32 turnAngle = iTurnAngle.Now();
+ TReal32 xOffset = 0;
+ TReal32 yOffset = 0;
+
+ TReal32 scale = HuiUtil::CalculateScaleFactorFromScaleMode(
+ content.Size(),
+ iImage.Texture().Size(),
+ iScaleMode,
+ iScale.Now() );
+
+ // Determine offset.
+ TSize imageSize = iImage.Texture().Size();
+ TReal32 scaled = scale * imageSize.iWidth;
+ if(scaled > content.Width())
+ {
+ xOffset = (scaled - content.Width()) * (iOffset.iX.Now() - 0.5f);
+ }
+ scaled = scale * imageSize.iHeight;
+ if(scaled > content.Height())
+ {
+ yOffset = (scaled - content.Height()) * (iOffset.iY.Now() - 0.5f);
+ }
+
+ if(turnAngle != 0 || scale != 1)
+ {
+ /** @todo GC must provide some support for transformations. */
+ aGc.Push(EHuiGcMatrixModel);
+
+ // Rotate around the midpoint of the visual.
+ THuiRealPoint mid = content.Center();
+
+ aGc.Translate(EHuiGcMatrixModel, mid.iX - xOffset, mid.iY - yOffset, 0.f);
+ if(turnAngle != 0)
+ {
+ aGc.Rotate(EHuiGcMatrixModel, turnAngle, 0.f, 0.f, -1.f);
+ }
+ if(scale != 1)
+ {
+ aGc.Scale(EHuiGcMatrixModel, scale, scale, 1.f);
+ }
+ aGc.Translate(EHuiGcMatrixModel, -mid.iX, -mid.iY, 0.f);
+ }
+
+ // Use the appropriate alignment in the graphics context.
+ if(iScaleMode == EScaleFit)
+ {
+ aGc.SetAlign(EHuiAlignHLeft, EHuiAlignVTop);
+ }
+ else
+ {
+ aGc.SetAlign(EHuiAlignHCenter, EHuiAlignVCenter);
+ }
+
+ // draw drop shadow
+ CHuiDropShadow* shadowHandler = DropShadowHandler();
+ if ( shadowHandler && iImage.HasTexture() )
+ {
+ CHuiTexture* shadowTextureSource = shadowHandler->ShadowedTextureInstance( *iImage.ImageTexture() );
+ if ( iImage.ImageTexture() &&
+ shadowTextureSource &&
+ shadowHandler->IsShadowVisible() )
+ {
+ const TInt requestedBlurredSize = HUI_ROUND_FLOAT_TO_INT( 2*DropShadowHandler()->iRadius.Now() );
+
+ THuiTextureHandle shadow;
+ TBool haveShadowTexture = shadowTextureSource->GetShadowTexture( shadow,requestedBlurredSize );
+
+ if ( haveShadowTexture )
+ {
+ THuiImage shadowImage( shadow );
+ const THuiRealRect shadowDrawingRect = shadowHandler->ShadowDrawingRealRect(
+ content.iTl,
+ content.Size(),
+ shadow.Size(),
+ *this );
+
+ // set drawing parameters
+ aGc.SetPenAlpha(TInt(effectiveOpacity * shadowHandler->iOpacity.Now()*255.f));
+ aGc.SetPenColor(shadowHandler->Color());
+ const THuiQuality oldQuality = aGc.Quality(); // store the original quality
+ aGc.SetQuality(EHuiQualityFast); // draw always with 'fast'
+
+ if(iScaleMode == EScaleFit)
+ {
+ aGc.DrawImage(shadowImage, shadowDrawingRect.iTl, shadowDrawingRect.Size() );
+ }
+ else
+ {
+ THuiRealSize relativeShadowTextureSize = iImage.Texture().Size();
+ relativeShadowTextureSize.iWidth *= ((TReal32)shadowDrawingRect.Width())/((TReal32)content.Size().iWidth);
+ relativeShadowTextureSize.iHeight *= ((TReal32)shadowDrawingRect.Height())/((TReal32)content.Size().iHeight);
+
+ aGc.DrawImage(
+ shadowImage,
+ relativeShadowTextureSize,
+ THuiRealRect( shadowDrawingRect.iTl, shadowDrawingRect.Size() ));
+
+ }
+
+ aGc.SetQuality(oldQuality); // restore quality
+ }
+ }
+ }
+
+ // Actual color of the image.
+ aGc.SetPenAlpha(TInt(effectiveOpacity * 255));
+ aGc.SetPenColor(iColor);
+
+ // Apply special color mode.
+ if(iColorMode == EColorDimmed)
+ {
+ aGc.Enable(CHuiGc::EFeatureFog);
+ aGc.SetDimmingFog(iColor, iColorParam);
+ }
+
+ if(iTopStretch || iBottomStretch)
+ {
+ aGc.DrawStretchImage(iStretchMode, iImage, content,
+ iTopStretch, iBottomStretch);
+ }
+ else
+ {
+ if(aGc.TextureUnits() >= 2 &&
+ CHuiStatic::Renderer().Allows(EHuiRenderPluginAllowTextureModeInterpolate) &&
+ iImage.HasTexture() && iSecondaryImage.HasTexture() &&
+ (iImage.SegmentCount() == iSecondaryImage.SegmentCount() &&
+ (iImage.Texture().Size() == iSecondaryImage.Texture().Size() || iImage.SegmentCount() == 1)))
+ {
+ // Can use multitexturing to interpolate.
+ aGc.SetTextureUnits(2);
+ aGc.Enable(CHuiGc::EFeatureTexturing);
+ aGc.SetTextureMode(CHuiGc::ETextureModeInterpolate,
+ iSecondaryAlpha.Now());
+ aGc.SetPenAlpha(TInt(effectiveOpacity * 255));
+
+ if(iScaleMode == EScaleFit)
+ {
+ // Scale both images to the content rectangle.
+ aGc.DrawImages(iImage, iSecondaryImage,
+ content.iTl, content.Size());
+ }
+ else
+ {
+ // Draw both images by taking the size of the first one.
+ aGc.DrawImages(iImage, iSecondaryImage,
+ iImage.Texture().Size(), content);
+ }
+
+ aGc.SetTextureUnits(1);
+ aGc.SetTextureMode(CHuiGc::ETextureModeNormal);
+ }
+ else
+ {
+ // Must draw using two passes.
+ TInt primaryAlpha = 0;
+ TInt secondaryAlpha = 0;
+ GetDualAlpha(effectiveOpacity, iSecondaryAlpha.Now(),
+ primaryAlpha, secondaryAlpha);
+
+ // Draw both the primary and the secondary images.
+ if(primaryAlpha > 0)
+ {
+ aGc.SetPenAlpha(primaryAlpha);
+ if(iScaleMode == EScaleFit)
+ {
+ aGc.DrawImage(iImage, content.iTl, content.Size());
+ }
+ else
+ {
+ aGc.DrawImage(iImage, content);
+ }
+ }
+
+ if(secondaryAlpha > 0 && iSecondaryImage.HasTexture())
+ {
+ aGc.SetPenAlpha(secondaryAlpha);
+ if(iScaleMode == EScaleFit)
+ {
+ aGc.DrawImage(iSecondaryImage, content.iTl, content.Size());
+ }
+ else
+ {
+ aGc.DrawImage(iSecondaryImage, iImage.Texture().Size(), content);
+ }
+ }
+ else
+ {
+ // Notify preferred size even if image is not drawn (yet)
+ aGc.NotifyImagePreferredSize(iSecondaryImage, content);
+ }
+ }
+ }
+
+ // Disable special color modes.
+ if(iColorMode == EColorDimmed)
+ {
+ aGc.Disable(CHuiGc::EFeatureFog);
+ }
+
+ // Restore original transformation.
+ if(turnAngle != 0 || scale != 1)
+ {
+ aGc.Pop(EHuiGcMatrixModel);
+ }
+ }
+
+
+TBool CHuiImageVisual::Changed() const
+ {
+ if(CHuiVisual::Changed())
+ {
+ return ETrue;
+ }
+
+ if(iImage.Changed())
+ {
+ return ETrue;
+ }
+
+ return (iTurnAngle.Changed() || iOffset.Changed() || iScale.Changed() ||
+ iSecondaryAlpha.Changed());
+ }
+
+
+void CHuiImageVisual::ClearChanged()
+ {
+ CHuiVisual::ClearChanged();
+ iImage.ClearChanged();
+ iTurnAngle.ClearChanged();
+ iOffset.ClearChanged();
+ iScale.ClearChanged();
+ iSecondaryAlpha.ClearChanged();
+ }
+
+void DoRotateRect(THuiRealRect& aRect, TReal32 aAngle)
+ {
+ // Transform dirty rect and enlarge it if rotated.
+ THuiRealRect transformed(aRect);
+
+ THuiRealPoint coords[4];
+ coords[0].iX = transformed.iTl.iX;
+ coords[0].iY = transformed.iTl.iY;
+ coords[1].iX = transformed.iBr.iX;
+ coords[1].iY = transformed.iTl.iY;
+ coords[2].iX = transformed.iBr.iX;
+ coords[2].iY = transformed.iBr.iY;
+ coords[3].iX = transformed.iTl.iX;
+ coords[3].iY = transformed.iBr.iY;
+
+
+ TInt radians = HuiFixMath::FixMul(HuiFixMath::FloatToFix(aAngle),KFixPi)/180;
+ if (aAngle < 0)
+ {
+ radians = -radians;
+ }
+
+ TInt sin = HuiFixMath::FixSin(radians);
+ TInt cos = HuiFixMath::FixCos(radians);
+
+
+ CHuiMatrixStack::TMatrix rotation;
+ rotation.iMatrix[0] = HuiFixMath::FixToFloat(cos);
+ rotation.iMatrix[1] = HuiFixMath::FixToFloat(sin);
+ rotation.iMatrix[3] = HuiFixMath::FixToFloat(-sin);
+ rotation.iMatrix[4] = HuiFixMath::FixToFloat(cos);
+ rotation.iMatrix[8] = 1.0f;
+ rotation.iIsIdentity = EFalse;
+
+ for (TInt count = 0; count < 4; count++)
+ {
+ rotation.Multiply(coords[count]);
+ }
+
+ // rotate only if there is really rotation, not mirroring
+
+ if ( !HuiUtil::RealCompare(coords[2].iY, coords[3].iY) )
+ {
+ // rotation has been applied
+ THuiRealPoint minPoint = coords[0];
+ THuiRealPoint maxPoint = coords[0];
+ for (TInt count = 1; count < 4; count++)
+ {
+ if (coords[count].iX < minPoint.iX)
+ {
+ minPoint.iX = coords[count].iX;
+ }
+ if (coords[count].iY < minPoint.iY)
+ {
+ minPoint.iY = coords[count].iY;
+ }
+ if (coords[count].iX > maxPoint.iX)
+ {
+ maxPoint.iX = coords[count].iX;
+ }
+ if (coords[count].iY > maxPoint.iY)
+ {
+ maxPoint.iY = coords[count].iY;
+ }
+ }
+
+ transformed.iTl = minPoint;
+ transformed.iBr = maxPoint;
+ }
+ else
+ {
+ transformed.iTl = coords[0];
+ transformed.iBr = coords[2];
+ }
+
+ aRect = transformed;
+ }
+
+
+void CHuiImageVisual::ExpandRectWithContent(TRect& aRect) const
+ {
+ if(!Clipping())
+ {
+ if( iImage.HasTexture() )
+ {
+ TSize imageSize = iImage.Texture().Size();
+
+ // Handle scale mode
+ if (iScaleMode == EScaleNormal &&
+ ( imageSize.iWidth > aRect.Width() || imageSize.iHeight > aRect.Height()))
+ {
+ const TInt growX = Max( 0, ((imageSize.iWidth - aRect.Width()) + 1) / 2 );
+ const TInt growY = Max( 0, ((imageSize.iHeight - aRect.Height()) + 1) / 2 );
+ aRect.Grow( growX, growY );
+ }
+ else if (iScaleMode == EScaleFitWidth)
+ {
+ TReal32 scale = HuiUtil::CalculateScaleFactorFromScaleMode(
+ aRect.Size(),
+ imageSize,
+ iScaleMode,
+ 1.f );
+ TInt scaled = (TReal32)imageSize.iHeight*scale+0.5f;
+ if (scaled > aRect.Height())
+ {
+ aRect.Grow(0,(((scaled-aRect.Height()) +1)/2));
+ }
+ }
+ else if (iScaleMode == EScaleFitHeight)
+ {
+ TReal32 scale = HuiUtil::CalculateScaleFactorFromScaleMode(
+ aRect.Size(),
+ imageSize,
+ iScaleMode,
+ 1.f );
+ TInt scaled = (TReal32)imageSize.iWidth*scale+0.5f;
+ if (scaled > aRect.Width())
+ {
+ aRect.Grow((((scaled-aRect.Width()) +1)/2),0);
+ }
+ }
+ else if (iScaleMode == EScaleCover || iScaleMode == EScaleFitInside)
+ {
+ TReal32 scale = HuiUtil::CalculateScaleFactorFromScaleMode(
+ aRect.Size(),
+ imageSize,
+ iScaleMode,
+ 1.f );
+ TInt scaledW = (TReal32)imageSize.iWidth*scale+0.5f;
+ TInt scaledH = (TReal32)imageSize.iHeight*scale+0.5f;
+
+ if (scaledW > aRect.Width())
+ {
+ aRect.Grow((((scaledW-aRect.Width()) +1)/2),0);
+ }
+ if (scaledH > aRect.Height())
+ {
+ aRect.Grow(0,(((scaledH-aRect.Height()) +1)/2));
+ }
+ }
+ else
+ {
+ // For PC-lint
+ }
+ }
+
+ // Calculate scaled rect.
+ // aRect and scaled rect has same center position.
+ TRect adjusted;
+ TReal32 scale = iScale.Now();
+ TReal32 offsetX = TReal32(aRect.Width()) * scale / 2.f;
+ TReal32 offsetY = TReal32(aRect.Height()) * scale / 2.f;
+
+ adjusted.iTl.iX = HUI_ROUND_FLOAT_TO_INT((aRect.iTl.iX + aRect.Width()/2.f) - offsetX);
+ adjusted.iTl.iY = HUI_ROUND_FLOAT_TO_INT((aRect.iTl.iY + aRect.Height()/2.f) - offsetY);
+ adjusted.iBr.iX = HUI_ROUND_FLOAT_TO_INT((aRect.iBr.iX - aRect.Width()/2.f) + offsetX);
+ adjusted.iBr.iY = HUI_ROUND_FLOAT_TO_INT((aRect.iBr.iY - aRect.Height()/2.f) + offsetY);
+
+ // aRect must not become smaller.
+ aRect.BoundingRect( adjusted );
+
+ // calculate drop shadow
+ CHuiDropShadow* shadowHandler = DropShadowHandler();
+ if ( iImage.HasTexture() &&
+ shadowHandler &&
+ shadowHandler->IsShadowVisible() )
+ {
+ CHuiTexture* shadowTextureSource = shadowHandler->ShadowedTextureInstance( *iImage.ImageTexture() );
+ if ( shadowTextureSource )
+ {
+
+ const TInt requestedBlurredSize = HUI_ROUND_FLOAT_TO_INT( 2*shadowHandler->iRadius.Now() );
+
+ THuiTextureHandle shadow;
+ TBool haveShadowTexture = shadowTextureSource->GetShadowTexture( shadow,requestedBlurredSize );
+
+ if ( haveShadowTexture )
+ {
+ const TRect shadowRect = shadowHandler->ShadowDrawingTRect(
+ aRect.iTl,
+ aRect.Size(),
+ shadow.Size(),
+ *this );
+
+ // aRect must not become smaller.
+ aRect.BoundingRect( shadowRect );
+ }
+ }
+ }
+
+ // add the turn angle effect
+ if ( iImage.HasTexture() && iTurnAngle.Now() )
+ {
+ // Take turn angle into accout by rotating aRect.
+ THuiRealRect rotated( THuiRealPoint(0.f,0.f), aRect.Size() );
+ rotated.Move( -rotated.Center().iX, -rotated.Center().iY );
+ DoRotateRect( rotated, iTurnAngle.Now() );
+ TSize rotatedSize = rotated.Size();
+ // Size rounds down, compensate by increasing by one.
+ rotatedSize.iWidth++;
+ rotatedSize.iHeight++;
+
+ // Define rotatedRect: same center point as aRect, different size
+ TRect rotatedRect( rotatedSize );
+ rotatedRect.Move(
+ aRect.Center() -
+ TPoint( ( rotatedSize.iWidth + 1 )/2, ( rotatedSize.iHeight + 1 )/2 ) );
+ rotatedRect.iBr += TPoint( 1, 1 ); // two possible center
+
+ // aRect must not become smaller.
+ aRect.BoundingRect( rotatedRect );
+ }
+
+ // Apparently, there is two pixel error in above
+ // (occurs already before scaling, fit width/fit height cases).
+ aRect.Grow( 2, 2 );
+ }
+
+ CHuiVisual::ExpandRectWithContent(aRect);
+ }