|
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 |