|
1 /* |
|
2 * Copyright (c) 2003-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: Implements the Form LCDUI component. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 // For LyaoutMirrored() method. |
|
20 #include <AknUtils.h> |
|
21 |
|
22 #include "CMIDFormRow.h" |
|
23 // CMIDForm API for iForm |
|
24 #include "CMIDForm.h" |
|
25 // API for items on rows |
|
26 #include "CMIDControlItem.h" |
|
27 #include "CMIDItemLabel.h" |
|
28 |
|
29 |
|
30 CMIDFormRow* CMIDFormRow::NewL(CMIDForm& aForm) |
|
31 { |
|
32 CMIDFormRow* self = new(ELeave) CMIDFormRow(aForm); |
|
33 CleanupStack::PushL(self); |
|
34 self->ActivateL(); |
|
35 CleanupStack::Pop(self); |
|
36 return self; |
|
37 } |
|
38 |
|
39 CMIDFormRow::~CMIDFormRow() |
|
40 { |
|
41 TInt i; |
|
42 for (i=0; i < iItems.Count(); i++) |
|
43 { |
|
44 if (CMIDForm::IsLabelContainerItem(*(iItems[i]))) |
|
45 { |
|
46 delete iItems[i]; |
|
47 } |
|
48 else if (CMIDForm::IsSpacerUsedForFormatting(*(iItems[i]))) |
|
49 { |
|
50 delete iItems[i]; |
|
51 } |
|
52 } |
|
53 iItems.Reset(); |
|
54 iItems.Close(); |
|
55 } |
|
56 |
|
57 TInt CMIDFormRow::CountComponentControls() const |
|
58 { |
|
59 return iItems.Count(); |
|
60 } |
|
61 |
|
62 CCoeControl* CMIDFormRow::ComponentControl(TInt aIndex) const |
|
63 { |
|
64 return iItems[aIndex]; |
|
65 } |
|
66 |
|
67 void CMIDFormRow::SizeChanged() |
|
68 { |
|
69 TInt xOff = 0; |
|
70 |
|
71 TSize size(0,0); |
|
72 |
|
73 TInt i; |
|
74 for (i=0; i < iItems.Count(); i++) |
|
75 { |
|
76 CMIDControlItem& ci = *(iItems[i]); |
|
77 size.iWidth += ci.Size().iWidth; |
|
78 if (ci.Size().iHeight > size.iHeight) |
|
79 { |
|
80 size.iHeight = ci.Size().iHeight; |
|
81 } |
|
82 } |
|
83 |
|
84 if (iAlignment == MMIDItem::ERight) |
|
85 { |
|
86 xOff = iForm.Width() - size.iWidth; |
|
87 // If it is mirrored layout, we need translate a row. |
|
88 if (AknLayoutUtils::LayoutMirrored()) |
|
89 { |
|
90 xOff -= iForm.GetMidpNaviPos(); |
|
91 } |
|
92 } |
|
93 |
|
94 if (iAlignment == MMIDItem::ECenter) |
|
95 { |
|
96 xOff = (iForm.Width() - size.iWidth) / 2; |
|
97 } |
|
98 |
|
99 for (i=0; i < iItems.Count(); i++) |
|
100 { |
|
101 CMIDControlItem& ci = *(iItems[i]); |
|
102 TInt yOff = 0; |
|
103 if (CMIDForm::LayoutBottom(ci)) |
|
104 { |
|
105 yOff = size.iHeight - ci.Size().iHeight; |
|
106 } |
|
107 if (CMIDForm::LayoutVerticalCenter(ci)) |
|
108 { |
|
109 yOff = (size.iHeight - ci.Size().iHeight) / 2; |
|
110 } |
|
111 |
|
112 // Form left margin is added in the beginning of each row |
|
113 TPoint newPosition = Position() + TPoint(xOff, yOff); |
|
114 TSize itemSize = ci.Size(); |
|
115 TRect itemRect = TRect(newPosition, itemSize); |
|
116 ci.SetRect(itemRect); |
|
117 xOff += ci.Size().iWidth; |
|
118 } |
|
119 } |
|
120 |
|
121 TSize CMIDFormRow::MinimumSize() |
|
122 { |
|
123 if (iItems.Count() == 0) |
|
124 { |
|
125 return iEmptyRowSize; |
|
126 } |
|
127 |
|
128 TInt width = 0; |
|
129 TInt height = 0; |
|
130 |
|
131 for (TInt i=0; i < iItems.Count(); i++) |
|
132 { |
|
133 CMIDControlItem& ci = *(iItems[i]); |
|
134 |
|
135 width += CMIDForm::LayoutShrink(ci) ? ci.MinimumSize().iWidth : ci.PreferredSize().iWidth; |
|
136 |
|
137 if (CMIDForm::LayoutVerticalShrink(ci)) |
|
138 { |
|
139 if (height < ci.MinimumSize().iHeight) |
|
140 { |
|
141 height = ci.MinimumSize().iHeight; |
|
142 } |
|
143 } |
|
144 else |
|
145 { |
|
146 if (height < ci.PreferredSize().iHeight) |
|
147 { |
|
148 height = ci.PreferredSize().iHeight; |
|
149 } |
|
150 } |
|
151 } |
|
152 return TSize(width, height); |
|
153 } |
|
154 |
|
155 void CMIDFormRow::AppendL(CMIDControlItem* aItem) |
|
156 { |
|
157 if (iForm.InitialAlignment() == MMIDItem::ELeft) |
|
158 { |
|
159 User::LeaveIfError(iItems.Append(aItem)); |
|
160 } |
|
161 else |
|
162 { |
|
163 User::LeaveIfError(iItems.Insert(aItem, 0)); |
|
164 } |
|
165 iCurrentWidth += aItem->Size().iWidth; |
|
166 } |
|
167 |
|
168 void CMIDFormRow::SetAlignment(MMIDItem::TLayout aAlignment) |
|
169 { |
|
170 ASSERT((aAlignment == MMIDItem::ELeft) || (aAlignment == MMIDItem::ERight) || (aAlignment == MMIDItem::ECenter)); |
|
171 iAlignment = aAlignment; |
|
172 } |
|
173 |
|
174 /** */ |
|
175 void CMIDFormRow::SizeItemsL() |
|
176 { |
|
177 TSize minSize = MinimumSize(); |
|
178 |
|
179 // size the widths first |
|
180 TInt availableWidth = iForm.Width() - minSize.iWidth; |
|
181 // equation is also allowed - resizing when extra space is same as allowed |
|
182 if (availableWidth >= 0) |
|
183 { |
|
184 TInt totalExtraWidth = 0; |
|
185 for (TInt j=0; j < iItems.Count(); j++) |
|
186 { |
|
187 CMIDControlItem& ci = *(iItems[j]); |
|
188 if (CMIDForm::LayoutShrink(ci)) |
|
189 { |
|
190 totalExtraWidth += ci.PreferredSize().iWidth - ci.MinimumSize().iWidth; |
|
191 } |
|
192 } |
|
193 |
|
194 if (availableWidth > totalExtraWidth) |
|
195 { |
|
196 // just give all items what they want |
|
197 for (TInt j=0; j < iItems.Count(); j++) |
|
198 { |
|
199 CMIDControlItem& ci = *(iItems[j]); |
|
200 ci.SetSizeQuiet(ci.PreferredSize()); |
|
201 } |
|
202 |
|
203 availableWidth -= totalExtraWidth; |
|
204 } |
|
205 else |
|
206 { |
|
207 // distribute the size |
|
208 TReal scaleFactor; |
|
209 if (availableWidth == totalExtraWidth) |
|
210 { |
|
211 scaleFactor = 1; |
|
212 } |
|
213 else |
|
214 { |
|
215 if (totalExtraWidth != 0) |
|
216 { |
|
217 scaleFactor = TReal(availableWidth) / TReal(totalExtraWidth); |
|
218 } |
|
219 else |
|
220 { |
|
221 scaleFactor = 1; |
|
222 } |
|
223 } |
|
224 |
|
225 for (TInt j=0; j < iItems.Count(); j++) |
|
226 { |
|
227 CMIDControlItem& ci = *(iItems[j]); |
|
228 |
|
229 if (CMIDForm::LayoutShrink(ci)) |
|
230 { |
|
231 TInt minAndPreferredDif = ci.PreferredSize().iWidth - ci.MinimumSize().iWidth; |
|
232 TInt newMinAndPreferredDif = TInt(scaleFactor * TReal(minAndPreferredDif)); |
|
233 TInt newWidth = ci.MinimumSize().iWidth + Min(newMinAndPreferredDif, minAndPreferredDif); |
|
234 availableWidth -= Min(newMinAndPreferredDif, minAndPreferredDif); |
|
235 ci.SetSizeQuiet(TSize(newWidth, ci.Size().iHeight)); |
|
236 } |
|
237 else |
|
238 { |
|
239 ci.SetSizeQuiet(TSize(ci.PreferredSize().iWidth, ci.Size().iHeight)); |
|
240 } |
|
241 } |
|
242 } |
|
243 // note: should probably do another pass through to make sure the above step |
|
244 // went ok and didn't suffer from rounding errors (ie that the Shrink items didn't |
|
245 // end up smaller than their preferred size (if we have size left over) |
|
246 |
|
247 // loop through and expand the items with Expand layout |
|
248 if (availableWidth > 0) |
|
249 { |
|
250 TInt numExpand = 0; |
|
251 // count the items with Expand layout |
|
252 for (TInt j=0; j < iItems.Count(); j++) |
|
253 { |
|
254 CMIDControlItem& ci = *(iItems[j]); |
|
255 |
|
256 if (CMIDForm::LayoutExpand(ci)) |
|
257 { |
|
258 numExpand++; |
|
259 } |
|
260 } |
|
261 if (numExpand > 0) |
|
262 { |
|
263 TInt addedSize = availableWidth / numExpand; |
|
264 TInt expandIdx = -1; |
|
265 |
|
266 for (TInt j=0; j < iItems.Count(); j++) |
|
267 { |
|
268 CMIDControlItem& ci = *(iItems[j]); |
|
269 |
|
270 if (CMIDForm::LayoutExpand(ci)) |
|
271 { |
|
272 ci.SetSizeQuiet(ci.Size() + TSize(addedSize, 0)); |
|
273 availableWidth -= addedSize; |
|
274 expandIdx = j; |
|
275 // at the end of the loop this will hold the last expanded |
|
276 // item. At that time we can check if we still have extra |
|
277 // space remaining and give it to the item at this index |
|
278 } |
|
279 } |
|
280 if (availableWidth > 0) |
|
281 { |
|
282 // if we still have extra width due to rounding error just give it to the last item |
|
283 iItems[expandIdx]->SetSizeQuiet(iItems[expandIdx]->Size() + TSize(availableWidth, 0)); |
|
284 } |
|
285 } |
|
286 } |
|
287 } |
|
288 |
|
289 |
|
290 // the widths have been calculated. This could have changed the height |
|
291 // due to for example label wrapping so ask the control to check |
|
292 // the new width. |
|
293 TInt j; |
|
294 for (j=0; j < iItems.Count(); j++) |
|
295 { |
|
296 CMIDControlItem& ci = *(iItems[j]); |
|
297 ci.AdjustToNewWidthL(ci.Size().iWidth); |
|
298 } |
|
299 |
|
300 // now size the heights |
|
301 |
|
302 // first find the row height |
|
303 TInt rowHeight = 0; |
|
304 for (j=0; j < iItems.Count(); j++) |
|
305 { |
|
306 CMIDControlItem& ci = *(iItems[j]); |
|
307 |
|
308 TInt height = ci.PreferredSize().iHeight; |
|
309 if (CMIDForm::LayoutVerticalShrink(ci)) |
|
310 { |
|
311 height = ci.MinimumSize().iHeight; |
|
312 } |
|
313 if (height > rowHeight) |
|
314 { |
|
315 rowHeight = height; |
|
316 } |
|
317 } |
|
318 |
|
319 if (iItems.Count() == 0) |
|
320 {//if not items use empty row height |
|
321 rowHeight = iEmptyRowSize.iHeight; |
|
322 } |
|
323 |
|
324 // now set the row heights |
|
325 for (j=0; j < iItems.Count(); j++) |
|
326 { |
|
327 CMIDControlItem& ci = *(iItems[j]); |
|
328 |
|
329 // first set the size normally, then change it based on shrink and expand directives |
|
330 ci.SetSizeQuiet(TSize(ci.Size().iWidth, ci.PreferredSize().iHeight)); |
|
331 if (CMIDForm::LayoutVerticalShrink(ci)) |
|
332 { |
|
333 TInt height = Min(ci.PreferredSize().iHeight, rowHeight); |
|
334 ci.SetSizeQuiet(TSize(ci.Size().iWidth, height)); |
|
335 } |
|
336 if (CMIDForm::LayoutVerticalExpand(ci)) |
|
337 { |
|
338 ci.SetSizeQuiet(TSize(ci.Size().iWidth, rowHeight)); |
|
339 } |
|
340 |
|
341 ci.AdjustToSizeL(ci.Size()); |
|
342 } |
|
343 |
|
344 // set the size of the row |
|
345 SetSize(TSize(iForm.Width(), rowHeight)); |
|
346 } |
|
347 |
|
348 TInt CMIDFormRow::NumItems() |
|
349 { |
|
350 return iItems.Count(); |
|
351 } |
|
352 |
|
353 TInt CMIDFormRow::Find(const CMIDControlItem* aItem) const |
|
354 { |
|
355 for (TInt i=0; i < iItems.Count(); i++) |
|
356 { |
|
357 if (aItem == iItems[i]) |
|
358 { |
|
359 return i; |
|
360 } |
|
361 } |
|
362 |
|
363 return KErrNotFound; |
|
364 } |
|
365 |
|
366 CMIDControlItem* CMIDFormRow::Item(TInt aIndex) |
|
367 { |
|
368 ASSERT(aIndex >= 0 && aIndex < iItems.Count()); |
|
369 return iItems[aIndex]; |
|
370 } |
|
371 |
|
372 TBool CMIDFormRow::HasFocusableItemOnOrAboveScreen() |
|
373 { |
|
374 for (TInt i=0; i < iItems.Count(); i++) |
|
375 { |
|
376 if (iItems[i]->IsSelectable()) |
|
377 { |
|
378 TRect rect = iItems[i]->Rect(); |
|
379 if (rect.iTl.iY < iForm.Height()) |
|
380 { |
|
381 return ETrue; |
|
382 } |
|
383 } |
|
384 } |
|
385 return EFalse; |
|
386 } |
|
387 |
|
388 TBool CMIDFormRow::HasFocusableItemOnOrBelowScreen() |
|
389 { |
|
390 for (TInt i=0; i < iItems.Count(); i++) |
|
391 { |
|
392 if (iItems[i]->IsSelectable()) |
|
393 { |
|
394 TRect rect = iItems[i]->Rect(); |
|
395 if (rect.iBr.iY >= 0) |
|
396 { |
|
397 return ETrue; |
|
398 } |
|
399 } |
|
400 } |
|
401 return EFalse; |
|
402 } |
|
403 |
|
404 CMIDControlItem* CMIDFormRow::FirstFocusableItemOnScreen() |
|
405 { |
|
406 TInt idx = -1; |
|
407 while (++idx < iItems.Count()) |
|
408 { |
|
409 if (iItems[idx]->IsSelectable()) |
|
410 { |
|
411 TRect rect = iItems[idx]->Rect(); |
|
412 if (iForm.RectPartiallyVisible(rect)) |
|
413 { |
|
414 return iItems[idx]; |
|
415 } |
|
416 } |
|
417 } |
|
418 return NULL; |
|
419 } |
|
420 |
|
421 CMIDControlItem* CMIDFormRow::FirstFocusableItem() |
|
422 { |
|
423 TInt idx = -1; |
|
424 while (++idx < iItems.Count()) |
|
425 { |
|
426 if (iItems[idx]->IsSelectable()) |
|
427 { |
|
428 return iItems[idx]; |
|
429 } |
|
430 } |
|
431 return NULL; |
|
432 } |
|
433 |
|
434 CMIDControlItem* CMIDFormRow::LastFocusableItem() |
|
435 { |
|
436 TInt idx = iItems.Count(); |
|
437 while (--idx >= 0) |
|
438 { |
|
439 if (iItems[idx]->IsSelectable()) |
|
440 { |
|
441 return iItems[idx]; |
|
442 } |
|
443 } |
|
444 return NULL; |
|
445 } |
|
446 |
|
447 // typically just used when cleaning up. This won't cause a layout. |
|
448 TBool CMIDFormRow::RemoveItemIfExists(CMIDControlItem& aItem) |
|
449 { |
|
450 TInt i = -1; |
|
451 while (++i < iItems.Count()) |
|
452 { |
|
453 if (&aItem == iItems[i]) |
|
454 { |
|
455 iItems.Remove(i); |
|
456 return ETrue; |
|
457 } |
|
458 } |
|
459 |
|
460 return EFalse; |
|
461 } |
|
462 |
|
463 TInt CMIDFormRow::CurrentWidth() |
|
464 { |
|
465 return iCurrentWidth; |
|
466 } |
|
467 |
|
468 CMIDFormRow::CMIDFormRow(CMIDForm& aForm) |
|
469 :iForm(aForm) |
|
470 { |
|
471 #ifdef RD_SCALABLE_UI_V2 |
|
472 SetAllowStrayPointers(); |
|
473 #endif |
|
474 } |
|
475 |
|
476 void CMIDFormRow::ConstructL() |
|
477 { |
|
478 } |
|
479 |
|
480 /** |
|
481 * Returns true if this row has at least an item which is not a spacer |
|
482 */ |
|
483 TBool CMIDFormRow::HasNonSpacerItems() const |
|
484 { |
|
485 TBool ret = EFalse; |
|
486 |
|
487 TInt i = -1; |
|
488 while (++i < iItems.Count()) |
|
489 { |
|
490 if (iItems[i]->Type() != MMIDComponent::ESpacer) |
|
491 { |
|
492 ret = ETrue; |
|
493 break; |
|
494 } |
|
495 } |
|
496 |
|
497 return ret; |
|
498 } |
|
499 |
|
500 // End of File |