diff -r 000000000000 -r 15bf7259bb7c uiacceltk/hitchcock/coretoolkit/src/HuiGridLayout.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uiacceltk/hitchcock/coretoolkit/src/HuiGridLayout.cpp Tue Feb 02 07:56:43 2010 +0200 @@ -0,0 +1,839 @@ +/* +* 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: ?Description +* +*/ + + + +#include "uiacceltk/HuiGridLayout.h" // Class definition +#include "uiacceltk/HuiControl.h" +#include "uiacceltk/HuiPanic.h" +#include "uiacceltk/HuiUtil.h" +#include "uiacceltk/huimetric.h" + +#include + + +#define FLOOR(x) (TReal32(TInt(TReal32(x)))) +#define FLOOR_INT(x) (TInt((x))) + +// Symbian does not have a native ceil() implementation, we need to use "near enough" rounding. +#define CEIL(x) (TReal32(TInt(TReal32(x)+0.999f))) +#define CEIL_INT(x) (TInt(TReal32(x)+0.999f)) + +// Fractional part of real +#define FRAC(x) (TReal32(x)-FLOOR(x)) + +// +// Private structures +// + +struct TAxis + { + + /** Array of block weights. Used to calculate relative sizes of lines of blocks. */ + RArray iWeights; + TUint iLayoutFlags; + }; + +/* + * grid weights + */ +struct CHuiGridLayout::TGridLayoutPrivateData + { +public: + TGridLayoutPrivateData(); +public: + RArray iAxes; + + /** Sets the grid dimensions to automatically expand to store more content */ + TInt iExpansionFlags; + }; + +CHuiGridLayout::TGridLayoutPrivateData::TGridLayoutPrivateData() + : + iExpansionFlags(0) + { + + } + + +// +// class CHuiGridLayout +// + +EXPORT_C CHuiGridLayout* CHuiGridLayout::AddNewL(CHuiControl& aOwnerControl, + TInt aColumns, TInt aRows, + CHuiLayout* aParentLayout) + { + CHuiGridLayout* grid = STATIC_CAST(CHuiGridLayout*, + aOwnerControl.AppendLayoutL(EHuiLayoutTypeGrid, aParentLayout)); + grid->SetColumnsL(aColumns); + grid->SetRowsL(aRows); + + return grid; + } + + +EXPORT_C CHuiGridLayout::CHuiGridLayout(MHuiVisualOwner& aOwner) + : CHuiLayout(aOwner) + { + } + + +EXPORT_C void CHuiGridLayout::ConstructL() + { + CHuiLayout::ConstructL(); + iGridLayoutData = new(ELeave) TGridLayoutPrivateData; + for(TInt ii = EHuiGridColumn; ii <= EHuiGridRow; ii++) + { + TAxis axis; + axis.iLayoutFlags = 0; + + iGridLayoutData->iAxes.AppendL(axis); + } + SetColumnsL(1); + SetRowsL(1); + } + + +EXPORT_C CHuiGridLayout::~CHuiGridLayout() + { + if ( iGridLayoutData ) + { + for(TInt ii = EHuiGridColumn; ii <= EHuiGridRow; ii++) + { + TAxis& axis = iGridLayoutData->iAxes[ii]; + axis.iWeights.Reset(); + } + + iGridLayoutData->iAxes.Reset(); + } + + delete iGridLayoutData; + iGridLayoutData = 0; + } + + +EXPORT_C TInt CHuiGridLayout::ChildOrdinal(TInt aIndex) + { + // Use the visual index as ordinal. + return EffectiveLayoutOrdinal(Visual(aIndex)); + } + + +EXPORT_C TPoint CHuiGridLayout::OrdinalToBlock(TInt aOrdinal) const + { + TPoint block(0,0); + TInt cols = ColumnCount(); + TInt rows = RowCount(); + + if (cols && rows) + { + if ( iGridLayoutData->iExpansionFlags & EExpandHorizontally ) + { + block.iX = aOrdinal / rows; + block.iY = aOrdinal % rows; + } + else + { + // By default the flow is vertically + block.iX = aOrdinal % cols; + block.iY = aOrdinal / cols; + } + } + + return block; + } + +EXPORT_C void CHuiGridLayout::SetSize(const THuiRealSize& aSize, TInt aTransitionTime) + { + CHuiLayout::SetSize(aSize, aTransitionTime); + UpdateChildrenLayout(aTransitionTime); + } + +EXPORT_C TBool CHuiGridLayout::ChildSize(TInt aOrdinal, TSize& aSize) + { + TBool result(EFalse); + THuiRealRect rect; + TInt childRectStatus(THuiLayoutChildRectUpdateNotNeeded); + childRectStatus = ChildRect(aOrdinal, rect); + if(childRectStatus != THuiLayoutChildRectNotImplemented) + { + result = (childRectStatus & THuiLayoutChildRectSizeUpdateNeeded); + if(result) + { + THuiRealPoint size(rect.Width(), rect.Height()); + aSize = LocalPointInPixels(size).AsSize(); + } + } + return result; + } + +EXPORT_C TBool CHuiGridLayout::ChildPos(TInt aOrdinal, TPoint& aPos) + { + TBool result(EFalse); + THuiRealRect rect; + TInt childRectStatus(THuiLayoutChildRectUpdateNotNeeded); + childRectStatus = ChildRect(aOrdinal, rect); + if(childRectStatus != THuiLayoutChildRectNotImplemented) + { + result = (childRectStatus & THuiLayoutChildRectPosUpdateNeeded); + if(result) + { + aPos = LocalPointInPixels(rect.iTl); + } + } + return result; + } + + +EXPORT_C TInt CHuiGridLayout::ChildRect(TInt aOrdinal, THuiRealRect& aPos) + { + if (!ColumnCount() || !RowCount()) + { + return THuiLayoutChildRectUpdateNotNeeded; + } + + // @todo refactorize with CHuiLayout::InnerSize + THuiRealRect paddingPx = PaddingInPixels(EHuiReferenceStateTarget); + + // find the inner border and remove the inner paddings + THuiRealPoint innerSizePx = LocalPointInPixels(Size().RealTarget(), EHuiReferenceStateTarget); + innerSizePx.iX -= paddingPx.iTl.iX + paddingPx.iBr.iX; + innerSizePx.iY -= paddingPx.iTl.iY + paddingPx.iBr.iY; + + // subtract the inner padding (space between each child). + THuiRealPoint innerPaddingPx = MetricToPixels(InnerPadding(), EHuiReferenceStateTarget); + + THuiRealPoint availablePx(innerSizePx.iX - ((ColumnCount() - 1) * innerPaddingPx.iX), + innerSizePx.iY - ((RowCount() - 1) * innerPaddingPx.iY)); + + TPoint blockLogical = OrdinalToBlock(aOrdinal); + TPoint blockPosPx; + TSize blockSizePx; + + CalculateCellInPixels(EHuiGridColumn, blockLogical.iX, availablePx.iX, blockPosPx.iX, blockSizePx.iWidth); + CalculateCellInPixels(EHuiGridRow, blockLogical.iY, availablePx.iY, blockPosPx.iY, blockSizePx.iHeight); + + // now add back in the inner paddings and the padding + blockPosPx.iX += HUI_ROUND_FLOAT_TO_INT( paddingPx.iTl.iX + (blockLogical.iX * innerPaddingPx.iX) ); + blockPosPx.iY += HUI_ROUND_FLOAT_TO_INT( paddingPx.iTl.iY + (blockLogical.iY * innerPaddingPx.iY) ); + + // get metric reference, for converting between base units of this layout (from the child visual's perspective) and pixels + THuiRealPoint layoutRefPx = MetricReferenceForLayoutInPixels(BaseUnit().Abs()); // always target reference + + // Convert the result back into child relative coordinates + THuiXYMetric blockPosChildMetric = BaseUnit(); + THuiXYMetric blockSizeChildMetric = BaseUnit(); + + ConvertPixelsToMetricLength(blockPosChildMetric.iX, TReal32(blockPosPx.iX), layoutRefPx.iX); + ConvertPixelsToMetricLength(blockPosChildMetric.iY, TReal32(blockPosPx.iY), layoutRefPx.iY); + ConvertPixelsToMetricLength(blockSizeChildMetric.iX, TReal32(blockSizePx.iWidth), layoutRefPx.iX); + ConvertPixelsToMetricLength(blockSizeChildMetric.iY, TReal32(blockSizePx.iHeight), layoutRefPx.iY); + + aPos.iTl.iX = blockPosChildMetric.iX.iMagnitude; + aPos.iTl.iY = blockPosChildMetric.iY.iMagnitude; + aPos.iBr.iX = aPos.iTl.iX + blockSizeChildMetric.iX.iMagnitude; + aPos.iBr.iY = aPos.iTl.iY + blockSizeChildMetric.iY.iMagnitude; + + return THuiLayoutChildRectLayoutUpdateNeeded; + } + + +EXPORT_C void CHuiGridLayout::SetColumnsL(TInt aColumnCount) + { + THuiMetric defaultWeight(1.f, EHuiUnitWeight); + FillWeightsL(EHuiGridColumn, aColumnCount, defaultWeight); + } + + +EXPORT_C void CHuiGridLayout::SetRowsL(TInt aRowCount) + { + THuiMetric defaultWeight(1.f, EHuiUnitWeight); + FillWeightsL(EHuiGridRow, aRowCount, defaultWeight); + } + + +EXPORT_C void CHuiGridLayout::SetColumnsL(const RArray& aWeights) + { + TAxis& axis = iGridLayoutData->iAxes[EHuiGridColumn]; + axis.iWeights.Reset(); + for(TInt i = 0; i < aWeights.Count(); ++i) + { + THuiMetric weight(TReal32(aWeights[i]), EHuiUnitWeight); + User::LeaveIfError(axis.iWeights.Append(weight)); + } + } + +EXPORT_C void CHuiGridLayout::SetRowsL(const RArray& aWeights) + { + TAxis& axis = iGridLayoutData->iAxes[EHuiGridRow]; + axis.iWeights.Reset(); + for(TInt i = 0; i < aWeights.Count(); ++i) + { + THuiMetric weight(TReal32(aWeights[i]), EHuiUnitWeight); + User::LeaveIfError(axis.iWeights.Append(weight)); + } + } + +EXPORT_C void CHuiGridLayout::FillWeightsL(THuiGridDimension aDim, TInt aCount, const THuiMetric& aWeight) + { + if(aDim <= EHuiGridRow) + { + TAxis& axis = iGridLayoutData->iAxes[aDim]; + axis.iWeights.Reset(); + for(TInt i = 0; i < aCount; ++i) + { + User::LeaveIfError(axis.iWeights.Append(aWeight)); + } + } + } + +EXPORT_C void CHuiGridLayout::AppendWeightL(THuiGridDimension aDim, const THuiMetric& aWeight) + { + if(aDim <= EHuiGridRow) + { + TAxis& axis = iGridLayoutData->iAxes[aDim]; + User::LeaveIfError(axis.iWeights.Append(aWeight)); + } + } + +EXPORT_C void CHuiGridLayout::InsertWeightL(THuiGridDimension aDim, const THuiMetric& aWeight, TInt aPos) + { + if(aDim <= EHuiGridRow) + { + TAxis& axis = iGridLayoutData->iAxes[aDim]; + if(aPos < 0 || aPos >= axis.iWeights.Count()) + { + User::Leave(KErrArgument); + } + else + { + User::LeaveIfError(axis.iWeights.Insert(aWeight, aPos)); + } + } + } + +EXPORT_C void CHuiGridLayout::ReplaceWeightL(THuiGridDimension aDim, const THuiMetric& aWeight, TInt aPos) + { + if(aDim <= EHuiGridRow) + { + TAxis& axis = iGridLayoutData->iAxes[aDim]; + if(aPos < 0 || aPos >= axis.iWeights.Count()) + { + User::Leave(KErrArgument); + } + else + { + axis.iWeights[aPos] = aWeight; + } + } + } + +EXPORT_C void CHuiGridLayout::RemoveWeightL(THuiGridDimension aDim, TInt aPos) + { + if(aDim <= EHuiGridRow) + { + TAxis& axis = iGridLayoutData->iAxes[aDim]; + if(aPos < 0 || aPos >= axis.iWeights.Count()) + { + User::Leave(KErrArgument); + } + else + { + axis.iWeights.Remove(aPos); + } + } + } + +EXPORT_C THuiMetric CHuiGridLayout::Weight(THuiGridDimension aDim, TInt aPos) const + { + THuiMetric metric(0.f, EHuiUnitWeight); + if(aDim <= EHuiGridRow) + { + TAxis& axis = iGridLayoutData->iAxes[aDim]; + if(aPos < 0 || aPos >= axis.iWeights.Count()) + { + // use empty weight + } + else + { + metric = axis.iWeights[aPos]; + } + } + return metric; + } + +EXPORT_C TInt CHuiGridLayout::DimensionCount(THuiGridDimension aDim) const + { + TInt count = 0; + if(aDim <= EHuiGridRow) + { + count = iGridLayoutData->iAxes[aDim].iWeights.Count(); + } + return count; + } + +EXPORT_C void CHuiGridLayout::SetExpanding(TInt aFlags) + { + iGridLayoutData->iExpansionFlags = aFlags; + } + +// --------------------------------------------------------------------------- +// Function that determines if the filling order. +// --------------------------------------------------------------------------- +// +TBool CHuiGridLayout::UseRightToLeftFillingOrder() const + { + return CHuiStatic::LayoutMirrored(); + } + +EXPORT_C void CHuiGridLayout::GetClassName(TDes& aName) const + { + aName = _L("CHuiGridLayout"); + } + +EXPORT_C THuiXYMetric CHuiGridLayout::BaseUnit() const + { + return CHuiLayout::BaseUnit(); + } + +EXPORT_C CHuiVisual* CHuiGridLayout::FindTag(const TDesC8& aTag) + { + return CHuiLayout::FindTag(aTag); + } + +EXPORT_C TInt CHuiGridLayout::Count() const + { + return CHuiLayout::Count(); + } + +EXPORT_C CHuiVisual& CHuiGridLayout::Visual(TInt aIndex) const + { + return CHuiLayout::Visual(aIndex); + } + +EXPORT_C void CHuiGridLayout::SetPos(const THuiRealPoint& aPos, TInt aTransitionTime) + { + CHuiLayout::SetPos(aPos, aTransitionTime); + } + +EXPORT_C void CHuiGridLayout::UpdateChildrenLayout(TInt aTransitionTime) + { + CHuiLayout::UpdateChildrenLayout(aTransitionTime); + } + +EXPORT_C TBool CHuiGridLayout::PrepareDrawL() + { + return CHuiLayout::PrepareDrawL(); + } + +EXPORT_C void CHuiGridLayout::Draw(CHuiGc& aGc) const + { + CHuiLayout::Draw(aGc); + } + +EXPORT_C void CHuiGridLayout::DrawSelf(CHuiGc& aGc, const TRect& aDisplayRect) const + { + CHuiLayout::DrawSelf(aGc, aDisplayRect); + } + +EXPORT_C TBool CHuiGridLayout::Changed() const + { + return CHuiLayout::Changed(); + } + +EXPORT_C void CHuiGridLayout::ReportChanged() + { + CHuiLayout::ReportChanged(); + } + +EXPORT_C void CHuiGridLayout::ClearChanged() + { + CHuiLayout::ClearChanged(); + } + +EXPORT_C void CHuiGridLayout::NotifySkinChangedL() + { + CHuiLayout::NotifySkinChangedL(); + } + +EXPORT_C void CHuiGridLayout::ExpandRectWithContent(TRect& aRect) const + { + CHuiLayout::ExpandRectWithContent(aRect); + } + +EXPORT_C void CHuiGridLayout::VisualExtension(const TUid& aExtensionUid, TAny** aExtensionParams) + { + CHuiLayout::VisualExtension(aExtensionUid, aExtensionParams); + } + +EXPORT_C void CHuiGridLayout::DumpTree() const + { + CHuiLayout::DumpTree(); + } + +EXPORT_C void CHuiGridLayout::GetInstanceName(TDes& aName) const + { + CHuiLayout::GetInstanceName(aName); + } + +EXPORT_C void CHuiGridLayout::RemoveAndDestroyAllD() + { + CHuiLayout::RemoveAndDestroyAllD(); + } + +HUI_SESSION_OBJECT_IMPL_EXPORT(CHuiGridLayout, ETypeVisual) + + +EXPORT_C TInt CHuiGridLayout::RowCount() const + { + return iGridLayoutData->iAxes[EHuiGridRow].iWeights.Count(); + } + +EXPORT_C TInt CHuiGridLayout::ColumnCount() const + { + return iGridLayoutData->iAxes[EHuiGridColumn].iWeights.Count(); + } + + +EXPORT_C void CHuiGridLayout::SetLayoutModeFlags(THuiGridDimension aDim, TUint aGridLayoutModeFlags) + { + if(aDim <= EHuiGridRow) + { + TAxis& axis = iGridLayoutData->iAxes[aDim]; + TUint oldFlags = axis.iLayoutFlags; + + + // The following flags are mutually exclusive, clear existing flags first + if (aGridLayoutModeFlags&EHuiGridIncreaseInnerPadding) + { + axis.iLayoutFlags &= ~EHuiGridDecreaseInnerPadding; + } + + if (aGridLayoutModeFlags&EHuiGridDecreaseInnerPadding) + { + axis.iLayoutFlags &= ~EHuiGridIncreaseInnerPadding; + } + + if (aGridLayoutModeFlags&EHuiGridIncreaseOuterPadding) + { + axis.iLayoutFlags &= ~EHuiGridDecreaseOuterPadding; + } + + if (aGridLayoutModeFlags&EHuiGridDecreaseOuterPadding) + { + axis.iLayoutFlags &= ~EHuiGridIncreaseOuterPadding; + } + + axis.iLayoutFlags |= aGridLayoutModeFlags; + + if((oldFlags != axis.iLayoutFlags) && !(Flags() & EHuiVisualFlagFreezeLayout)) + { + UpdateChildrenLayout(0); + } + } + } + +EXPORT_C void CHuiGridLayout::ClearLayoutModeFlags(THuiGridDimension aDim, TUint aGridLayoutModeFlags) + { + if(aDim <= EHuiGridRow) + { + TAxis& axis = iGridLayoutData->iAxes[aDim]; + TUint oldFlags = axis.iLayoutFlags; + axis.iLayoutFlags &= ~aGridLayoutModeFlags; + + if((oldFlags != axis.iLayoutFlags) && !(Flags() & EHuiVisualFlagFreezeLayout)) + { + UpdateChildrenLayout(0); + } + } + } + +EXPORT_C TUint CHuiGridLayout::LayoutModeFlags(THuiGridDimension aDim) + { + if(aDim <= EHuiGridRow) + { + TAxis& axis = iGridLayoutData->iAxes[aDim]; + return axis.iLayoutFlags; + } + + return 0; + } + +void CHuiGridLayout::CalculateCellInPixels( + THuiGridDimension aDim, + TInt aIndex, + TReal32 aAvailablePixels, + TInt& aPos, + TInt& aSize) const + { + ASSERT(aDim < EHuiGridSize); + + TAxis& axis = iGridLayoutData->iAxes[aDim]; + TInt numItems = (aDim==EHuiGridColumn)?ColumnCount():RowCount(); + TInt itemIntegerWidths = 0; + TInt itemCeilingedIntegerWidths = 0; + TReal32 realPos; + TReal32 realSize; + TInt sumIntegerWidths; + TInt sumCeilingIntegerWidths; + TReal32 layoutWidthPx; + TReal32 layoutSizePx; + + CalculateCellInPixelsReal(aDim, aIndex, aAvailablePixels, realPos, realSize, itemIntegerWidths, itemCeilingedIntegerWidths); + + TReal32 innerPadPos = realPos; + + // Decide what to do with pixel error based on flags + if (axis.iLayoutFlags&EHuiGridDecreaseInnerPadding) + { + // Allow every item to grow out into the padding, this will make the padding appear smaller. + realSize = CEIL(realSize); + } + else if (axis.iLayoutFlags&EHuiGridIncreaseInnerPadding) + { + // Allow every item to be floored, this will make the padding appear bigger. + realSize = FLOOR(realSize); + } + else + { + // For PC-lint + } + + if (axis.iLayoutFlags&EHuiGridIncreaseOuterPadding) + { + // Ignore accumulated error, simply increase outer padding by the total error for the entire layout. + + // Ignore the rounded positions we have calculated, we get the pos by summing the integer widths, + realPos = itemIntegerWidths-FLOOR_INT(realSize); + + CalculateCellInPixelsReal(aDim, numItems-1, aAvailablePixels, layoutWidthPx, layoutSizePx, sumIntegerWidths, sumCeilingIntegerWidths); + realPos += (aAvailablePixels-sumIntegerWidths)/2; + realSize = FLOOR(realSize); + } + else if (axis.iLayoutFlags&EHuiGridDecreaseOuterPadding) + { + // Ignore accumulated error, simply decrease outer padding by the total error for the entire layout. + + // Ignore the rounded positions we have calculated, we get the pos by summing the integer widths, + realPos = itemCeilingedIntegerWidths-CEIL_INT(realSize); + + CalculateCellInPixelsReal(aDim, numItems-1, aAvailablePixels, layoutWidthPx, layoutSizePx, sumIntegerWidths, sumCeilingIntegerWidths); + realPos += (aAvailablePixels-sumCeilingIntegerWidths)/2; + realSize = CEIL(realSize); + } + else + { + // For PC-lint + } + + realPos = ProportionalInnerOuterPadding(aDim, innerPadPos, realPos); + + aPos = TInt(realPos); + aSize = TInt(realSize); + } + +TReal32 CHuiGridLayout::ProportionalInnerOuterPadding( + THuiGridDimension aDim, + TReal32 aInnerPadPos, + TReal32 aOuterPadPos) const + { + THuiRealPoint innerPaddingPx = MetricToPixels(InnerPadding(), EHuiReferenceStateTarget); + THuiRealRect outerPaddingPx = PaddingInPixels(EHuiReferenceStateTarget); + TAxis& axis = iGridLayoutData->iAxes[aDim]; + TUint flag = axis.iLayoutFlags; + TReal32 totalPadding; + TReal32 meanOuterPadding; + + if ( HuiUtil::RealCompare( aInnerPadPos, aOuterPadPos ) ) + { + // Same pos, nothing to do. + return aOuterPadPos; + } + + if (aDim==EHuiGridColumn) + { + meanOuterPadding = (outerPaddingPx.iTl.iX+outerPaddingPx.iBr.iX)/2.0f; + totalPadding = innerPaddingPx.iX+meanOuterPadding; + } + else + { + meanOuterPadding = (outerPaddingPx.iTl.iY+outerPaddingPx.iBr.iY)/2.0f; + totalPadding = innerPaddingPx.iY+meanOuterPadding; + } + + if (totalPadding && ((flag&EHuiGridIncreaseInnerPadding) && (flag&EHuiGridIncreaseOuterPadding)) + || ((flag&EHuiGridIncreaseInnerPadding) && (flag&EHuiGridDecreaseOuterPadding)) + || ((flag&EHuiGridDecreaseInnerPadding) && (flag&EHuiGridIncreaseOuterPadding)) + || ((flag&EHuiGridDecreaseInnerPadding) && (flag&EHuiGridDecreaseOuterPadding))) + { + // Both inner and outer padding flags are active, linearly interpolate between them based on ratio. + if (aDim==EHuiGridColumn) + { + return ((innerPaddingPx.iX*aInnerPadPos + meanOuterPadding*aOuterPadPos)/totalPadding); + } + else + { + return ((innerPaddingPx.iY*aInnerPadPos + meanOuterPadding*aOuterPadPos)/totalPadding); + } + } + + return aOuterPadPos; + } + + +void CHuiGridLayout::CalculateCellInPixelsReal( + THuiGridDimension aDim, + TInt aIndex, + TReal32 aAvailablePixels, + TReal32& aPos, + TReal32& aSize, + TInt& aFloorPixelPos, + TInt& aCeilingPixelPos) const + { + // note that we will add in the inner padding later + // total up the pixels or weights on either side of the target block, so that we know what + // the total size is that we're sharing out by weight. + // while we're at it we can remember the size of the target block as well (call it "mid") + TReal32 totalWeightsValid(0.f); + TReal32 totalPixelsValid(0.f); + TReal32 error(0.f); + TInt pixelWeight; + TReal32 weightWeight; + + TAxis& axis = iGridLayoutData->iAxes[aDim]; + TInt weightCount = axis.iWeights.Count(); + + aPos = 0; + aSize = 0; + aFloorPixelPos = 0; + aCeilingPixelPos = 0; + + // First pass to get total weights and pixels. + for(TInt ii = 0; ii < weightCount; ii++) + { + THuiMetric& weight = axis.iWeights[ii]; + + WeightFromMetric(aDim, weight, weightWeight, pixelWeight); + totalPixelsValid += pixelWeight; + totalWeightsValid += weightWeight; + } + + // All the fixed-pixel items have been accounted for, this is + // what's left for distribution between the variable, weighted items. + TReal32 remainderPixels = aAvailablePixels - totalPixelsValid; + + // Second pass to calculate size and pos + for(TInt ii = 0; ii <= aIndex; ii++) + { + TReal32 nextWeight(0.f); + TReal32 nextPixels(0.f); + + // Child visuals that are outside of the specified range of blocks + // should take the weight of the last specified block. + THuiMetric weight(1.f, EHuiUnitWeight); + if(ii < weightCount) + { + weight = axis.iWeights[ii]; + } + else if( weightCount ) // return weight of last element + { + weight = axis.iWeights[weightCount-1]; + } + else + { + // For PC-lint + } + + WeightFromMetric(aDim, weight, nextWeight, pixelWeight); + nextPixels += pixelWeight; + + TReal32 width; + if(totalWeightsValid != 0) + { + width = (nextWeight / totalWeightsValid) * remainderPixels; + } + else + { + width = 0; + } + + aFloorPixelPos += FLOOR_INT(width); + aCeilingPixelPos += CEIL_INT(width); + aFloorPixelPos += nextPixels; + aCeilingPixelPos += nextPixels; + + error += FRAC(width); + + if ((axis.iLayoutFlags == 0)) + { + if (error >= 0.5) + { + // There is a rounding error here, so increase size if no flags forcing exact-size are set + error--; + width = CEIL(width); + } + else + { + width = FLOOR(width); + } + } + + if(ii < aIndex) + { + aPos += width; + aPos += nextPixels; + } + else + { + aSize += width; + aSize += nextPixels; + } + } + } + +void CHuiGridLayout::WeightFromMetric(THuiGridDimension aDim, THuiMetric& aMetric, TReal32& aWeight, TInt& aPix) const + { + aWeight = 0.0f; + aPix = 0; + + switch(aMetric.iUnit) + { + case EHuiUnitWeight: + { + aWeight = aMetric.iMagnitude; + break; + } + case EHuiUnitPixel: + { + // slight optimization here as we know it's pixels + aPix = HUI_ROUND_FLOAT_TO_INT(aMetric.iMagnitude); + break; + } + case EHuiUnitNormalized: + case EHuiUnitRelativeToDisplay: + case EHuiUnitRelativeToMySize: + case EHuiUnitS60: + { + THuiRealPoint refPx = MetricToPixels(THuiXYMetric(aMetric), EHuiReferenceStateTarget); + aPix = (aDim == EHuiGridColumn) ? HUI_ROUND_FLOAT_TO_INT(refPx.iX) : HUI_ROUND_FLOAT_TO_INT(refPx.iY); + break; + } + default: + break; + } + }