uiacceltk/hitchcock/coretoolkit/src/HuiAnchorLayout.cpp
changeset 0 15bf7259bb7c
child 3 d8a3531bc6b8
equal deleted inserted replaced
-1:000000000000 0:15bf7259bb7c
       
     1 /*
       
     2 * Copyright (c) 2006-2007 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:   Implementation for CHuiAnchorLayout. Anchor layouts 
       
    15 *                allow specifying the placement of child visuals using 
       
    16 *                anchors, that can be relative or absolute coordinates and 
       
    17 *                attached to a specific edge of the layout.
       
    18 *
       
    19 */
       
    20 
       
    21 
       
    22 
       
    23 #include "uiacceltk/HuiAnchorLayout.h"  // Class definition
       
    24 #include "uiacceltk/HuiControl.h"
       
    25 #include "uiacceltk/HuiPanic.h"
       
    26 #include "uiacceltk/HuiUtil.h"
       
    27 
       
    28 //
       
    29 // Private structures
       
    30 //
       
    31 
       
    32 /*
       
    33  * Anchor that defines an edge's position and/or size. 
       
    34  */
       
    35 struct CHuiAnchorLayout::TEdgeAnchor
       
    36     {
       
    37     THuiAnchorProximity iEdgeProximity;
       
    38     THuiMetric iOffset;
       
    39     THuiAnchorProximity iAttachmentProximity;
       
    40     TInt iAttachmentOrdinal;
       
    41     };
       
    42 
       
    43 /* 
       
    44  * an axis can contain up to two edges
       
    45  */
       
    46 struct CHuiAnchorLayout::TAxis
       
    47     {
       
    48 public:
       
    49     inline TInt Edge(THuiAnchorProximity aEdgeProximity, TEdgeAnchor*& aEdge) const;
       
    50     inline TInt AddEdge(THuiAnchorProximity aEdgeProximity, TEdgeAnchor*& aEdge);
       
    51     
       
    52 public:
       
    53     /** array of edges */
       
    54     TFixedArray<TEdgeAnchor, 2> iEdges;
       
    55     };
       
    56 
       
    57 inline TInt CHuiAnchorLayout::TAxis::Edge(THuiAnchorProximity aEdgeProximity, TEdgeAnchor*& aEdge) const
       
    58     {
       
    59     TInt error = KErrNotFound;
       
    60     TInt count = iEdges.Count();
       
    61     for(TInt ii = 0; ii < count && error == KErrNotFound ; ii++)
       
    62         {
       
    63         if(iEdges[ii].iEdgeProximity == aEdgeProximity)
       
    64             {
       
    65             aEdge = const_cast<TEdgeAnchor*>(&(iEdges[ii])); // uses the const operator[] as this is a const method
       
    66             error = KErrNone;
       
    67             }
       
    68         }
       
    69     return error;
       
    70     }
       
    71 
       
    72 TInt CHuiAnchorLayout::TAxis::AddEdge(THuiAnchorProximity aEdgeProximity, TEdgeAnchor*& aEdge)
       
    73     {
       
    74     TInt error = Edge(aEdgeProximity, aEdge);
       
    75     if(error == KErrNotFound)
       
    76         {
       
    77         // we haven't found the one we're looking for, so now look for an empty slot
       
    78         error = Edge(EHuiAnchorProximityNone, aEdge);
       
    79         if(error == KErrNotFound)
       
    80             {
       
    81             // couldn't find an empty slot, so actually we consider that to be an overflow
       
    82             error = KErrOverflow;
       
    83             }
       
    84         }
       
    85     return error;
       
    86     }
       
    87 
       
    88 
       
    89 /*
       
    90  * axes for a given anchor. 
       
    91  *
       
    92  */
       
    93 struct CHuiAnchorLayout::TAnchor
       
    94     {
       
    95 public:
       
    96     TAxis& Axis(THuiAnchorAxis aAxis) const;
       
    97     
       
    98 public:
       
    99     /** 
       
   100      * array of axes indexed by THuiAnchorAxis, each one contains the edges for a given axis
       
   101      */
       
   102     TFixedArray<TAxis, 2> iAxes;
       
   103     };
       
   104 
       
   105 CHuiAnchorLayout::TAxis& CHuiAnchorLayout::TAnchor::Axis(THuiAnchorAxis aAxis) const
       
   106     {
       
   107     // index is an enumeration and cannot go outside array boundaries.
       
   108     return const_cast<CHuiAnchorLayout::TAxis&>(iAxes[aAxis]);
       
   109     }
       
   110 
       
   111 
       
   112 /*
       
   113  * Internal private data struct.
       
   114  */
       
   115 struct CHuiAnchorLayout::THuiAnchorLayoutPrivateData
       
   116     {
       
   117 public:
       
   118     THuiAnchorLayoutPrivateData();
       
   119     
       
   120 public:
       
   121     /*
       
   122      * Anchors for a given axis, indexed by ordinal. 
       
   123      * @note that if an ordinal is used that is outside the current size of the 
       
   124      * array, then empty items will be filled in up to the ordinal needed. However,
       
   125      * in general ordinals will correspond to indexes of visuals within the layout, 
       
   126      * and therefore we shouldn't expect unreasonable growth of anchors.
       
   127      */
       
   128     RArray<TAnchor> iAnchors;
       
   129     };
       
   130 
       
   131 CHuiAnchorLayout::THuiAnchorLayoutPrivateData::THuiAnchorLayoutPrivateData()
       
   132     {
       
   133     }
       
   134 
       
   135 
       
   136 
       
   137 //
       
   138 // Methods for compatibility with deprecated APIs
       
   139 //
       
   140 
       
   141 THuiAnchorType CHuiAnchorLayout::ConvertDeprecatedAnchorTypeToType(THuiAnchor aAnchor) const
       
   142     {
       
   143     THuiAnchorType type;
       
   144     switch(aAnchor)
       
   145         {
       
   146         case EHuiAnchorTopLeft:
       
   147             type = EHuiAnchorTypeTopLeft;
       
   148             break;
       
   149         case EHuiAnchorBottomRight:
       
   150             type = EHuiAnchorTypeBottomRight;
       
   151             break;
       
   152         default:
       
   153             type = EHuiAnchorTypeNone;
       
   154             break;
       
   155         }
       
   156     return type;
       
   157     }
       
   158     
       
   159 THuiAnchorAttachmentOrigin CHuiAnchorLayout::ConvertDeprecatedOrginToAttachmentOrigin(THuiAnchorOrigin aOrigin) const
       
   160     {
       
   161     THuiAnchorAttachmentOrigin origin;
       
   162     switch(aOrigin)
       
   163         {
       
   164         case EHuiAnchorOriginLeft:
       
   165             origin = EHuiAnchorAttachmentOriginLeft;
       
   166             break;
       
   167         case EHuiAnchorOriginHCenter:
       
   168             origin = EHuiAnchorAttachmentOriginHCenter;
       
   169             break;
       
   170         case EHuiAnchorOriginRight:
       
   171             origin = EHuiAnchorAttachmentOriginRight;
       
   172             break;
       
   173         case EHuiAnchorOriginTop:
       
   174             origin = EHuiAnchorAttachmentOriginTop;
       
   175             break;
       
   176         case EHuiAnchorOriginVCenter:
       
   177             origin = EHuiAnchorAttachmentOriginVCenter;
       
   178             break;
       
   179         case EHuiAnchorOriginBottom:
       
   180             origin = EHuiAnchorAttachmentOriginBottom;
       
   181             break;
       
   182         default:
       
   183             origin = EHuiAnchorAttachmentOriginNone;
       
   184             break;
       
   185         }
       
   186     return origin;
       
   187     }
       
   188 
       
   189 THuiAnchorAttachmentOrigin CHuiAnchorLayout::ConvertDeprecatedOriginsToAttachmentOrigin(THuiAnchorOrigin aHorizOrigin, THuiAnchorOrigin aVertOrigin) const
       
   190     {
       
   191     THuiAnchorAttachmentOrigin newHorizAttachmentOrigin = ConvertDeprecatedOrginToAttachmentOrigin(aHorizOrigin);
       
   192     THuiAnchorAttachmentOrigin newVertAttachmentOrigin = ConvertDeprecatedOrginToAttachmentOrigin(aVertOrigin);
       
   193     THuiAnchorAttachmentOrigin origin = THuiAnchorAttachmentOrigin(newHorizAttachmentOrigin | newVertAttachmentOrigin);
       
   194     return origin;
       
   195     }
       
   196 
       
   197 THuiMetric CHuiAnchorLayout::ConvertDeprecatedAnchorMetricAndTargetToHuiMetric(THuiAnchorMetric aMetric, TReal32 aTarget) const
       
   198     {
       
   199     THuiUnit unit;
       
   200     switch(aMetric)
       
   201         {
       
   202         case EHuiAnchorMetricAbsolute:
       
   203             unit = EHuiUnitPixel;
       
   204             break;
       
   205         case EHuiAnchorMetricRelativeToSize:
       
   206             unit = EHuiUnitRelativeToMySize;
       
   207             break;
       
   208         default:
       
   209             unit = EHuiUnitPixel;
       
   210             break;
       
   211         }
       
   212     THuiMetric metric(aTarget, unit);
       
   213     return metric;
       
   214     }
       
   215 
       
   216 THuiXYMetric CHuiAnchorLayout::ConvertDeprecatedAnchorMetricsAndOffsetToHuiMetric(
       
   217     THuiAnchorMetric aHorizMetric,
       
   218     THuiAnchorMetric aVertMetric,
       
   219     const THuiTimedPoint& aOffset) const
       
   220     {
       
   221     TReal32 horizTarget = aOffset.iX.Target();
       
   222     TReal32 vertTarget = aOffset.iY.Target();
       
   223     
       
   224     THuiMetric horizMetric = ConvertDeprecatedAnchorMetricAndTargetToHuiMetric(aHorizMetric, horizTarget);
       
   225     THuiMetric vertMetric = ConvertDeprecatedAnchorMetricAndTargetToHuiMetric(aVertMetric, vertTarget);
       
   226     
       
   227     THuiXYMetric metric(horizMetric, vertMetric);
       
   228     return metric;
       
   229     }
       
   230 
       
   231 //
       
   232 // Methods for dealing with internal data types
       
   233 //
       
   234 
       
   235 THuiAnchorProximity CHuiAnchorLayout::ConvertTypeToProximity(THuiAnchorType aType, THuiAnchorAxis& aAxis) const
       
   236     {
       
   237     THuiAnchorProximity proximity;
       
   238     
       
   239     THuiAnchorProximity proximityH = THuiAnchorProximity((aType & EHuiAnchorBitmaskHorizontal) >> EHuiAnchorBitmaskShiftHorizontal);
       
   240     THuiAnchorProximity proximityV = THuiAnchorProximity((aType & EHuiAnchorBitmaskVertical) >> EHuiAnchorBitmaskShiftVertical);
       
   241     if(proximityH)
       
   242         {
       
   243         proximity = proximityH;
       
   244         aAxis = EHuiAnchorAxisHorizontal;
       
   245         }
       
   246     else if(proximityV)
       
   247         {
       
   248         proximity = proximityV;
       
   249         aAxis = EHuiAnchorAxisVertical;
       
   250         }
       
   251     else 
       
   252         {
       
   253         proximity = EHuiAnchorProximityNone;
       
   254         }
       
   255     return proximity;
       
   256     }
       
   257 
       
   258 THuiAnchorProximity CHuiAnchorLayout::ConvertAttachmentOriginToProximity(THuiAnchorAttachmentOrigin aAttachmentOrigin, THuiAnchorAxis& aAxis) const
       
   259     {
       
   260     THuiAnchorType type = THuiAnchorType(aAttachmentOrigin);
       
   261     return ConvertTypeToProximity(type, aAxis);
       
   262     }
       
   263 
       
   264 void CHuiAnchorLayout::ConvertCornerToEdges(THuiAnchorType aCorner, THuiAnchorType& aEdgeH, THuiAnchorType& aEdgeV) const
       
   265     {
       
   266     aEdgeH = THuiAnchorType(aCorner & EHuiAnchorBitmaskHorizontal);
       
   267     aEdgeV = THuiAnchorType(aCorner & EHuiAnchorBitmaskVertical);
       
   268     }
       
   269 
       
   270 void CHuiAnchorLayout::ConvertCornerAttachmentOriginToEdgeAttachmentOrigins(THuiAnchorAttachmentOrigin aCornerOrigin, THuiAnchorAttachmentOrigin& aAttachmentOriginH, THuiAnchorAttachmentOrigin& aAttachmentOriginV) const
       
   271     {
       
   272     aAttachmentOriginH = THuiAnchorAttachmentOrigin(aCornerOrigin & EHuiAnchorBitmaskHorizontal);
       
   273     aAttachmentOriginV = THuiAnchorAttachmentOrigin(aCornerOrigin & EHuiAnchorBitmaskVertical);
       
   274     }
       
   275 
       
   276 
       
   277 //
       
   278 // Methods
       
   279 //
       
   280 
       
   281 EXPORT_C CHuiAnchorLayout* CHuiAnchorLayout::AddNewL(CHuiControl& aOwnerControl,
       
   282                                                      CHuiLayout* aParentLayout)
       
   283     {
       
   284     CHuiAnchorLayout* layout = STATIC_CAST(CHuiAnchorLayout*,
       
   285         aOwnerControl.AppendLayoutL(EHuiLayoutTypeAnchor, aParentLayout));
       
   286     return layout;
       
   287     }
       
   288 
       
   289 
       
   290 CHuiAnchorLayout::CHuiAnchorLayout(MHuiVisualOwner& aOwner)
       
   291         : CHuiLayout(aOwner)
       
   292     {
       
   293     }
       
   294 
       
   295 
       
   296 void CHuiAnchorLayout::ConstructL()
       
   297     {
       
   298     CHuiLayout::ConstructL();
       
   299     iHuiAnchorLayoutPrivateData = new (ELeave) THuiAnchorLayoutPrivateData;
       
   300     }
       
   301 
       
   302 
       
   303 EXPORT_C CHuiAnchorLayout::~CHuiAnchorLayout()
       
   304     {
       
   305     Reset();
       
   306     delete iHuiAnchorLayoutPrivateData;
       
   307     }
       
   308 
       
   309 
       
   310 EXPORT_C void CHuiAnchorLayout::Reset()
       
   311     {
       
   312     if ( iHuiAnchorLayoutPrivateData ) // a Fix for OOM situations, tried to dereference NULL pointer
       
   313     	{
       
   314 	    for(TInt ii = EHuiAnchorAxisHorizontal; ii <= EHuiAnchorAxisVertical; ii++)
       
   315 	        {
       
   316 	        iHuiAnchorLayoutPrivateData->iAnchors.Reset();
       
   317 	        }
       
   318     	}
       
   319     }
       
   320 
       
   321 
       
   322 EXPORT_C void CHuiAnchorLayout::SetSize(const THuiRealSize& aSize, TInt aTransitionTime)
       
   323     {
       
   324     CHuiLayout::SetSize(aSize, aTransitionTime);
       
   325     if(!(Flags() & EHuiVisualFlagFreezeLayout))
       
   326         {    
       
   327         UpdateChildrenLayout(aTransitionTime);
       
   328         }
       
   329     }
       
   330 
       
   331 
       
   332 EXPORT_C TBool CHuiAnchorLayout::ChildSize(TInt aOrdinal, TSize& aSize)
       
   333     {
       
   334     TBool result(EFalse);
       
   335     THuiRealRect rect;
       
   336     TInt childRectStatus(THuiLayoutChildRectUpdateNotNeeded);
       
   337     childRectStatus = ChildRect(aOrdinal, rect);
       
   338     if(childRectStatus != THuiLayoutChildRectNotImplemented)
       
   339         {
       
   340         result = (childRectStatus & THuiLayoutChildRectSizeUpdateNeeded);
       
   341         if(result)
       
   342             {
       
   343             THuiRealPoint size(rect.Width(), rect.Height());
       
   344             aSize = LocalPointInPixels(size, EHuiReferenceStateTarget).AsSize();
       
   345             }
       
   346         }
       
   347     return result;
       
   348     }
       
   349     
       
   350 EXPORT_C TBool CHuiAnchorLayout::ChildPos(TInt aOrdinal, TPoint& aPos)
       
   351     {
       
   352     TBool result(EFalse);
       
   353     THuiRealRect rect;
       
   354     TInt childRectStatus(THuiLayoutChildRectUpdateNotNeeded);
       
   355     childRectStatus = ChildRect(aOrdinal, rect);
       
   356     if(childRectStatus != THuiLayoutChildRectNotImplemented)
       
   357         {
       
   358         result = (childRectStatus & THuiLayoutChildRectPosUpdateNeeded);
       
   359         if(result)
       
   360             {
       
   361             aPos = LocalPointInPixels(rect.iTl, EHuiReferenceStateTarget);
       
   362             }
       
   363         }
       
   364     return result;
       
   365     }
       
   366 
       
   367 EXPORT_C TInt CHuiAnchorLayout::ChildRect(TInt aOrdinal, THuiRealRect& aRect)
       
   368     {
       
   369     TInt result(THuiLayoutChildRectUpdateNotNeeded);
       
   370 
       
   371     // split inner area (in pixels) into separate axes
       
   372     TFixedArray<TReal32, 2> tl;
       
   373     TFixedArray<TReal32, 2> br;
       
   374 
       
   375     // evaluate the anchor along each axis in turn
       
   376     if(aOrdinal < iHuiAnchorLayoutPrivateData->iAnchors.Count())
       
   377         {
       
   378         TAnchor& anchor = iHuiAnchorLayoutPrivateData->iAnchors[aOrdinal];
       
   379         for(TInt ii = EHuiAnchorAxisHorizontal; ii <= EHuiAnchorAxisVertical; ii++)
       
   380             {
       
   381             THuiAnchorAxis axisId = THuiAnchorAxis(ii);
       
   382             TAxis& axis = anchor.Axis(axisId);
       
   383             // index is an enumeration and cannot go outside array boundaries
       
   384             result |= EvaluateAxis(axisId, axis, tl[axisId], br[axisId]);
       
   385             }
       
   386         aRect.iTl.iX = tl[EHuiAnchorAxisHorizontal];
       
   387         aRect.iTl.iY = tl[EHuiAnchorAxisVertical];
       
   388         aRect.iBr.iX = br[EHuiAnchorAxisHorizontal];
       
   389         aRect.iBr.iY = br[EHuiAnchorAxisVertical];
       
   390         }
       
   391 
       
   392     if(result == THuiLayoutChildRectUpdateNotNeeded)
       
   393         {
       
   394         // No anchor defined at all. Use the default anchor.
       
   395         THuiRealPoint topLeft = InnerTopLeft();
       
   396         THuiRealSize inner = InnerSize();
       
   397         aRect.iTl = topLeft;
       
   398         aRect.iBr.iX = inner.iWidth;
       
   399         aRect.iBr.iY = inner.iHeight;
       
   400         result = THuiLayoutChildRectLayoutUpdateNeeded;
       
   401         }
       
   402 
       
   403     return result;
       
   404     }
       
   405 
       
   406 
       
   407 /* 
       
   408  * the values from the paddings are in parent base units, whilst the anchor edges have 
       
   409  * their own units, so we must first convert everything to real pixels, then calculate 
       
   410  * the pixel positions, then convert everything back into base units of this layout visual
       
   411  */
       
   412 TInt CHuiAnchorLayout::EvaluateAxis(THuiAnchorAxis aAxisId, const TAxis& aAxis, TReal32& aNear, TReal32& aFar) const
       
   413     {
       
   414     TInt result(THuiLayoutChildRectUpdateNotNeeded);
       
   415     // @todo use cached value if optimization is needed
       
   416 
       
   417     // @todo refactorize with CHuiLayout::InnerSize
       
   418     THuiRealRect paddingRectPx = PaddingInPixels(EHuiReferenceStateTarget);
       
   419     THuiRealPoint sizePointPx = LocalPointInPixels(Size().RealTarget(), EHuiReferenceStateTarget);
       
   420     THuiRealPoint innerPaddingPointPx = MetricToPixels(InnerPadding(), EHuiReferenceStateTarget);
       
   421     
       
   422     // switch to near and far along this axis
       
   423     TReal32 nearPx = (aAxisId == EHuiAnchorAxisHorizontal) ? paddingRectPx.iTl.iX : paddingRectPx.iTl.iY;
       
   424     TReal32 farPaddingPx = (aAxisId == EHuiAnchorAxisHorizontal) ? paddingRectPx.iBr.iX : paddingRectPx.iBr.iY;
       
   425     TReal32 sizePx = (aAxisId == EHuiAnchorAxisHorizontal) ? sizePointPx.iX : sizePointPx.iY;
       
   426     TReal32 farPx = sizePx - farPaddingPx;
       
   427     TReal32 innerPaddingPx= (aAxisId == EHuiAnchorAxisHorizontal) ? innerPaddingPointPx.iX : innerPaddingPointPx.iY;
       
   428 
       
   429     // these will be the calculated values, which we build up one edge at a time
       
   430     TReal32 nearCalculatedPx(nearPx);
       
   431     TReal32 farCalculatedPx(farPx);
       
   432 
       
   433     // we iterate over the edges, but we don't know what order
       
   434     // they were defined, so have to build up the answer as we go
       
   435     TInt count = aAxis.iEdges.Count();
       
   436     for(TInt ii = 0; ii < count; ii++)
       
   437         {
       
   438         const TEdgeAnchor& edge = aAxis.iEdges[ii];
       
   439         if(edge.iEdgeProximity != EHuiAnchorProximityNone)
       
   440             {
       
   441             // now convert this edge anchor's metric offset into pixels
       
   442             TReal32 offsetPx = EdgeOffsetInPixels(aAxisId, edge);
       
   443             result |= EvaluateEdgeAnchorInPixels(aAxisId, edge, innerPaddingPx , offsetPx, nearPx, nearCalculatedPx, farPx, farCalculatedPx);
       
   444             }
       
   445         }
       
   446 
       
   447     // Get metric reference, for converting between base units of this layout (from the child visual's perspective) and pixels.
       
   448     // We must calculate metric reference in both directions, but we only need it along this axis
       
   449     THuiRealPoint childMetricRefSizePx = MetricReferenceForLayoutInPixels(BaseUnit().Abs()); // always target reference
       
   450     TReal32 childMetricRefPx = (aAxisId == EHuiAnchorAxisHorizontal) ? childMetricRefSizePx.iX :childMetricRefSizePx.iY;
       
   451         
       
   452     // Convert the result back into child relative coordinates
       
   453     THuiMetric nearCalculated = (aAxisId == EHuiAnchorAxisHorizontal) ? BaseUnit().iX :BaseUnit().iY;
       
   454     THuiMetric farCalculated(nearCalculated);
       
   455     ConvertPixelsToMetricLength(nearCalculated, nearCalculatedPx, childMetricRefPx);
       
   456     ConvertPixelsToMetricLength(farCalculated, farCalculatedPx, childMetricRefPx);
       
   457 
       
   458     // back to point and size
       
   459     aNear = nearCalculated.iMagnitude; 
       
   460     aFar = farCalculated.iMagnitude;
       
   461 
       
   462     return result;
       
   463     }
       
   464 
       
   465 TReal32 CHuiAnchorLayout::EdgeOffsetInPixels(THuiAnchorAxis aAxisId, const TEdgeAnchor& aEdge) const
       
   466     {
       
   467     THuiRealPoint offsetRefSizePx = MetricReferenceInPixels(THuiXYMetric(aEdge.iOffset), EHuiReferenceStateTarget);
       
   468     TReal32 offsetRefPx = (aAxisId == EHuiAnchorAxisHorizontal) ? offsetRefSizePx.iX :offsetRefSizePx.iY;
       
   469     TReal32 offsetPx(0);
       
   470     ConvertMetricLengthToPixels(offsetPx, aEdge.iOffset, offsetRefPx);
       
   471     return offsetPx;
       
   472     }
       
   473     
       
   474 TInt CHuiAnchorLayout::EvaluateEdgeAnchorInPixels(
       
   475     THuiAnchorAxis aAxisId,
       
   476     const TEdgeAnchor& aEdge,
       
   477     TReal32 aInnerPaddingPx,
       
   478     TReal32 aOffsetPx,
       
   479     TReal32 aNearPx, TReal32& aNearCalculatedPx, 
       
   480     TReal32 aFarPx, TReal32& aFarCalculatedPx) const
       
   481     {
       
   482     TInt result(THuiLayoutChildRectUpdateNotNeeded);
       
   483 
       
   484     // first calculate the offset caused if there is an attached anchor
       
   485     TReal32 attachOriginNearCalculatedPx(aNearPx);
       
   486     TReal32 attachOriginFarCalculatedPx(aFarPx);
       
   487     result |= EvaluateEdgeAttachmentInPixels(aAxisId, aEdge, aInnerPaddingPx, aNearPx, attachOriginNearCalculatedPx, aFarPx, attachOriginFarCalculatedPx);
       
   488     
       
   489     TReal32 origDimensionPx = attachOriginFarCalculatedPx - attachOriginNearCalculatedPx;
       
   490     TReal32 nearOriginTransform = attachOriginNearCalculatedPx - aNearPx;
       
   491     TReal32 farOriginTransform = attachOriginFarCalculatedPx - aFarPx;
       
   492 
       
   493     // Transform to origin
       
   494     switch(aEdge.iAttachmentProximity)
       
   495         {
       
   496         case EHuiAnchorProximitySize:
       
   497             // @todo not yet implemented
       
   498             return(EFalse);
       
   499         case EHuiAnchorProximityNear:
       
   500             nearOriginTransform = 0;
       
   501             farOriginTransform -= origDimensionPx;
       
   502             break;
       
   503         case EHuiAnchorProximityCenter:
       
   504             nearOriginTransform += origDimensionPx / 2;
       
   505             farOriginTransform -= origDimensionPx / 2;
       
   506             break;
       
   507         case EHuiAnchorProximityFar:
       
   508             nearOriginTransform += origDimensionPx;
       
   509             farOriginTransform = 0;
       
   510             break;
       
   511         default:
       
   512             break;
       
   513         }
       
   514 
       
   515     // Apply edge offset.
       
   516     switch(aEdge.iEdgeProximity)
       
   517         {
       
   518         case EHuiAnchorProximitySize:
       
   519             // @todo not yet implemented
       
   520             return(EFalse);
       
   521         case EHuiAnchorProximityNear:
       
   522             aNearCalculatedPx = attachOriginNearCalculatedPx + aOffsetPx + nearOriginTransform;
       
   523             result |= THuiLayoutChildRectPosUpdateNeeded;
       
   524             break;
       
   525         case EHuiAnchorProximityCenter:
       
   526             // @todo not yet implemented
       
   527             return(EFalse);
       
   528         case EHuiAnchorProximityFar:
       
   529             aFarCalculatedPx = attachOriginFarCalculatedPx + aOffsetPx + farOriginTransform;
       
   530             result |= THuiLayoutChildRectSizeUpdateNeeded;
       
   531             break;
       
   532         default:
       
   533             break;
       
   534         }
       
   535 
       
   536     return result;
       
   537     }
       
   538 
       
   539 TInt CHuiAnchorLayout::EvaluateEdgeAttachmentInPixels(
       
   540     THuiAnchorAxis aAxisId,
       
   541     const TEdgeAnchor& aEdge,
       
   542     TReal32 aInnerPaddingPx,
       
   543     TReal32 aNearPx, TReal32& aNearCalculatedPx, 
       
   544     TReal32 aFarPx, TReal32& aFarCalculatedPx) const
       
   545     {
       
   546     TInt result(THuiLayoutChildRectUpdateNotNeeded);
       
   547     
       
   548     // if there is an attachment, follow that
       
   549     if(aEdge.iAttachmentOrdinal != EHuiAnchorAttachToParent)
       
   550         {
       
   551         // retrieve the edge to which we are attached
       
   552         const TAnchor* nextAnchor = Anchor(aEdge.iAttachmentOrdinal); 
       
   553         if(nextAnchor)
       
   554             {
       
   555             // @todo note that with size attachments, the axis id might change here
       
   556             TAxis& nextAxis = nextAnchor->Axis(aAxisId);
       
   557             TEdgeAnchor* nextEdge = NULL;
       
   558             TInt error = nextAxis.Edge(aEdge.iAttachmentProximity, nextEdge);
       
   559             if(error == KErrNone)
       
   560                 {
       
   561                 // now need to calculate near and far for the attached edge
       
   562                 // @todo in the case of size attachments, need to evaluate both next edges
       
   563                 TReal32 nextOffsetPx = EdgeOffsetInPixels(aAxisId, *nextEdge);
       
   564                 TReal32 attachOriginNearCalculatedPx(aNearPx);
       
   565                 TReal32 attachOriginFarCalculatedPx(aFarPx);
       
   566                 result |= EvaluateEdgeAnchorInPixels(aAxisId, *nextEdge, aInnerPaddingPx , nextOffsetPx, aNearPx, attachOriginNearCalculatedPx, aFarPx, attachOriginFarCalculatedPx);
       
   567  
       
   568                 switch(aEdge.iAttachmentProximity)
       
   569                     {
       
   570                     case EHuiAnchorProximitySize:
       
   571                          // @todo not yet implemented
       
   572                         return(EFalse);
       
   573                     case EHuiAnchorProximityNear:
       
   574                         aNearCalculatedPx =  attachOriginNearCalculatedPx + aInnerPaddingPx;
       
   575                         break;
       
   576                     case EHuiAnchorProximityCenter:
       
   577                         aNearCalculatedPx = (attachOriginNearCalculatedPx + attachOriginFarCalculatedPx + aInnerPaddingPx) / 2;
       
   578                         aFarCalculatedPx = aNearCalculatedPx;
       
   579                         break;
       
   580                     case EHuiAnchorProximityFar:
       
   581                         aFarCalculatedPx = attachOriginFarCalculatedPx - aInnerPaddingPx;
       
   582                         break;
       
   583                     default:
       
   584                         break;                    
       
   585                     }
       
   586                 }
       
   587             }
       
   588         }
       
   589     return result;
       
   590     }
       
   591     
       
   592 const CHuiAnchorLayout::TAnchor* CHuiAnchorLayout::Anchor(TInt aOrdinal) const
       
   593     {
       
   594     TAnchor* anchor(NULL);
       
   595     if(aOrdinal < iHuiAnchorLayoutPrivateData->iAnchors.Count())
       
   596         {
       
   597         anchor = &(iHuiAnchorLayoutPrivateData->iAnchors[aOrdinal]);
       
   598         }
       
   599     return anchor;
       
   600     }
       
   601 
       
   602 EXPORT_C TInt CHuiAnchorLayout::SetRelativeAnchorRect
       
   603         (TInt aOrdinal,
       
   604          THuiAnchorOrigin aTlHorizOrigin,
       
   605          THuiAnchorOrigin aTlVertOrigin,
       
   606          const THuiRealPoint& aTopLeftOffset,
       
   607          THuiAnchorOrigin aBrHorizOrigin,
       
   608          THuiAnchorOrigin aBrVertOrigin,
       
   609          const THuiRealPoint& aBottomRightOffset)
       
   610     {
       
   611     // Create top left anchor first
       
   612     TInt error = SetAnchor(
       
   613         EHuiAnchorTopLeft, 
       
   614         aOrdinal, 
       
   615         aTlHorizOrigin, 
       
   616         aTlVertOrigin,
       
   617         EHuiAnchorMetricRelativeToSize, 
       
   618         EHuiAnchorMetricRelativeToSize,
       
   619         THuiTimedPoint(aTopLeftOffset.iX, aTopLeftOffset.iY));
       
   620 
       
   621     // if TL is OK, create BR anchor
       
   622     if ( error == KErrNone )
       
   623         {
       
   624         error = SetAnchor(
       
   625             EHuiAnchorBottomRight, 
       
   626             aOrdinal, 
       
   627             aBrHorizOrigin, 
       
   628             aBrVertOrigin,
       
   629             EHuiAnchorMetricRelativeToSize, 
       
   630             EHuiAnchorMetricRelativeToSize,
       
   631             THuiTimedPoint(aBottomRightOffset.iX, aBottomRightOffset.iY));
       
   632         
       
   633         // If BR fails try to roll back by removing the TL anchor.
       
   634         if ( error != KErrNone )
       
   635             {
       
   636             RemoveAnchor( EHuiAnchorTopLeft, aOrdinal );
       
   637             }
       
   638         }
       
   639     return error;
       
   640     }
       
   641     
       
   642 EXPORT_C TInt CHuiAnchorLayout::SetAnchor(THuiAnchor aAnchor, TInt aOrdinal,
       
   643                                           THuiAnchorOrigin aHorizOrigin,
       
   644                                           THuiAnchorOrigin aVertOrigin,
       
   645                                           THuiAnchorMetric aHorizMetric,
       
   646                                           THuiAnchorMetric aVertMetric,
       
   647                                           const THuiTimedPoint& aOffset)
       
   648     {
       
   649     // convert deprecated API call into new format
       
   650     THuiAnchorType newType = ConvertDeprecatedAnchorTypeToType(aAnchor);
       
   651     THuiAnchorAttachmentOrigin newAttachmentOrigin = ConvertDeprecatedOriginsToAttachmentOrigin(aHorizOrigin, aVertOrigin);
       
   652     THuiXYMetric newOffset = ConvertDeprecatedAnchorMetricsAndOffsetToHuiMetric(aHorizMetric, aVertMetric, aOffset);
       
   653     return Attach(aOrdinal, newType, newOffset, newAttachmentOrigin, EHuiAnchorAttachToParent);
       
   654     }
       
   655 
       
   656 
       
   657 EXPORT_C void CHuiAnchorLayout::RemoveAnchor(THuiAnchor aAnchor, TInt aOrdinal)
       
   658     {
       
   659     // convert deprecated API call into new format
       
   660     THuiAnchorType newType = ConvertDeprecatedAnchorTypeToType(aAnchor);
       
   661     Detach(aOrdinal, newType);
       
   662     }
       
   663 
       
   664 EXPORT_C TInt CHuiAnchorLayout::Attach(
       
   665     TInt aOrdinal,
       
   666     THuiAnchorType aType, 
       
   667     const THuiMetric& aOffset,
       
   668     THuiAnchorAttachmentOrigin aAttachmentOrigin,
       
   669     TInt aAttachmentOrdinal)
       
   670     {
       
   671     TInt error = KErrNone;
       
   672     
       
   673     // ensure that it's an edge
       
   674     THuiAnchorType edgeH;
       
   675     THuiAnchorType edgeV;
       
   676     ConvertCornerToEdges(aType, edgeH, edgeV);
       
   677     TBool bothAxes = (edgeH != EHuiAnchorTypeNone) && (edgeV != EHuiAnchorTypeNone);
       
   678     if(bothAxes)
       
   679             {
       
   680         return KErrArgument;
       
   681             }
       
   682     
       
   683     THuiAnchorAxis axisId(EHuiAnchorAxisHorizontal);
       
   684     THuiAnchorProximity edgeProximity = ConvertTypeToProximity(aType, axisId);
       
   685     THuiAnchorProximity attachmentProximity = ConvertAttachmentOriginToProximity(aAttachmentOrigin, axisId);
       
   686 
       
   687     // size currently not supported, center only supported for attachment proximity
       
   688     TBool sizeProx = (edgeProximity == EHuiAnchorProximitySize) || (attachmentProximity == EHuiAnchorProximitySize);
       
   689     TBool centerProx = (edgeProximity == EHuiAnchorProximityCenter);
       
   690     if(sizeProx || centerProx)
       
   691         {
       
   692         return KErrArgument;
       
   693         }
       
   694 
       
   695     // avoid issue of Anchor() returning pointer to const
       
   696     TAnchor* anchor(NULL);
       
   697     TInt count = iHuiAnchorLayoutPrivateData->iAnchors.Count();
       
   698     if(aOrdinal < count)
       
   699         {
       
   700         anchor = &(iHuiAnchorLayoutPrivateData->iAnchors[aOrdinal]);
       
   701         }
       
   702     else
       
   703         {
       
   704         // Create a new anchor. Fill any gaps.
       
   705         for(TInt ii = count; ii <= aOrdinal; ii++)
       
   706             {
       
   707             TInt appendError = iHuiAnchorLayoutPrivateData->iAnchors.Append(TAnchor());
       
   708             if ( appendError != KErrNone )
       
   709                 {
       
   710                 return appendError;
       
   711                 }
       
   712             anchor = &(iHuiAnchorLayoutPrivateData->iAnchors[ii]);
       
   713             Mem::FillZ(anchor, sizeof(*anchor));
       
   714             }
       
   715         }
       
   716         
       
   717     TEdgeAnchor* edge(NULL);
       
   718     TAxis& axis = anchor->Axis(axisId);
       
   719     error = axis.AddEdge(edgeProximity, edge);
       
   720     if(error == KErrNone)
       
   721         {
       
   722         edge->iEdgeProximity = edgeProximity;
       
   723         edge->iOffset = aOffset;
       
   724         edge->iAttachmentProximity = attachmentProximity;
       
   725         edge->iAttachmentOrdinal = aAttachmentOrdinal;
       
   726 
       
   727         // ensure that the attachment doesn't attach an edge to itself, 
       
   728         // however we don't need to do anything additional here, as this will
       
   729         // be checked automatically when we check for cycles.
       
   730         
       
   731         // ensure that adding the attachment will not cause a circular dependency...
       
   732         if(CheckForCycles(axisId, edgeProximity, aOrdinal, edge))
       
   733             {
       
   734             edge->iEdgeProximity = EHuiAnchorProximityNone;
       
   735             error = KErrArgument;
       
   736             }
       
   737         }
       
   738     
       
   739     return error;
       
   740     }
       
   741 
       
   742 EXPORT_C TInt CHuiAnchorLayout::Attach(
       
   743     TInt aOrdinal,
       
   744     THuiAnchorType aType, 
       
   745     const THuiXYMetric& aOffset,
       
   746     THuiAnchorAttachmentOrigin aAttachmentOrigin,
       
   747     TInt aAttachmentOrdinal)
       
   748         {
       
   749     // ensure that it's a corner
       
   750     THuiAnchorType typeH;
       
   751     THuiAnchorType typeV;
       
   752     ConvertCornerToEdges(aType, typeH, typeV);
       
   753     TBool bothAxes = (typeH != EHuiAnchorTypeNone) && (typeV != EHuiAnchorTypeNone);
       
   754     if(!bothAxes)
       
   755         {
       
   756         return KErrArgument;
       
   757         }
       
   758 
       
   759     // split the corner into two edges
       
   760     THuiAnchorAttachmentOrigin attachmentOriginH;
       
   761     THuiAnchorAttachmentOrigin attachmentOriginV;
       
   762     ConvertCornerAttachmentOriginToEdgeAttachmentOrigins(aAttachmentOrigin, attachmentOriginH, attachmentOriginV);
       
   763             
       
   764     TInt error = Attach(aOrdinal, typeH, aOffset.iX, attachmentOriginH, aAttachmentOrdinal);
       
   765 
       
   766     // if H is OK, create V
       
   767     if ( error == KErrNone )
       
   768         {
       
   769         error = Attach(aOrdinal, typeV, aOffset.iY, attachmentOriginV, aAttachmentOrdinal);
       
   770         // If V fails try to roll back by removing H
       
   771         if ( error != KErrNone )
       
   772             {
       
   773             Detach(aOrdinal, typeH);
       
   774             }
       
   775         }
       
   776     
       
   777     return error;
       
   778     }
       
   779 
       
   780 EXPORT_C TInt CHuiAnchorLayout::Attach(
       
   781     TInt aOrdinal,
       
   782     const THuiBoxMetric& aOffset,
       
   783     THuiAnchorAttachmentOrigin aAttachmentOrigin,
       
   784     TInt aAttachmentOrdinal)
       
   785     {
       
   786     // first detach all other edges
       
   787     Detach(aOrdinal);
       
   788     
       
   789     // if no attachment origin is specified, interpret this as meaning "attach each edge to its neighbour's corresponding edge"
       
   790     THuiAnchorAttachmentOrigin leftAttachmentOrigin = (aAttachmentOrigin == EHuiAnchorAttachmentOriginNone) ? EHuiAnchorAttachmentOriginLeft : aAttachmentOrigin;
       
   791     THuiAnchorAttachmentOrigin rightAttachmentOrigin = (aAttachmentOrigin == EHuiAnchorAttachmentOriginNone) ? EHuiAnchorAttachmentOriginRight : aAttachmentOrigin;
       
   792     THuiAnchorAttachmentOrigin topAttachmentOrigin = (aAttachmentOrigin == EHuiAnchorAttachmentOriginNone) ? EHuiAnchorAttachmentOriginTop : aAttachmentOrigin;
       
   793     THuiAnchorAttachmentOrigin bottomAttachmentOrigin = (aAttachmentOrigin == EHuiAnchorAttachmentOriginNone) ? EHuiAnchorAttachmentOriginBottom : aAttachmentOrigin;
       
   794         
       
   795     // just attach all four edges separately
       
   796     TInt error = Attach(aOrdinal, EHuiAnchorTypeLeft, aOffset.iLeft, leftAttachmentOrigin, aAttachmentOrdinal);
       
   797     if ( error == KErrNone )
       
   798         {
       
   799         error = Attach(aOrdinal, EHuiAnchorTypeRight, aOffset.iRight, rightAttachmentOrigin, aAttachmentOrdinal);
       
   800         if ( error == KErrNone )
       
   801             {
       
   802             error = Attach(aOrdinal, EHuiAnchorTypeTop, aOffset.iTop, topAttachmentOrigin, aAttachmentOrdinal);
       
   803             if ( error == KErrNone )
       
   804                 {
       
   805                 error = Attach(aOrdinal, EHuiAnchorTypeBottom, aOffset.iBottom, bottomAttachmentOrigin, aAttachmentOrdinal);
       
   806                 // if any of them fail, roll back the ones we've already added, unwinding as we go
       
   807                 if ( error != KErrNone )
       
   808                     {
       
   809                     DetachEdge(aOrdinal, EHuiAnchorTypeBottom);
       
   810                     }
       
   811                 }
       
   812             if ( error != KErrNone )
       
   813                 {
       
   814                 DetachEdge(aOrdinal, EHuiAnchorTypeTop);
       
   815                 }
       
   816             }
       
   817         if ( error != KErrNone )
       
   818             {
       
   819             DetachEdge(aOrdinal, EHuiAnchorTypeRight);
       
   820             }
       
   821         }
       
   822     if ( error != KErrNone )
       
   823         {
       
   824         DetachEdge(aOrdinal, EHuiAnchorTypeLeft);
       
   825         }
       
   826     return error;
       
   827     }
       
   828 
       
   829 EXPORT_C void CHuiAnchorLayout::Detach(TInt aOrdinal)
       
   830     {
       
   831     if(aOrdinal < iHuiAnchorLayoutPrivateData->iAnchors.Count())
       
   832         {
       
   833         TAnchor& anchor = iHuiAnchorLayoutPrivateData->iAnchors[aOrdinal];
       
   834         for(TInt axisId = EHuiAnchorAxisHorizontal; axisId <= EHuiAnchorAxisVertical; axisId++)
       
   835             {
       
   836             TAxis& axis = anchor.Axis(THuiAnchorAxis(axisId));
       
   837             TInt count = axis.iEdges.Count();
       
   838             for(TInt ii = 0; ii < count; ii++)
       
   839                 {
       
   840                 TEdgeAnchor& edge = axis.iEdges[ii];
       
   841                 edge.iEdgeProximity = EHuiAnchorProximityNone; 
       
   842                 edge.iOffset = THuiMetric();
       
   843                 edge.iAttachmentProximity = EHuiAnchorProximityNone;
       
   844                 edge.iAttachmentOrdinal = EHuiAnchorAttachToParent;
       
   845                 }
       
   846             }
       
   847         }
       
   848     }
       
   849     
       
   850 EXPORT_C void CHuiAnchorLayout::Detach(TInt aOrdinal, THuiAnchorType aType)
       
   851     {
       
   852     // split into edges
       
   853     THuiAnchorType typeH;
       
   854     THuiAnchorType typeV;
       
   855     ConvertCornerToEdges(aType, typeH, typeV);
       
   856     if(typeH != EHuiAnchorTypeNone)
       
   857         {
       
   858         DetachEdge(aOrdinal, typeH);
       
   859         }
       
   860     if(typeV != EHuiAnchorTypeNone)
       
   861         {
       
   862         DetachEdge(aOrdinal, typeV);
       
   863         }
       
   864     }
       
   865 
       
   866 void CHuiAnchorLayout::DetachEdge(TInt aOrdinal, THuiAnchorType aType)
       
   867     {
       
   868     // Try to find an existing edge anchor entry for this
       
   869     TEdgeAnchor* edge(NULL);
       
   870     THuiAnchorAxis axisId(EHuiAnchorAxisHorizontal);
       
   871     THuiAnchorProximity edgeProximity = ConvertTypeToProximity(aType, axisId);
       
   872 
       
   873     // avoid issue of Anchor() returning pointer to const
       
   874     TAnchor* anchor(NULL);
       
   875     if(aOrdinal < iHuiAnchorLayoutPrivateData->iAnchors.Count())
       
   876         {
       
   877         anchor = &(iHuiAnchorLayoutPrivateData->iAnchors[aOrdinal]);
       
   878         TAxis& axis = anchor->Axis(axisId);
       
   879         TInt error = axis.Edge(edgeProximity, edge);
       
   880         if(error == KErrNone)
       
   881             {
       
   882             edge->iEdgeProximity = EHuiAnchorProximityNone; 
       
   883             edge->iOffset = THuiMetric();
       
   884             edge->iAttachmentProximity = EHuiAnchorProximityNone;
       
   885             edge->iAttachmentOrdinal = EHuiAnchorAttachToParent;
       
   886             }
       
   887         }
       
   888     }
       
   889 
       
   890 /*
       
   891  * The model of anchors attached to other anchors should represent a directed 
       
   892  * acyclic graph (DAG), so check that insertion of a new attachment (/edge) does not 
       
   893  * cause a cycle. 
       
   894  * 
       
   895  * @note This method assumes that all previous insertion attempts have maintained 
       
   896  *               the DAG property.
       
   897  * @note This method is implemented using a depth first recursive tree search. 
       
   898  * @note Because there can be only one attachment (which is along a specfic axis) starting 
       
   899  *              at each edge, it is not necessary to keep a visited list.
       
   900  */
       
   901 TBool CHuiAnchorLayout::CheckForCycles(
       
   902     THuiAnchorAxis aStartAxisId,
       
   903     THuiAnchorProximity aStartAnchorProximity,
       
   904     TInt aStartOrdinal, 
       
   905     const TEdgeAnchor* aEdge) const
       
   906     {
       
   907     TInt nextOrdinal = aEdge->iAttachmentOrdinal;
       
   908     if(nextOrdinal == EHuiAnchorAttachToParent)
       
   909         {
       
   910         // we've found the end of a path, as this corner attaches to the parent.
       
   911         return EFalse;
       
   912         }
       
   913 
       
   914     const TAnchor* nextAnchor = Anchor(nextOrdinal); 
       
   915     if(!nextAnchor)
       
   916         {
       
   917         // anchor not specified, so we've found the end of a path
       
   918         return EFalse;
       
   919         }
       
   920 
       
   921     // @todo note that with size attachments, the axis might change here
       
   922     TAxis& nextAxis = nextAnchor->Axis(aStartAxisId);
       
   923     TEdgeAnchor* nextEdge = NULL;
       
   924     TInt error = nextAxis.Edge(aEdge->iAttachmentProximity, nextEdge);
       
   925 
       
   926     // @todo, when implementing size attachments, need to evaluate both edges at this point
       
   927     // in order to determine the dependencies for this edge
       
   928     if(error != KErrNone)
       
   929         {
       
   930         return EFalse;
       
   931         }
       
   932 
       
   933     // so we now know the next proximity, and the next anchor.
       
   934     if(aStartAnchorProximity == nextEdge->iEdgeProximity && aStartOrdinal == nextOrdinal)
       
   935         {
       
   936         // we have found a cycle!
       
   937         // note that this will also detect an attempt to attach to the same edge on same ordinal
       
   938         return ETrue;
       
   939         }
       
   940     else
       
   941         {
       
   942         return CheckForCycles(aStartAxisId, aStartAnchorProximity, aStartOrdinal, nextEdge);
       
   943         }
       
   944     }
       
   945 
       
   946 // end of file