javauis/lcdui_akn/lcdui/src/CMIDForm.cpp
branchRCL_3
changeset 14 04becd199f91
child 17 0fd27995241b
equal deleted inserted replaced
13:f5050f1da672 14:04becd199f91
       
     1 /*
       
     2 * Copyright (c) 2003-2008 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 //RD_SCALABLE_UI definition
       
    20 #include <bldvariant.hrh>
       
    21 // using CEikScrollBarFrame API for iSBFrame
       
    22 #include <eiksbfrm.h>
       
    23 
       
    24 // API used for retrieving layout for initial alignment (in ConstructL)
       
    25 #include <centralrepository.h>
       
    26 // constants used in retrieving layout for initial alignment (in ConstructL)
       
    27 #include <AvkonInternalCRKeys.h>
       
    28 
       
    29 // control context that provides a layout background
       
    30 #include <AknsListBoxBackgroundControlContext.h>
       
    31 // highlight background
       
    32 #include <AknsFrameBackgroundControlContext.h>
       
    33 // API for text formatting used in DrawNoDataStringL function
       
    34 #include <AknBidiTextUtils.h>
       
    35 
       
    36 #include "CMIDForm.h"
       
    37 #include "CMIDFormRow.h"
       
    38 // API for iDisplayable
       
    39 #include "CMIDDisplayable.h"
       
    40 #include "CMIDItem.h"
       
    41 #include "CMIDControlItem.h"
       
    42 #include "CMIDGaugeItem.h"
       
    43 #include "CMIDImageItem.h"
       
    44 #include "CMIDStringItem.h"
       
    45 // CMIDLabelContainerItem API used to obtain CMIDStringItem item
       
    46 #include "CMIDLabelContainerItem.h"
       
    47 #include "CMIDTextFieldItem.h"
       
    48 #include "CMIDChoiceGroupItem.h"
       
    49 #include "CMIDSpacer.h"
       
    50 #include "CMIDCustomItem.h"
       
    51 #include "CMIDDateFieldItem.h"
       
    52 #include "CMIDComponentFactory.h"
       
    53 #include "CMIDUtils.h"
       
    54 #include "CMIDItemLabel.h"
       
    55 #include "CMIDTicker.h"
       
    56 #include "CMIDFont.h"
       
    57 #include "CMIDPopupNoteController.h"
       
    58 // Kinetic scrolling
       
    59 #include "CMIDFormPhysics.h"
       
    60 
       
    61 #include <applayout.cdl.h>
       
    62 // LAF
       
    63 #include <aknlayoutscalable_avkon.cdl.h>
       
    64 // LAF
       
    65 #include <layoutmetadata.cdl.h>
       
    66 
       
    67 // Api for skin layout
       
    68 #include <skinlayout.cdl.h>
       
    69 using namespace SkinLayout;
       
    70 
       
    71 #include <j2me/jdebug.h>
       
    72 
       
    73 #undef  TRAP_INSTRUMENTATION_LEAVE
       
    74 #define TRAP_INSTRUMENTATION_LEAVE(aResult) DEBUG_INT2("In CMIDForm.cpp, trapped method was called at line %D and got exception %D", __LINE__, aResult);
       
    75 
       
    76 #ifdef RD_SCALABLE_UI_V2
       
    77 /** Dividers used when the the scroll amount is calculated*/
       
    78 const TInt KScrollAmountDivider = 4;
       
    79 const TInt KScrollAmountDividerForThumbDrag = 10;
       
    80 
       
    81 /** Interval for scrolling when stylus is dragged outside the form and held down */
       
    82 const TInt KScrollInterval = 100000; // 0,1 sec
       
    83 #endif //RD_SCALABLE_UI_V2
       
    84 
       
    85 /** The minimum amount to scroll */
       
    86 const TInt KMinScrollAmount = 40;
       
    87 
       
    88 /** The timeout in microseconds for visual updates. When items are added or removed
       
    89 or modified, the form is not redrawn immediately but only after this timeout. This way
       
    90 if more items are being added or removed or changed we reduce the number of redraws.
       
    91 */
       
    92 const TInt KLayoutTimeout = 60000; //60 msecs
       
    93 
       
    94 /** If layout has been requested for a period longer than the cap then perform layout
       
    95 even if the midlet is still performing form insert/delete operations. */
       
    96 const TInt KLayoutCap = 1000000; // 1 sec
       
    97 
       
    98 ///////////////////////////////////////////////////////////////////////////////////////////////////
       
    99 // MMIDForm interface
       
   100 ///////////////////////////////////////////////////////////////////////////////////////////////////
       
   101 
       
   102 /**
       
   103  * Add items list. Note: this is no longer called by framework!!
       
   104  */
       
   105 void CMIDForm::SetAllItemsL(const RArray<MMIDItem*>& aItems)
       
   106 {
       
   107     DEBUG("CMIDForm::SetAllItemsL");
       
   108 
       
   109     ASSERT(iItems.Count() == 0);
       
   110     //
       
   111     TInt count = aItems.Count();
       
   112     for (TInt i=0; i<count; i++)
       
   113     {
       
   114         User::LeaveIfError(iItems.Append(aItems[i]));
       
   115         CMIDControlItem& ci = ControlItem(i);
       
   116 
       
   117         AddItemToFormL(ci);
       
   118         ci.MakeVisible(ETrue);
       
   119     }
       
   120 
       
   121     RequestLayoutL();
       
   122 }
       
   123 
       
   124 /**
       
   125  * Replaces an item. Keeps the same item focused which had focus before,
       
   126  * and if that's the one that this is replacing, then this will be focused
       
   127  * if possible.
       
   128  */
       
   129 void CMIDForm::SetItemL(MMIDItem& aItem,TInt aIndex)
       
   130 {
       
   131     DEBUG("CMIDForm::SetItemL");
       
   132 
       
   133     CMIDControlItem& oldCi = ControlItem(aIndex);
       
   134     RemoveItemFromForm(oldCi);
       
   135 
       
   136     iItems[aIndex] = &aItem;
       
   137     CMIDControlItem& ci = ControlItem(aIndex);
       
   138     AddItemToFormL(ci);
       
   139 
       
   140     ci.MakeVisible(ETrue);
       
   141 
       
   142     if (iFocused == aIndex)
       
   143     {
       
   144         iDisplayable.MenuHandler()->HideMenuIfVisible();
       
   145 
       
   146         if (ci.IsSelectable())
       
   147         {
       
   148             SetFocusedItem(aIndex);
       
   149         }
       
   150         else
       
   151         {
       
   152             SetFocusedItem(KErrNotFound);
       
   153         }
       
   154     }
       
   155 
       
   156     RequestLayoutL();
       
   157 }
       
   158 
       
   159 /**
       
   160  * Inserts a new Item.
       
   161  */
       
   162 void CMIDForm::InsertItemL(MMIDItem& aItem,TInt aIndex)
       
   163 {
       
   164     DEBUG("CMIDForm::InsertItemL");
       
   165 
       
   166     User::LeaveIfError(iItems.Insert(&aItem,aIndex));
       
   167     CMIDControlItem& ci = ControlItem(aIndex);
       
   168 
       
   169     AddItemToFormL(ci);
       
   170     ci.MakeVisible(ETrue);
       
   171     // if insert item then index of pointed control is increase
       
   172     if (aIndex <= iIndexPointedControl)
       
   173     {
       
   174         iIndexPointedControl++;
       
   175     }
       
   176 
       
   177     // If there isn't any focused item yet, we have to set focus
       
   178     // to first item which is focusable. Once the item has focus,
       
   179     // we can skip this step.
       
   180     if (iFocused == KErrNotFound)
       
   181     {
       
   182         SetFocusedItem(ci.IsSelectable() ? aIndex : KErrNotFound);
       
   183     }
       
   184 
       
   185     RequestLayoutL();
       
   186 }
       
   187 
       
   188 void CMIDForm::DeleteItemL(TInt aIndex)
       
   189 {
       
   190     DEBUG("CMIDForm::DeleteItemL");
       
   191 
       
   192     TBool updateFocused = EFalse;
       
   193     // if delete item then index of pointed control is decrease
       
   194     if (iIndexPointedControl > aIndex)
       
   195     {
       
   196         iIndexPointedControl--;
       
   197     }
       
   198     else
       
   199         // if delete item is same as index of pointed control then index is set to not active
       
   200     {
       
   201         if (iIndexPointedControl == aIndex)
       
   202         {
       
   203             iIndexPointedControl = -1;
       
   204         }
       
   205     }
       
   206     if (iFocused > aIndex)
       
   207     {
       
   208         iFocused--;
       
   209     }
       
   210     else if (iFocused == aIndex)
       
   211     {
       
   212         iDisplayable.MenuHandler()->HideMenuIfVisible();
       
   213         ReplaceFocusedItem();
       
   214         updateFocused = ETrue;
       
   215     }
       
   216 
       
   217     CMIDControlItem& ci = ControlItem(aIndex);
       
   218     RemoveItemFromForm(ci);
       
   219     if (&ci == iPointedControl)
       
   220     {
       
   221         iPointedControl = NULL;
       
   222     }
       
   223 
       
   224     iItems.Remove(aIndex);
       
   225 
       
   226     if (iFocused != KErrNotFound && updateFocused)
       
   227     {
       
   228         iFocused--;
       
   229     }
       
   230 
       
   231     RequestLayoutL();
       
   232 }
       
   233 
       
   234 void CMIDForm::DeleteAllItemsL()
       
   235 {
       
   236     DEBUG("CMIDForm::DeleteAllItemsL");
       
   237     iDisplayable.MenuHandler()->HideMenuIfVisible();
       
   238     SetFocusedItem(KErrNotFound);
       
   239 
       
   240     TInt itemCount = iItems.Count();
       
   241     for (TInt i=0; i < itemCount; i++)
       
   242     {
       
   243         CMIDControlItem& ci = ControlItem(i);
       
   244         RemoveItemFromForm(ci);
       
   245     }
       
   246     iItems.Reset();
       
   247 
       
   248     iScroll = 0;
       
   249     // if delete all then index of pointed control is set to not active
       
   250     iIndexPointedControl = -1;
       
   251 
       
   252     iPointedControl = NULL;
       
   253     RequestLayoutL();
       
   254 }
       
   255 
       
   256 /**
       
   257  * Called when the item has changed its appearance in some way.
       
   258  */
       
   259 void CMIDForm::RefreshItemL(TInt aIndex)
       
   260 {
       
   261     DEBUG("CMIDForm::RefreshItemL");
       
   262 
       
   263     if (aIndex != KErrNotFound)
       
   264     {
       
   265         RequestLayoutL();
       
   266     }
       
   267 }
       
   268 
       
   269 /**
       
   270  * Returns whether the item is actually visible to the user. Must therefore take into
       
   271  * account the visibility of the entire form, and whether the specific item is scrolled
       
   272  * in/out of the viewable area.
       
   273  */
       
   274 TBool CMIDForm::IsItemVisible(TInt aIndex)
       
   275 {
       
   276     DEBUG("CMIDForm::IsItemVisible");
       
   277 
       
   278     CMIDControlItem& control = ControlItem(aIndex);
       
   279 
       
   280     if ((control.Position().iY > Height()) ||
       
   281             ((control.Position().iY + control.Size().iHeight) < 0))
       
   282     {
       
   283         return EFalse;
       
   284     }
       
   285     return ETrue;
       
   286 }
       
   287 
       
   288 /**
       
   289  * Called prior to the Form itself being made the current Displayable.
       
   290  * It provides an opportunity to prepare the form such that this item will
       
   291  * be visible and focused when the form is eventually made current
       
   292  */
       
   293 void CMIDForm::SetCurrentItemL(TInt aIndex)
       
   294 {
       
   295     DEBUG("CMIDForm::SetCurrentItemL");
       
   296 
       
   297     // If it is pending request for layout, than layout now.
       
   298     if (LayoutPending())
       
   299     {
       
   300         LayoutAndDrawL();
       
   301     }
       
   302 
       
   303     // Set focus of item to aIndex and scroll to it.
       
   304     SetFocusedItem(aIndex);
       
   305 
       
   306 }
       
   307 
       
   308 
       
   309 //
       
   310 // End of MMIDForm interface
       
   311 //
       
   312 
       
   313 TInt CMIDForm::CountComponentControls() const
       
   314 {
       
   315     return iRows.Count();
       
   316 }
       
   317 
       
   318 CCoeControl* CMIDForm::ComponentControl(TInt aIndex) const
       
   319 {
       
   320     return iRows[aIndex];
       
   321 }
       
   322 
       
   323 TKeyResponse CMIDForm::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
       
   324 {
       
   325     DEBUG("< CMIDForm::OfferKeyEventL");
       
   326 
       
   327     TBool isArrowKey = (aKeyEvent.iCode == EKeyDownArrow || aKeyEvent.iCode == EKeyUpArrow ||
       
   328                         aKeyEvent.iCode == EKeyLeftArrow || aKeyEvent.iCode == EKeyRightArrow);
       
   329 
       
   330     if (iFocused != KErrNotFound)
       
   331     {
       
   332         CMIDControlItem& controlItem = ControlItem(iFocused);
       
   333         TRect controlRect = GetControlRect(iFocused);
       
   334         TBool visible = RectPartiallyVisible(controlRect);
       
   335 
       
   336         // arrow key events are not sent to the hidden focused item
       
   337         if ((visible || !isArrowKey) &&
       
   338                 controlItem.OfferKeyEventL(aKeyEvent,aType) == EKeyWasConsumed)
       
   339         {
       
   340             DEBUG("CMIDForm::OfferKeyEventL - out after item consumed key");
       
   341 
       
   342 #ifdef RD_SCALABLE_UI_V2
       
   343             // If focused TextField or DateField item is at least partly out of
       
   344             // Form viewport, then key event (excluding arrow keys and soft keys)
       
   345             // scrolls the item completely visible. This situation
       
   346             // is possible when scrolling has been done with scrollbar.
       
   347 
       
   348             // Soft keys and arrow keys are ignored. Filtering must be done comparing
       
   349             // scan codes because the aEventType.iCode is not available for all key presses.
       
   350             TBool ignoreKey = (aKeyEvent.iScanCode == EStdKeyRightArrow ||
       
   351                                aKeyEvent.iScanCode == EStdKeyUpArrow ||
       
   352                                aKeyEvent.iScanCode == EStdKeyDownArrow ||
       
   353                                aKeyEvent.iScanCode == EStdKeyLeftArrow ||
       
   354                                aKeyEvent.iScanCode == EStdKeyDevice0 ||
       
   355                                aKeyEvent.iScanCode == EStdKeyDevice1 ||
       
   356                                aKeyEvent.iScanCode == EStdKeyDevice3);
       
   357 
       
   358             if ((controlItem.Type() == MMIDComponent::ETextField ||
       
   359                     controlItem.Type() == MMIDComponent::EDateField) &&
       
   360                     !RectFullyVisible(controlRect) && !ignoreKey)
       
   361             {
       
   362                 // Scroll up if controlItem is above the Form viewport.
       
   363                 // Otherwise scroll down.
       
   364                 if (controlRect.iTl.iY < 0)
       
   365                 {
       
   366                     ScrollToFocused(EUp, ETrue);
       
   367                 }
       
   368                 else
       
   369                 {
       
   370                     ScrollToFocused(EDown, ETrue);
       
   371                 }
       
   372 
       
   373             }
       
   374 #endif // RD_SCALABLE_UI_V2
       
   375 
       
   376             return EKeyWasConsumed;
       
   377         }
       
   378     }
       
   379 
       
   380     DEBUG("CMIDForm::OfferKeyEventL - got chance to scroll");
       
   381 
       
   382     if ((aType == EEventKey) && isArrowKey && (iItems.Count() > 0))
       
   383     {
       
   384         DEBUG("CMIDForm::OfferKeyEventL - about to call Traverse");
       
   385 
       
   386         Traverse(ConvertKeyToDirection(aKeyEvent.iCode));
       
   387 
       
   388         DEBUG("CMIDForm::OfferKeyEventL - out after Traverse");
       
   389         return EKeyWasConsumed;
       
   390     }
       
   391 
       
   392     // msk: this is needed if MSK is not enabled
       
   393     if ((aType == EEventKey) &&
       
   394             ((aKeyEvent.iScanCode == EStdKeyDevice3) || (aKeyEvent.iCode == EKeyEnter))
       
   395        )
       
   396     {
       
   397         if (!DoDefaultCommand())
       
   398         {
       
   399             iDisplayable.ShowOkOptionsMenuL();
       
   400         }
       
   401 
       
   402         DEBUG("CMIDForm::OfferKeyEventL - out after default command or ok menu");
       
   403         return EKeyWasConsumed;
       
   404     }
       
   405     // end msk
       
   406     DEBUG("> CMIDForm::OfferKeyEventL");
       
   407     return EKeyWasNotConsumed;
       
   408 }
       
   409 
       
   410 /**  Handle a focus change. Make sure there is no layout pending and if there is
       
   411 one then do it, see TrappedLayoutAndDraw(). This is because when there is a layout
       
   412 pending we are in a temporary inconsistent phase with no rows and the rows are the
       
   413 intermediary to the items via the CountComponentControl() and ComponentControl() calls.
       
   414 Then pass on focus to our children according to the value stored in iFocused. Finally
       
   415 update the scroll bars if gaining focus and draw. */
       
   416 void CMIDForm::FocusChanged(TDrawNow /*aDrawNow*/)
       
   417 {
       
   418     DEBUG("CMIDForm::FocusChanged");
       
   419 
       
   420     TrappedLayoutAndDraw(ETrue);
       
   421 
       
   422     TInt i = -1;
       
   423     TInt itemCount = iItems.Count();
       
   424     while (++i < itemCount)
       
   425     {
       
   426         if (i == iFocused)
       
   427         {
       
   428             ControlItem(iFocused).SetFocus(IsFocused());
       
   429         }
       
   430         else
       
   431         {
       
   432             ControlItem(i).SetFocus(EFalse);
       
   433         }
       
   434     }
       
   435 
       
   436     // make sure scrollbar is up to date when we get focus
       
   437     if (IsFocused())
       
   438     {
       
   439         UpdateScrollBar();
       
   440     }
       
   441 
       
   442     DrawNow();
       
   443 }
       
   444 
       
   445 void CMIDForm::SizeChanged()
       
   446 {
       
   447     DEBUG("CMIDForm::SizeChanged");
       
   448 
       
   449     iBackgroundControlContext->SetParentPos(PositionRelativeToScreen()) ;
       
   450     iBackgroundControlContext->SetRect(Rect()) ;
       
   451 }
       
   452 
       
   453 /** Before calling CCoeControl::InputCapabilities(), make sure there is
       
   454 no outstanding layout. This is because if there is one outstanding, we have
       
   455 no rows and hence ComponentControls() returns zero. This means that, for example
       
   456 if there are any editors in the items, CCoeControl::InputCapabilities() will not
       
   457 reach them and the FEP will not be initialised. @see TrappedLayoutAndDraw(),
       
   458 CCoeControl::InputCapabilities(), CAknFepManager::HandleChangeInFocusL() and
       
   459 CCoeAppUi::InputCapabilities() */
       
   460 TCoeInputCapabilities CMIDForm::InputCapabilities() const
       
   461 {
       
   462     if (iFocused != KErrNotFound)
       
   463     {
       
   464         return ControlItem(iFocused).InputCapabilities();
       
   465     }
       
   466     return     CCoeControl::InputCapabilities(); //TCoeInputCapabilities::ENone
       
   467 }
       
   468 
       
   469 TTypeUid::Ptr CMIDForm::MopSupplyObject(TTypeUid aId)
       
   470 {
       
   471     if (aId.iUid == MAknsControlContext::ETypeId && iBackgroundControlContext)
       
   472     {
       
   473         return MAknsControlContext::SupplyMopObject(aId, iBackgroundControlContext);
       
   474     }
       
   475 
       
   476     CMIDMenuHandler* menuHandler = iDisplayable.MenuHandler();
       
   477     return SupplyMopObject(aId, menuHandler->Cba(), menuHandler->MenuBar());
       
   478 }
       
   479 
       
   480 
       
   481 #ifdef RD_SCALABLE_UI_V2
       
   482 void CMIDForm::HandlePointerEventL(const TPointerEvent& aPointerEvent)
       
   483 {
       
   484     if (!AknLayoutUtils::PenEnabled())
       
   485     {
       
   486         return;
       
   487     }
       
   488 
       
   489     if (iPhysics)
       
   490     {
       
   491         HandlePhysicsPointerEventL(aPointerEvent);
       
   492         return;
       
   493     }
       
   494 
       
   495     switch (aPointerEvent.iType)
       
   496     {
       
   497     case TPointerEvent::EButton1Down:
       
   498     {
       
   499         DEBUG_INT3("CMIDForm::HandlePointerEventL(): event=%D, x,y=%D,%D",
       
   500                    aPointerEvent.iType, aPointerEvent.iPosition.iX, aPointerEvent.iPosition.iY);
       
   501         iLastValidPointerEvent = aPointerEvent;
       
   502 
       
   503         CMIDControlItem* ci = ControlItemAtPoint(aPointerEvent.iPosition);
       
   504         // stored on ButtonDown value
       
   505 
       
   506         if (ci && ci->IsSelectable())
       
   507         {
       
   508             TInt itemIndex = ItemIndex(*ci);
       
   509             iIndexPointedControl = itemIndex;
       
   510             iLastValidPointedItemPosition = ci->Position();
       
   511             TBool changeFocus = (itemIndex != iFocused);
       
   512 
       
   513             if (changeFocus)
       
   514             {
       
   515                 // changing the focused item by dragging must start from unfocused item
       
   516                 iCanDragFocus = ETrue;
       
   517                 iFocusChangingWithPen = ETrue;
       
   518                 // give basic tactile feedback on button down when move focus
       
   519 #ifdef RD_TACTILE_FEEDBACK
       
   520                 DoFeedbackOnFocusChange(*ci);
       
   521 #endif // RD_TACTILE_FEEDBACK
       
   522                 SetFocusedItem(itemIndex, ENone, EFalse);
       
   523             }
       
   524 
       
   525             TInt scroll = ScrollDistanceToTappedItem(ci);
       
   526 
       
   527             iScrollOnPointerDown = (scroll != 0);
       
   528 
       
   529             CCoeControl::HandlePointerEventL(aPointerEvent);
       
   530 
       
   531             if (iScrollOnPointerDown)
       
   532             {
       
   533                 ScrollRelative(scroll);
       
   534                 ControlItem(iFocused).NotifyScrollingCompleted();
       
   535             }
       
   536             else if (changeFocus)
       
   537             {
       
   538                 HandleItemVisibilityChange();
       
   539                 DrawNow();
       
   540             }
       
   541             else
       
   542             {
       
   543                 iCanDragFocus = ETrue;
       
   544             }
       
   545         }
       
   546         else // pointer down did not happen on any control item, allow starting drag
       
   547         {
       
   548             iCanDragFocus = ETrue;
       
   549         }
       
   550 
       
   551         break;
       
   552     }
       
   553 
       
   554     case TPointerEvent::EButton1Up:
       
   555     {
       
   556         if (iIndexPointedControl>-1 && &ControlItem(iIndexPointedControl) == ControlItemAtPoint(aPointerEvent.iPosition))
       
   557             // When this is item where TPointerEvent::EButton1Down was happened,
       
   558             // then event is forwarded to item. It is its responsibility check that
       
   559             // up event occured if it have some actions on up event.
       
   560         {
       
   561             DEBUG_INT3("CMIDForm::HandlePointerEventL(): event=%D, x,y=%D,%D",
       
   562                        aPointerEvent.iType, aPointerEvent.iPosition.iX, aPointerEvent.iPosition.iY);
       
   563 
       
   564             HandleDragEventL(aPointerEvent, ETrue);
       
   565         }
       
   566         else
       
   567         {
       
   568             // When this is not item where TPointerEvent::EButton1Down was happened,
       
   569             // then e`vent is forwarded to item where originally. It is its responsibility
       
   570             // check that up event occured if it have some actions on up event.
       
   571             // Setting default values of related variables.
       
   572 
       
   573             if (iIndexPointedControl>-1 && &ControlItem(iIndexPointedControl))
       
   574             {
       
   575                 TBool bbutton = EFalse;
       
   576 
       
   577                 if (IsStringItem(ControlItem(iIndexPointedControl)))
       
   578                 {
       
   579                     // get appearance from StringItem
       
   580                     CMIDStringItem *strItem = static_cast< CMIDStringItem* >(&ControlItem(iIndexPointedControl));
       
   581                     MMIDItem::TAppearance appearance = strItem->Appearance();
       
   582                     bbutton = (appearance == MMIDItem::EButton || appearance == MMIDItem::EHyperLink);
       
   583                 }
       
   584 
       
   585                 if (ControlItem(iIndexPointedControl).Type() != MMIDComponent::EChoiceGroup && !bbutton)
       
   586                 {
       
   587                     TPointerEvent pointerevent;
       
   588                     pointerevent.iType = TPointerEvent::EButton1Up;
       
   589                     pointerevent.iModifiers = aPointerEvent.iModifiers;
       
   590                     pointerevent.iPosition = iLastValidPointerEvent.iPosition +
       
   591                                              ControlItem(iIndexPointedControl).Position() - iLastValidPointedItemPosition;
       
   592                     pointerevent.iParentPosition = iLastValidPointerEvent.iParentPosition;
       
   593 
       
   594                     ControlItem(iIndexPointedControl).HandlePointerEventL(pointerevent);
       
   595 
       
   596                     DEBUG_INT3("CMIDForm::HandlePointerEventL(): event=%D, x,y=%D,%D",
       
   597                                pointerevent.iType, pointerevent.iPosition.iX, pointerevent.iPosition.iY);
       
   598 
       
   599                 }
       
   600 
       
   601                 // forward event for aPointerEvent
       
   602                 CCoeControl::HandlePointerEventL(aPointerEvent);
       
   603             }
       
   604         }
       
   605 
       
   606         // If it is pending request for layout, than layout form now and refresh.
       
   607         if (LayoutPending())
       
   608         {
       
   609             LayoutFormL();
       
   610             DrawDeferred();
       
   611         }
       
   612 
       
   613         iCanDragFocus = EFalse;
       
   614         iFocusChangingWithPen = EFalse;
       
   615         iScrollOnPointerDown = EFalse;
       
   616         iIndexPointedControl = -1;
       
   617 
       
   618         break;
       
   619     }
       
   620 
       
   621     case TPointerEvent::EDrag:
       
   622         // for dragging
       
   623     {
       
   624         if (iIndexPointedControl>-1 && &ControlItem(iIndexPointedControl) == ControlItemAtPoint(aPointerEvent.iPosition))
       
   625         {
       
   626             // When this is item where TPointerEvent::EButton1Down was happened,
       
   627             // then it is updated iLastValidPointerEvent.
       
   628             iLastValidPointerEvent = aPointerEvent;
       
   629             // If it is pending request for layout, than layout Form now and refresh
       
   630             // elsewhere call HandleDragEventL and forward EDrag events to event.
       
   631             if (LayoutPending())
       
   632             {
       
   633                 LayoutFormL();
       
   634                 DrawDeferred();
       
   635             }
       
   636             else
       
   637             {
       
   638                 HandleDragEventL(aPointerEvent, ETrue);
       
   639             }
       
   640             DEBUG_INT3("CMIDForm::HandlePointerEventL(): event=%D, x,y=%D,%D",
       
   641                        aPointerEvent.iType, aPointerEvent.iPosition.iX,
       
   642                        aPointerEvent.iPosition.iY);
       
   643         }
       
   644         else
       
   645         {
       
   646             // When this is not item where TPointerEvent::EButton1Down was happened,
       
   647             // then we do only dragging. There it is not send event to item.
       
   648             HandleDragEventL(aPointerEvent, EFalse);
       
   649         }
       
   650         break;
       
   651     }
       
   652 
       
   653     case TPointerEvent::EButtonRepeat:
       
   654         // For button repeating
       
   655     {
       
   656         DEBUG_INT3("CMIDForm::HandlePointerEventL(): event=%D, x,y=%D,%D",
       
   657                    aPointerEvent.iType, aPointerEvent.iPosition.iX,
       
   658                    aPointerEvent.iPosition.iY);
       
   659 
       
   660         RequestPointerRepeat(aPointerEvent);
       
   661 
       
   662         if (iCanDragFocus)
       
   663         {
       
   664             if (aPointerEvent.iPosition.iY < 0  && CanScrollUp())
       
   665             {
       
   666                 TimedScroll(EUp);
       
   667             }
       
   668             else if (aPointerEvent.iPosition.iY > Height() && CanScrollDown())
       
   669             {
       
   670                 TimedScroll(EDown);
       
   671             }
       
   672         }
       
   673         else
       
   674         {
       
   675             CCoeControl::HandlePointerEventL(aPointerEvent);
       
   676         }
       
   677 
       
   678         break;
       
   679     }
       
   680     default:
       
   681         // By defalt only implementation of base class.
       
   682     {
       
   683         CCoeControl::HandlePointerEventL(aPointerEvent);
       
   684         DEBUG_INT3("CMIDForm::HandlePointerEventL(): event=%D, x,y=%D,%D",
       
   685                    aPointerEvent.iType, aPointerEvent.iPosition.iX,
       
   686                    aPointerEvent.iPosition.iY);
       
   687         break;
       
   688     }
       
   689     }
       
   690 }
       
   691 
       
   692 
       
   693 void CMIDForm::HandleDragEventL(const TPointerEvent& aPointerEvent, TBool aForItem)
       
   694 {
       
   695     RequestPointerRepeat(aPointerEvent);
       
   696 
       
   697     if (iCanDragFocus)
       
   698     {
       
   699         // formRect covers the whole vertical form area, but excludes
       
   700         // the left and right margins and the scroll bar area
       
   701         TRect formRect(TPoint(iFormRect.Rect().iTl.iX, 0),
       
   702                        TPoint(iFormRect.Rect().iBr.iX, Height()));
       
   703 
       
   704         // Try to find the new focused item, if needed
       
   705         if (formRect.Contains(aPointerEvent.iPosition) &&
       
   706                 !FocusedItemContainsPoint(aPointerEvent.iPosition))
       
   707         {
       
   708             CMIDControlItem* ci = ControlItemAtPoint(aPointerEvent.iPosition);
       
   709 
       
   710             if (ci && ci->IsSelectable())
       
   711             {
       
   712                 TInt itemIndex = ItemIndex(*ci);
       
   713 
       
   714                 // Find the direction to which the focus is dragged
       
   715                 TDirection direction = ENone;
       
   716                 if (iFocused != KErrNotFound)
       
   717                 {
       
   718                     TRect rect = ControlItem(iFocused).Rect();
       
   719 
       
   720                     if (aPointerEvent.iPosition.iY < rect.iTl.iY)
       
   721                     {
       
   722                         direction = EUp;
       
   723                     }
       
   724                     else if (aPointerEvent.iPosition.iY >= rect.iBr.iY)
       
   725                     {
       
   726                         direction = EDown;
       
   727                     }
       
   728                     else // focus is moved horizontally
       
   729                     {
       
   730                         direction = (itemIndex < iFocused) ? ELeft : ERight;
       
   731                     }
       
   732                 }
       
   733 
       
   734 #ifdef RD_TACTILE_FEEDBACK
       
   735                 if (iFocused != itemIndex)
       
   736                 {
       
   737                     iFeedback->InstantFeedback(ETouchFeedbackSensitive);
       
   738                 }
       
   739 #endif
       
   740                 SetFocusedItem(itemIndex, direction, EFalse);
       
   741                 HandleItemVisibilityChange();
       
   742                 DrawNow();
       
   743             }
       
   744         }
       
   745 
       
   746         if (FocusedItemContainsPoint(aPointerEvent.iPosition))
       
   747         {
       
   748             // forward EDrag events to the focused so that the focus can
       
   749             // move inside the item
       
   750             // (only when this is item where TPointerEvent::EButton1Down was occured)
       
   751 
       
   752             CMIDControlItem* focusedControl = ControlItemAtPoint(aPointerEvent.iPosition);
       
   753 
       
   754             if (aForItem || (iIndexPointedControl > -1 && &ControlItem(iIndexPointedControl) &&
       
   755                              (IsChoiceGroup(ControlItem(iIndexPointedControl)) || IsCustomItem(ControlItem(iIndexPointedControl)))) ||
       
   756                     focusedControl && IsChoiceGroup(*focusedControl) ||
       
   757                     focusedControl && IsCustomItem(*focusedControl))
       
   758             {
       
   759                 ControlItem(iFocused).HandlePointerEventL(aPointerEvent);
       
   760             }
       
   761             else
       
   762             {
       
   763                 if (iIndexPointedControl > -1 && &ControlItem(iIndexPointedControl))
       
   764                 {
       
   765                     TBool bbutton = EFalse;
       
   766 
       
   767                     if (IsStringItem(ControlItem(iIndexPointedControl)))
       
   768                     {
       
   769                         CMIDStringItem *strItem = static_cast< CMIDStringItem* >(&ControlItem(iIndexPointedControl));
       
   770                         MMIDItem::TAppearance appearance = strItem->Appearance();
       
   771                         bbutton = (appearance == MMIDItem::EButton || appearance == MMIDItem::EHyperLink);
       
   772                     }
       
   773 
       
   774                     //forward event (only for changing focus) for Button & Hyperlink
       
   775                     if (bbutton && &ControlItem(iIndexPointedControl))
       
   776                     {
       
   777                         ControlItem(iIndexPointedControl).HandlePointerEventL(aPointerEvent);
       
   778                     }
       
   779                     else
       
   780                     {
       
   781                         iDisplayable.TryDetectLongTapL(aPointerEvent);
       
   782                     }
       
   783                 }
       
   784                 else
       
   785                 {
       
   786                     iDisplayable.TryDetectLongTapL(aPointerEvent);
       
   787                 }
       
   788             }
       
   789         }
       
   790         else
       
   791         {
       
   792             // make sure that long tap animation is canceled in this case
       
   793             iDisplayable.TryDetectLongTapL(aPointerEvent);
       
   794         }
       
   795     }
       
   796     else // cannot drag focus
       
   797     {
       
   798         CCoeControl::HandlePointerEventL(aPointerEvent);
       
   799     }
       
   800 }
       
   801 
       
   802 
       
   803 void CMIDForm::RequestPointerRepeat(const TPointerEvent& aPointerEvent)
       
   804 {
       
   805     if (aPointerEvent.iPosition.iY < 0 ||
       
   806             aPointerEvent.iPosition.iY > Height())
       
   807     {
       
   808         TRect screen;
       
   809         AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EScreen, screen);
       
   810 
       
   811         TRect repeatRect = screen;
       
   812         if (aPointerEvent.iPosition.iY < 0)
       
   813         {
       
   814             repeatRect.iBr.iY = iMidpFormRect.Rect().iTl.iY;
       
   815         }
       
   816         else
       
   817         {
       
   818             repeatRect.iTl.iY = iMidpFormRect.Rect().iBr.iY;
       
   819         }
       
   820 
       
   821         // repeatRect must be given in propotion to form's window, move it up
       
   822         repeatRect.Move(0, -iMidpFormRect.Rect().iTl.iY);
       
   823         Window().RequestPointerRepeatEvent(KScrollInterval, repeatRect);
       
   824     }
       
   825 }
       
   826 
       
   827 
       
   828 void CMIDForm::TimedScroll(TDirection aDirection)
       
   829 {
       
   830     ASSERT(aDirection == EDown || aDirection == EUp);
       
   831 
       
   832     // First find the row that is the first or last row (depending on
       
   833     // the scroll direction) that is at least partailly visible on the form.
       
   834     // Search direction is opposite to aDirection.
       
   835     TDirection searchDirection = (aDirection == EUp) ? EDown : EUp;
       
   836     TInt idx = FirstRowOnScreen(searchDirection);
       
   837 
       
   838     if (idx == KErrNotFound)
       
   839     {
       
   840         return;
       
   841     }
       
   842 
       
   843     TInt scroll = Height() / KScrollAmountDividerForThumbDrag;
       
   844 
       
   845     // Find the row that will be visible (at least partially) after
       
   846     // after the scrolling.
       
   847     if (aDirection == EUp)
       
   848     {
       
   849         while (idx > 0 && (iRows[idx]->Rect().iTl.iY + scroll > 0))
       
   850         {
       
   851             --idx;
       
   852         }
       
   853     }
       
   854     else
       
   855     {
       
   856         while ((idx < iRows.Count() - 1) &&
       
   857                 (iRows[idx]->Rect().iBr.iY - scroll < Height()))
       
   858         {
       
   859             ++idx;
       
   860         }
       
   861     }
       
   862 
       
   863     TBool rowFocused = EFalse;
       
   864     if (iFocused != KErrNotFound)
       
   865     {
       
   866         rowFocused = GetControlRect(iFocused).Intersects(iRows[idx]->Rect());
       
   867     }
       
   868 
       
   869     // If the focus is not yet on the row, try to set one of its items focused
       
   870     if (!rowFocused)
       
   871     {
       
   872         for (TInt i = 0; i < iRows[idx]->NumItems(); ++i)
       
   873         {
       
   874             CMIDControlItem* item = iRows[idx]->Item(i);
       
   875             if (item->IsSelectable())
       
   876             {
       
   877                 SetFocusedItem(ItemIndex(*item), aDirection, EFalse);
       
   878             }
       
   879         }
       
   880     }
       
   881 
       
   882 #ifdef RD_TACTILE_FEEDBACK
       
   883     iFeedback->InstantFeedback(ETouchFeedbackSensitive);
       
   884 #endif
       
   885 
       
   886     ScrollRelative((aDirection == EUp) ? scroll : -scroll);
       
   887 }
       
   888 
       
   889 
       
   890 TBool CMIDForm::CanScrollUp() const
       
   891 {
       
   892     return (iScroll < 0);
       
   893 }
       
   894 
       
   895 
       
   896 TBool CMIDForm::CanScrollDown() const
       
   897 {
       
   898     return ((iFormHeight - iScroll) < iTotalFormHeight);
       
   899 }
       
   900 
       
   901 
       
   902 TBool CMIDForm::FocusedItemContainsPoint(const TPoint& aPoint) const
       
   903 {
       
   904     if (iFocused != KErrNotFound)
       
   905     {
       
   906         if (ItemIsUnconstrained(iFocused))
       
   907         {
       
   908             return StringItemContainsPoint(
       
   909                        static_cast<CMIDStringItem*>(&ControlItem(iFocused)), aPoint);
       
   910         }
       
   911         else
       
   912         {
       
   913             return ControlItem(iFocused).Rect().Contains(aPoint);
       
   914         }
       
   915     }
       
   916     else
       
   917     {
       
   918         return EFalse;
       
   919     }
       
   920 }
       
   921 
       
   922 CMIDControlItem* CMIDForm::ControlItemAtPoint(const TPoint& aPoint) const
       
   923 {
       
   924     TInt idx = RowAtPoint(aPoint);
       
   925 
       
   926     if (idx != KErrNotFound)
       
   927     {
       
   928         for (TInt i = 0; i < iRows[idx]->NumItems(); ++i)
       
   929         {
       
   930             CMIDControlItem* ci = iRows[idx]->Item(i);
       
   931             if (ci && ci->Rect().Contains(aPoint))
       
   932             {
       
   933                 return ci;
       
   934             }
       
   935         }
       
   936     }
       
   937 
       
   938     return NULL;
       
   939 }
       
   940 
       
   941 
       
   942 TInt CMIDForm::RowAtPoint(const TPoint& aPoint) const
       
   943 {
       
   944     TInt rowCount = iRows.Count();
       
   945     // loop until the first row fully below the visible form area
       
   946     for (TInt i = 0; i < rowCount && (iRows[i]->Position().iY < iFormHeight); ++i)
       
   947     {
       
   948         if (iRows[i]->Rect().Contains(aPoint))
       
   949         {
       
   950             return i;
       
   951         }
       
   952     }
       
   953     return KErrNotFound;
       
   954 }
       
   955 
       
   956 #endif // #ifdef RD_SCALABLE_UI_V2
       
   957 
       
   958 
       
   959 void CMIDForm::SetFocusedItemIfNone(CMIDItem* aItem)
       
   960 {
       
   961     if (iFocused == KErrNotFound)
       
   962     {
       
   963         ASSERT(aItem);
       
   964         TInt index = Index(aItem);
       
   965 
       
   966         if (index >= 0 && index < iItems.Count())
       
   967         {
       
   968             CMIDControlItem& ci = ControlItem(iItems[index]);
       
   969             if (ci.IsSelectable())
       
   970             {
       
   971                 SetFocusedItem(index);
       
   972                 ScrollToFocused();
       
   973             }
       
   974         }
       
   975     }
       
   976 }
       
   977 
       
   978 /** This method is called when an item loses focusability,
       
   979 for example because it loses all its commands. If this item
       
   980 is focused, call ReplaceFocusedItem() to find another focusable
       
   981 item. @see CMIDItem::RemoveCommand() and  ReplaceFocusedItem*/
       
   982 void CMIDForm::RemoveFocusIfFocused(CMIDItem* aItem)
       
   983 {
       
   984     ASSERT(aItem);
       
   985     TInt index = Index(aItem);
       
   986     if (iFocused == index)
       
   987     {
       
   988         // Hide menu because item has lost all item commands and
       
   989         // another item may have become focused behind the menu.
       
   990         iDisplayable.MenuHandler()->HideMenuIfVisible();
       
   991         ReplaceFocusedItem();
       
   992     }
       
   993 }
       
   994 
       
   995 /**
       
   996  * Traverse is a method to go thorough the form; it includes moving focus from
       
   997  * item to another possibly scrolling the form. Note that sometimes traversal
       
   998  * does not move focus, because an item is larger that the screen and thus form
       
   999  * is scrolled little by little so that the user can see the whole content. On
       
  1000  * other cases, traversing means only moving focus from item to another as both
       
  1001  * items are visible on the screen.
       
  1002  *
       
  1003  * @param  aDirection defines the direction of the traversing (up, down, left, right).
       
  1004  **/
       
  1005 void CMIDForm::Traverse(TDirection aDirection)
       
  1006 {
       
  1007     DEBUG("< CMIDForm::Traverse");
       
  1008     DEBUG_INT("< CMIDForm::Traverse Direction is %D", aDirection);
       
  1009     TBool horizontalScroll = EFalse;
       
  1010 
       
  1011     if (LayoutPending())
       
  1012     {
       
  1013         DEBUG("CMIDForm::Traverse - calling layout");
       
  1014         // lets do the layout now so we can always assume that we are layed out before doing this stuff
       
  1015         TrappedLayoutAndDraw();
       
  1016     }
       
  1017 
       
  1018 #ifdef RD_SCALABLE_UI_V2
       
  1019     TBool focusHidden = EFalse;
       
  1020     // If the focused item is currently fully outside the visible form area,
       
  1021     // it means that form has been scrolled by moving the scrollbar with pen. In this case
       
  1022     // set iFocused (temporarily) to KErrNone in order that scrolling with arrow keys works ok.
       
  1023     if (iFocused != KErrNotFound && !RectPartiallyVisible(GetControlRect(iFocused)))
       
  1024     {
       
  1025         focusHidden = ETrue;
       
  1026         SetFocusedItem(KErrNotFound, ENone, EFalse);
       
  1027     }
       
  1028 #endif
       
  1029 
       
  1030     if (aDirection == ELeft || aDirection == ERight)
       
  1031     {
       
  1032         DEBUG("CMIDForm::Traverse - move focus horizontally");
       
  1033         if (!TryMovingFocusHorizontally(aDirection))
       
  1034         {
       
  1035             if (iInitialAlignment == MMIDItem::ERight)
       
  1036             {//RIGHT TO LEFT
       
  1037                 TryMovingFocusVertically(aDirection == ELeft ? EDown : EUp, EFalse);
       
  1038             }
       
  1039             else
       
  1040             {//LEFT TO RIGHT
       
  1041                 TryMovingFocusVertically(aDirection == ELeft ? EUp : EDown, EFalse);
       
  1042             }
       
  1043         }
       
  1044         else
       
  1045         {
       
  1046             horizontalScroll = ETrue;
       
  1047         }
       
  1048     }
       
  1049     else if (aDirection == EUp || aDirection == EDown)
       
  1050     {
       
  1051         DEBUG("CMIDForm::Traverse - move focus vertically");
       
  1052         TryMovingFocusVertically(aDirection, ETrue);
       
  1053     }
       
  1054 
       
  1055     // if there is still a focused item, make sure it is still on the screen.
       
  1056     // if it isn't remove focus as we've already tried out best to have a
       
  1057     // focussed item on screen
       
  1058     if (iFocused != KErrNotFound)
       
  1059     {
       
  1060         TRect rect = GetControlRect(iFocused);
       
  1061         if (!RectPartiallyVisible(rect))
       
  1062         {
       
  1063             SetFocusedItem(KErrNotFound, ENone);
       
  1064         }
       
  1065     }
       
  1066 #ifdef RD_SCALABLE_UI_V2
       
  1067     else if (focusHidden)
       
  1068     {
       
  1069         // Try to bring the focus back to visible area by setting the last focusable
       
  1070         // item in the scroll direction focused.
       
  1071         TDirection searchDirection = (aDirection == EDown || aDirection == ERight) ?
       
  1072                                      EUp : EDown;
       
  1073         TInt newFocusIndex  = IndexOfFirstFocusableItemOnScreen(searchDirection);
       
  1074         if (newFocusIndex != KErrNotFound)
       
  1075         {
       
  1076             // Pass searchDirection also to SetFocusedItem(). This is needed at least
       
  1077             // for choice group and custom item cases, so that they can set there
       
  1078             // internal focus to the last element in the actual scroll direction.
       
  1079             SetFocusedItem(newFocusIndex, searchDirection, EFalse);
       
  1080             DrawDeferred();
       
  1081         }
       
  1082     }
       
  1083 #endif
       
  1084 
       
  1085     RawScrollFinalize(horizontalScroll);
       
  1086     DEBUG("> CMIDForm::Traverse");
       
  1087 }
       
  1088 
       
  1089 
       
  1090 // -----------------------------------------------------------------------------
       
  1091 // Form scrolling methods
       
  1092 // -----------------------------------------------------------------------------
       
  1093 /**
       
  1094  * Scroll to the focused control if there is one and update form visibility (draw) and scroll bar.
       
  1095  * @see ScrollToRect() and SetRowExtentsWithRespectToScrolledLocation().
       
  1096  **/
       
  1097 void CMIDForm::ScrollToFocused(TDirection aDirection /*=EDown*/, TBool aReset /*= ETrue*/)
       
  1098 {
       
  1099     DEBUG("< CMIDForm::ScrollToFocused");
       
  1100     if (!LayoutPending())
       
  1101     {
       
  1102         if (iFocused != KErrNotFound)
       
  1103         {
       
  1104             TRect rect = GetControlRect(iFocused);
       
  1105             DEBUG_INT4("CMIDForm::ScrollToFocused - rect is %D %D %D %D",
       
  1106                        rect.iTl.iX, rect.iTl.iY, rect.iBr.iX, rect.iBr.iY);
       
  1107             RawScrollToRect(rect, aDirection, aReset);
       
  1108         }
       
  1109 
       
  1110         RawScrollFinalize(ETrue);
       
  1111 
       
  1112         if (iFocused != KErrNotFound)
       
  1113         {
       
  1114             ControlItem(iFocused).NotifyScrollingCompleted();
       
  1115         }
       
  1116     }
       
  1117 
       
  1118     UpdatePhysics();
       
  1119 
       
  1120     DEBUG("> CMIDForm::ScrollToFocused");
       
  1121 }
       
  1122 
       
  1123 TInt CMIDForm::ScrollDistanceToTappedItem(CMIDControlItem* aPointedControl)
       
  1124 {
       
  1125     TRect focusedRect = aPointedControl->Rect();
       
  1126     TInt scroll = 0;
       
  1127 
       
  1128     // Calculate how much we need to scroll to make the tapped item fully/more visible
       
  1129     if (!RectFullyVisible(focusedRect))
       
  1130     {
       
  1131         TInt topMargin = iFormRect.Rect().iTl.iY - iMidpFormRect.Rect().iTl.iY;
       
  1132         TInt bottomMargin = iMidpFormRect.Rect().iBr.iY - iFormRect.Rect().iBr.iY;
       
  1133 
       
  1134         if (focusedRect.Height() <= Height())
       
  1135         {
       
  1136             scroll = (focusedRect.iBr.iY > Height()) ?
       
  1137                      Height() - focusedRect.iBr.iY : -focusedRect.iTl.iY;
       
  1138         }
       
  1139         // Scroll long item so that it fills the whole form height.
       
  1140         // No scroll in case item already fills the whole screen or if there would
       
  1141         // be just few pixels (~margins) to scroll.
       
  1142         else if ((focusedRect.iTl.iY > 0 && focusedRect.iTl.iY > topMargin) ||
       
  1143                  (focusedRect.iBr.iY < Height() &&
       
  1144                   Height() - focusedRect.iBr.iY > bottomMargin))
       
  1145         {
       
  1146             scroll = (focusedRect.iTl.iY > 0) ?
       
  1147                      -focusedRect.iTl.iY : -(focusedRect.iBr.iY - Height());
       
  1148         }
       
  1149     }
       
  1150     return scroll;
       
  1151 }
       
  1152 
       
  1153 /**
       
  1154  * Scrolls to the rect corresponding to the row specified by aIdx using
       
  1155  * the direction indicated by aDirection. @see ScrollToRect()
       
  1156  **/
       
  1157 void CMIDForm::RawScrollToRow(TInt aIdx, TDirection aDirection)
       
  1158 {
       
  1159     DEBUG("< CMIDForm::RawScrollToRow");
       
  1160     if (aIdx >= 0 && aIdx < iRows.Count())
       
  1161     {
       
  1162         TRect rect = iRows[aIdx]->Rect();
       
  1163         DEBUG("CMIDForm::RawScrollToRow - scroll to rect");
       
  1164         RawScrollToRect(rect, aDirection);
       
  1165     }
       
  1166     DEBUG("> CMIDForm::RawScrollToRow");
       
  1167 }
       
  1168 
       
  1169 /** */
       
  1170 void CMIDForm::RawScrollToRect(const TRect& aRect, TDirection aDirection, TBool aReset)
       
  1171 {
       
  1172     DEBUG("< CMIDForm::RawScrollToRect");
       
  1173     DEBUG_INT4("CMIDForm::RawScrollToRect - rect is %D %D %D %D", aRect.iTl.iX, aRect.iTl.iY,
       
  1174                aRect.iBr.iX, aRect.iBr.iY);
       
  1175 
       
  1176     if (RectFullyVisible(aRect))
       
  1177     {
       
  1178         DEBUG("CMIDForm::RawScrollToRect - return rect fully visible");
       
  1179         TInt maxScrollValue = Height() - HeightOfAllItems();
       
  1180         // Avoid scrolling out of the form (i.e. after the view port has lower height)
       
  1181 
       
  1182         if (iScroll < maxScrollValue)
       
  1183         {
       
  1184             RawScroll(maxScrollValue);
       
  1185         }
       
  1186         return;
       
  1187     }
       
  1188 
       
  1189     TInt scrollOffset = 0;
       
  1190     if (aRect.Size().iHeight > Height())
       
  1191     {//rect higher than screen height
       
  1192         if (RectPartiallyVisible(aRect) && !aReset)
       
  1193         {//if already visible, scroll only of KMinScrollAmount (panning)
       
  1194             scrollOffset = (aDirection == EDown) ? -KMinScrollAmount : KMinScrollAmount;
       
  1195         }
       
  1196         else
       
  1197         {//if not visible and scrolling down scroll to top - KMinScrollAmount
       
  1198             // or to bottom + KMinScrollAmount if scrolling up
       
  1199             scrollOffset = (aDirection == EDown) ? (Height() - (aRect.iTl.iY + KMinScrollAmount))
       
  1200                            : -(aRect.iBr.iY - KMinScrollAmount);
       
  1201         }
       
  1202     }
       
  1203     else
       
  1204     {//if it fits on screen make sure its BR is at the bottom if scrolling down
       
  1205         //or its TL is at the top if scrolling up
       
  1206         scrollOffset = (aDirection == EDown) ? (Height() - aRect.iBr.iY) : (-aRect.iTl.iY);
       
  1207     }
       
  1208 
       
  1209     RawScroll(iScroll + scrollOffset);
       
  1210     DEBUG("> CMIDForm::RawScrollToRect");
       
  1211 }
       
  1212 
       
  1213 void CMIDForm::ScrollRelative(TInt aScroll)
       
  1214 {
       
  1215     DEBUG("CMIDForm::ScrollRelative");
       
  1216     RawScrollRelative(aScroll);
       
  1217     RawScrollFinalize(EFalse);
       
  1218 }
       
  1219 
       
  1220 void CMIDForm::RawScrollRelative(TInt aScroll)
       
  1221 {
       
  1222     TInt scroll = iScroll + aScroll;
       
  1223     RawScroll(scroll);
       
  1224 }
       
  1225 
       
  1226 void CMIDForm::RawScroll(TInt aScroll)
       
  1227 {
       
  1228     TInt contentHeight  = HeightOfAllItems();
       
  1229     TInt viewPortHeight = Height();
       
  1230     if (aScroll > 0 || contentHeight <= viewPortHeight)
       
  1231     { // make sure that top does not slide down
       
  1232         aScroll = 0;
       
  1233     }
       
  1234     if (contentHeight > viewPortHeight && ((-aScroll) + viewPortHeight) > contentHeight)
       
  1235     { // scroll only as long as there is content
       
  1236         aScroll = -(contentHeight - viewPortHeight);
       
  1237     }
       
  1238     iHasScrolled = iScroll != aScroll;
       
  1239     iScrollDelta = aScroll - iScroll;
       
  1240     iScroll = aScroll;
       
  1241 
       
  1242     SetRowPositionsWithRespectToScrolledLocation();
       
  1243 }
       
  1244 
       
  1245 void CMIDForm::SetRowExtentsWithRespectToScrolledLocation()
       
  1246 {
       
  1247     iTotalFormHeight = 0;
       
  1248     TInt xMargin = iFormRect.Rect().iTl.iX;
       
  1249     TInt yTopMargin = iFormRect.Rect().iTl.iY - iMidpFormRect.Rect().iTl.iY;
       
  1250     TInt yBottomMargin = iMidpFormRect.Rect().iBr.iY - iFormRect.Rect().iBr.iY;
       
  1251 
       
  1252     iTotalFormHeight = yTopMargin;
       
  1253 
       
  1254     TInt rowCount = iRows.Count();
       
  1255     for (TInt i=0; i < rowCount; i++)
       
  1256     {
       
  1257         // Form left margin is added in the beginning of each row
       
  1258         iRows[i]->SetExtent(TPoint(xMargin, iScroll + iTotalFormHeight),
       
  1259                             TSize(Width(), iRows[i]->Size().iHeight));
       
  1260         iTotalFormHeight += iRows[i]->Size().iHeight;
       
  1261     }
       
  1262     // Form bottom margin is added
       
  1263     iTotalFormHeight += yBottomMargin;
       
  1264 }
       
  1265 
       
  1266 void CMIDForm::SetRowPositionsWithRespectToScrolledLocation()
       
  1267 {
       
  1268     TInt rowCount = iRows.Count();
       
  1269     for (TInt i=0; i < rowCount; i++)
       
  1270     {
       
  1271         // Form left margin is added in the beginning of each row
       
  1272         TPoint pos = iRows[i]->Position();
       
  1273         pos.iY += ScrollDelta();
       
  1274         iRows[i]->SetPosition(pos);
       
  1275     }
       
  1276 }
       
  1277 
       
  1278 // Finalizes scrolling after any RawScrollXxxx method call, e.g. causes repaint.
       
  1279 // Draw can be prevented e.g. because of the performance reasons.
       
  1280 void CMIDForm::RawScrollFinalize(TBool forseAction, TBool aDraw /*= ETrue*/)
       
  1281 {
       
  1282     if (iHasScrolled || forseAction)
       
  1283     {
       
  1284         UpdateHighlightBackgroundPosition();
       
  1285         HandleItemVisibilityChange();
       
  1286         UpdateScrollBar();
       
  1287         if (iFocused != KErrNotFound)
       
  1288         {
       
  1289             CMIDControlItem& ci = ControlItem(iFocused);
       
  1290             if (IsTextFieldItem(ci))
       
  1291             {
       
  1292                 if (RectPartiallyVisible(ci.Rect()))
       
  1293                 {
       
  1294                     ((CMIDTextFieldItem&) ci).SetCursorVisibility(ETrue);
       
  1295                 }
       
  1296                 else
       
  1297                 {
       
  1298                     ((CMIDTextFieldItem&) ci).SetCursorVisibility(EFalse);
       
  1299                 }
       
  1300             }
       
  1301             if (IsDateField(ci))
       
  1302             {
       
  1303                 // Update right cursor position on Datefiled
       
  1304                 ((CMIDDateFieldItem&) ci).CursorUpdate();
       
  1305             }
       
  1306         }
       
  1307         if (aDraw)
       
  1308         {
       
  1309             DrawDeferred();
       
  1310         }
       
  1311         iHasScrolled = EFalse;
       
  1312     }
       
  1313 }
       
  1314 
       
  1315 /** Returns the client area */
       
  1316 TRect CMIDForm::GetClientArea()
       
  1317 {
       
  1318     TRect scrolledClientArea = TRect(Position(), TSize(Width(), Height()));
       
  1319     return scrolledClientArea;
       
  1320 }
       
  1321 
       
  1322 // returns ETrue if it moved the focus
       
  1323 // returns EFalse otherwise
       
  1324 TBool CMIDForm::TryMovingFocusHorizontally(TDirection aDirection)
       
  1325 {
       
  1326     ASSERT(aDirection == ELeft || aDirection == ERight);
       
  1327 
       
  1328     TInt idx = NextFocusableHorizontalIdx(aDirection);
       
  1329     if (idx != KErrNotFound)
       
  1330     {
       
  1331         SetFocusedItem(idx, aDirection);
       
  1332         return ETrue;
       
  1333     }
       
  1334 
       
  1335     return EFalse;
       
  1336 }
       
  1337 
       
  1338 /**
       
  1339   Moves the focus vertically.
       
  1340 
       
  1341   We check if there is a focussable item,
       
  1342   which is on a row totally or partially visible and if there is such
       
  1343   an item we then select that row. This is done by calling
       
  1344   NextPartiallyVisibleRowWithFocusableItem(). If no such item was found we pick
       
  1345   the top or bottom (depending on scrolling direction) row that is partially
       
  1346   visible or the first not visible if the last one is completely shown.
       
  1347   This is done by FirstRowWithBottomBelowScreen() and LastRowWithTopAboveScreen().
       
  1348 
       
  1349   At this point if we have a row,  we select a focussable item on it and
       
  1350   scroll to it if aScroll is true. Calling scroll methods doesn't mean there is going to be
       
  1351   scrolling of the form,
       
  1352   if the item is already visible no scrolling is done. We select the
       
  1353   next focussable item according to the value of the parameter aSelectClosest.
       
  1354   If this paramerter is true we call SelectClosestFocussableItem() otherwise
       
  1355   we either select the first or the last selectable item on the row depending
       
  1356   on the direction.
       
  1357 
       
  1358   If we find a control we scroll to it by calling ScrollToFocused() (if aScroll is true) and move
       
  1359   the focus to it by calling SetFocusedItem(). Otherwise we
       
  1360   scroll to the row by calling ScrollToRow() if aScroll is true.
       
  1361 
       
  1362   If we could not find any row with a focusable item on it, we scroll the form
       
  1363   of a fixed quantity, KMinScrollAmount, if aScroll is true.
       
  1364 
       
  1365   We return ETrue if the focus was moved, EFalse otherwise. Note: Currently the
       
  1366   return value of this method is ignored.
       
  1367 
       
  1368   @see  NextPartiallyVisibleRowWithFocusableItem(), FirstRowWithBottomBelowScreen(),
       
  1369               LastRowWithTopAboveScreen(), SelectClosestFocussableItem()
       
  1370                    ScrollToRow(), SetFocusedItem() and DoScrollRelative().
       
  1371            Also see ReplaceFocusedItem(), called when the focused item is removed or
       
  1372            loses focusability - in this case no scrolling will occur.
       
  1373   */
       
  1374 TBool CMIDForm::TryMovingFocusVertically(TDirection aDirection, TBool aSelectClosest,
       
  1375         TBool aScroll /*=ETrue*/)
       
  1376 {
       
  1377     DEBUG("> CMIDForm::TryMovingFocusVertically");
       
  1378     ASSERT(aDirection == EUp || aDirection == EDown);
       
  1379 
       
  1380     // is VKB opened
       
  1381     if (iDisplayable.IsVKBOnScreen())
       
  1382     {
       
  1383         return ETrue;
       
  1384     }
       
  1385 
       
  1386     TInt rowIdx = NextPartiallyVisibleRowWithFocusableItem(aDirection);
       
  1387 
       
  1388     if (rowIdx == KErrNotFound)
       
  1389     {
       
  1390         DEBUG("CMIDForm::TryMovingFocusVertically - no partially visible focusable control found");
       
  1391         rowIdx = aDirection == EDown ? FirstRowWithBottomBelowScreen() : LastRowWithTopAboveScreen();
       
  1392     }
       
  1393 
       
  1394     if (rowIdx != KErrNotFound)
       
  1395     {
       
  1396         CMIDControlItem* ci = aSelectClosest ? SelectClosestFocussableItem(rowIdx) :
       
  1397                               (aDirection == EDown ? iRows[rowIdx]->FirstFocusableItem() :
       
  1398                                iRows[rowIdx]->LastFocusableItem());
       
  1399 
       
  1400 
       
  1401         if (ci)
       
  1402         {
       
  1403             DEBUG("CMIDForm::TryMovingFocusVertically - got control");
       
  1404             TInt index = Index(ci);
       
  1405 
       
  1406             if (index == KErrNotFound && IsLabelContainerItem(*ci))
       
  1407             {
       
  1408                 CMIDLabelContainerItem* ucsi = static_cast<CMIDLabelContainerItem*>(ci);
       
  1409                 CMIDStringItem& si = ucsi->StringItem();
       
  1410                 index = Index(&si);
       
  1411             }
       
  1412 
       
  1413             if (index != KErrNotFound)
       
  1414             {
       
  1415                 TRect rect = GetControlRect(index);
       
  1416 
       
  1417                 if (aScroll)
       
  1418                 {
       
  1419                     SetFocusedItem(index, aDirection, ETrue);
       
  1420                 }
       
  1421                 else if (RectPartiallyVisible(rect))
       
  1422                 {
       
  1423                     SetFocusedItem(index, aDirection);
       
  1424                 }
       
  1425                 else
       
  1426                 {
       
  1427                     SetFocusedItem(KErrNotFound);
       
  1428                 }
       
  1429 
       
  1430                 DEBUG("CMIDForm::TryMovingFocusVertically - out after scroll to control");
       
  1431                 return ETrue;
       
  1432             }
       
  1433         }
       
  1434 
       
  1435         DEBUG("CMIDForm::TryMovingFocusVertically - scrolling to row");
       
  1436         if (aScroll)
       
  1437         {
       
  1438             RawScrollToRow(rowIdx, aDirection);
       
  1439         }
       
  1440     }
       
  1441     else
       
  1442     {
       
  1443         DEBUG("CMIDForm::TryMovingFocusVertically - small default scrolling");
       
  1444         if (aScroll)
       
  1445         {
       
  1446             RawScrollRelative((aDirection == EDown) ? -KMinScrollAmount : KMinScrollAmount);
       
  1447         }
       
  1448     }
       
  1449 
       
  1450     DEBUG("< CMIDForm::TryMovingFocusVertically");
       
  1451     return EFalse;
       
  1452 }
       
  1453 
       
  1454 /** Given a row index, selects on this row the focusable control whose center on
       
  1455 the x axis is closes to the center of the currently focused item, if there is one.
       
  1456 If no control is found, returns the first selectable item on the row. */
       
  1457 CMIDControlItem* CMIDForm::SelectClosestFocussableItem(TInt aRowIndex) const
       
  1458 {
       
  1459     ASSERT(aRowIndex >= 0 && aRowIndex < iRows.Count());
       
  1460     TInt selectedIndex = -1;
       
  1461 
       
  1462     if (iFocused != -1)
       
  1463     {
       
  1464         TRect rect = GetControlRect(iFocused);
       
  1465         TInt focusedCenter = rect.iTl.iX + rect.Width()/2;
       
  1466 
       
  1467         TInt diff = iInnerWidth;
       
  1468 
       
  1469         TInt numItemsOnRow = iRows[aRowIndex]->NumItems();
       
  1470         for (TInt i = 0; i < numItemsOnRow; i++)
       
  1471         {
       
  1472             CMIDControlItem* item = iRows[aRowIndex]->Item(i);
       
  1473             if (item->IsSelectable())
       
  1474             {
       
  1475                 TInt center = item->Position().iX + (item->Size().iWidth / 2);
       
  1476                 TInt itemDiff = focusedCenter > center ? (focusedCenter - center) : (center - focusedCenter);
       
  1477 
       
  1478                 if (itemDiff < diff)
       
  1479                 {
       
  1480                     selectedIndex = i;
       
  1481                     diff = itemDiff;
       
  1482                 }
       
  1483             }
       
  1484         }
       
  1485     }
       
  1486 
       
  1487     return selectedIndex == -1 ? iRows[aRowIndex]->FirstFocusableItem() :
       
  1488            iRows[aRowIndex]->Item(selectedIndex);
       
  1489 }
       
  1490 
       
  1491 TInt CMIDForm::IndexOfFirstFocusableItemOnScreen(TDirection aDirection)
       
  1492 {
       
  1493     ASSERT(aDirection == EUp || aDirection == EDown);
       
  1494 
       
  1495     TInt startIdx = FirstRowOnScreen(aDirection);
       
  1496 
       
  1497     if (startIdx == KErrNotFound)
       
  1498     {
       
  1499         return KErrNotFound;
       
  1500     }
       
  1501 
       
  1502     CMIDControlItem* ci = NULL;
       
  1503 
       
  1504     if (aDirection == EDown)
       
  1505     {
       
  1506         TInt idx = startIdx - 1;
       
  1507         TInt rowCount = iRows.Count();
       
  1508         while (++idx < rowCount)
       
  1509         {
       
  1510             CMIDFormRow* row = iRows[idx];
       
  1511             if (row->Position().iY > Height())
       
  1512             {
       
  1513                 break;
       
  1514             }
       
  1515             ci = row->FirstFocusableItemOnScreen();
       
  1516             if (ci)
       
  1517             {
       
  1518                 break;
       
  1519             }
       
  1520         }
       
  1521     }
       
  1522     else
       
  1523     {
       
  1524         TInt idx = startIdx + 1;
       
  1525         while (--idx >= 0)
       
  1526         {
       
  1527             CMIDFormRow* row = iRows[idx];
       
  1528             if ((row->Position().iY + row->Size().iHeight) < 0)
       
  1529             {
       
  1530                 break;
       
  1531             }
       
  1532             ci = row->FirstFocusableItemOnScreen();
       
  1533             if (ci)
       
  1534             {
       
  1535                 break;
       
  1536             }
       
  1537         }
       
  1538     }
       
  1539 
       
  1540     if (!ci)
       
  1541     {
       
  1542         return KErrNotFound;
       
  1543     }
       
  1544 
       
  1545     TInt index = Index(ci);
       
  1546     if (index == KErrNotFound)
       
  1547     {
       
  1548         if (IsLabelContainerItem(*ci))
       
  1549         {
       
  1550             CMIDLabelContainerItem* ucsi = static_cast<CMIDLabelContainerItem*>(ci);
       
  1551             CMIDStringItem& si = ucsi->StringItem();
       
  1552             index = Index(&si);
       
  1553         }
       
  1554     }
       
  1555 
       
  1556     return index;
       
  1557 }
       
  1558 
       
  1559 /** Return the rect for a control, taking into account if the control is an
       
  1560 unconstrained string item which has been split over more than one label container
       
  1561 */
       
  1562 TRect CMIDForm::GetControlRect(TInt aIdx) const
       
  1563 {
       
  1564     CMIDControlItem& ci = ControlItem(aIdx);
       
  1565     TRect rect;
       
  1566 
       
  1567     if (ItemIsUnconstrained(aIdx))
       
  1568     {
       
  1569         rect = GetUnconstrainedStringItemRect(static_cast<CMIDStringItem*>(&ci));
       
  1570     }
       
  1571     else
       
  1572     {
       
  1573         rect = ci.Rect();
       
  1574     }
       
  1575 
       
  1576     return rect;
       
  1577 }
       
  1578 
       
  1579 /** Collate rects for unconstrained string items that have been split across more
       
  1580 than one lable container */
       
  1581 TRect CMIDForm::GetUnconstrainedStringItemRect(CMIDStringItem* aStringItem) const
       
  1582 {
       
  1583     TRect rect(0,0,0,0);
       
  1584     TBool found = EFalse;
       
  1585 
       
  1586     TInt rowIdx = FirstRowOfUnconstrainedStringItem(*aStringItem);
       
  1587     TInt rowCount = iRows.Count();
       
  1588 
       
  1589     // if the first row of unconstrained string item cannot be found
       
  1590     // it means that string item is placed as default item
       
  1591     // so simply return item's rect
       
  1592     if (rowIdx == KErrNotFound)
       
  1593     {
       
  1594         return aStringItem->Rect();
       
  1595     }
       
  1596 
       
  1597     while (rowIdx != KErrNotFound && rowIdx < rowCount)
       
  1598     {
       
  1599         CMIDFormRow* row = iRows[rowIdx];
       
  1600         for (TInt idxOnRow = 0; idxOnRow < row->NumItems(); idxOnRow++)
       
  1601         {
       
  1602             CMIDControlItem* ci = row->Item(idxOnRow);
       
  1603             if (ci && IsLabelContainerItem(*ci))
       
  1604             {
       
  1605                 CMIDLabelContainerItem* usil = static_cast<CMIDLabelContainerItem*>(ci);
       
  1606                 CMIDStringItem* si = &(usil->StringItem());
       
  1607 
       
  1608                 if (si == aStringItem)
       
  1609                 {
       
  1610                     if (!found)
       
  1611                     {
       
  1612                         rect.iTl = usil->Rect().iTl;
       
  1613                         found = ETrue;
       
  1614                     }
       
  1615                     rect.iBr = usil->Rect().iBr;
       
  1616                 }
       
  1617                 else if (found)
       
  1618                 {
       
  1619                     return rect;
       
  1620                 }
       
  1621             }
       
  1622             else if (found)
       
  1623             {
       
  1624                 return rect;
       
  1625             }
       
  1626         }
       
  1627         rowIdx++;
       
  1628     }
       
  1629 
       
  1630     return rect;
       
  1631 }
       
  1632 
       
  1633 TBool CMIDForm::RectPartiallyVisible(const TRect& aRect)
       
  1634 {
       
  1635     return ((aRect.iTl.iY >= 0) && (aRect.iTl.iY < Height())) ||
       
  1636            ((aRect.iBr.iY >= 0) && (aRect.iBr.iY < Height())) ||
       
  1637            ((aRect.iTl.iY < 0) && (aRect.iBr.iY >= Height()));
       
  1638 }
       
  1639 
       
  1640 TBool CMIDForm::RectFullyVisible(const TRect& aRect)
       
  1641 {
       
  1642     return (aRect.iTl.iY >= 0) && (aRect.iBr.iY <= Height());
       
  1643 }
       
  1644 
       
  1645 TInt CMIDForm::FirstRowWithBottomBelowScreen()
       
  1646 {
       
  1647     TInt idx = -1;
       
  1648     TInt rowWithFocus = iFocused == KErrNotFound ? -1 : Row(ControlItem(iFocused));
       
  1649     TInt rowCount = iRows.Count();
       
  1650     while (++idx < rowCount)
       
  1651     {
       
  1652         CMIDFormRow* row = iRows[idx];
       
  1653         TInt height = row->Size().iHeight;
       
  1654         TInt yPos = row->Position().iY;
       
  1655         if ((height + yPos) > Height() && row->HasNonSpacerItems() && idx != rowWithFocus)
       
  1656         {
       
  1657             return idx;
       
  1658         }
       
  1659     }
       
  1660 
       
  1661     return KErrNotFound;
       
  1662 }
       
  1663 
       
  1664 TInt CMIDForm::LastRowWithTopAboveScreen()
       
  1665 {
       
  1666     TInt idx = iRows.Count();
       
  1667     TInt rowWithFocus = iFocused == KErrNotFound ? -1 : Row(ControlItem(iFocused));
       
  1668 
       
  1669     while (--idx >= 0)
       
  1670     {
       
  1671         CMIDFormRow* row = iRows[idx];
       
  1672         TInt yPos = row->Position().iY;
       
  1673         if (yPos < 0 && row->HasNonSpacerItems() && idx != rowWithFocus)
       
  1674         {
       
  1675             return idx;
       
  1676         }
       
  1677     }
       
  1678 
       
  1679     return KErrNotFound;
       
  1680 }
       
  1681 
       
  1682 // note: inspite of the name of this method, we only consider rows with
       
  1683 // a focusable item that has not already been scrolled off the screen.
       
  1684 // For Example:
       
  1685 //
       
  1686 //  ----
       
  1687 // | A  | This is a
       
  1688 // |    | string item
       
  1689 //  ----  that is placed
       
  1690 //----------------------- <- top of form
       
  1691 //        next to item A.
       
  1692 //        This
       
  1693 //        string
       
  1694 //        item
       
  1695 //        is
       
  1696 //        quite
       
  1697 //        tall
       
  1698 //        and
       
  1699 //----------------------- <- botom of form
       
  1700 //        fills
       
  1701 //        the
       
  1702 //        screen
       
  1703 //
       
  1704 // Assuming that A is focusable, and we are scrolling down, and also assuming
       
  1705 // that the string item is not focusable, we do not consider A when looking
       
  1706 // for focusable items, because we are scrolling down and A is already above
       
  1707 // the screen.
       
  1708 TInt CMIDForm::NextPartiallyVisibleRowWithFocusableItem(TDirection aDirection)
       
  1709 {
       
  1710     ASSERT(aDirection == EUp || aDirection == EDown);
       
  1711 
       
  1712     TInt startIdx = 0;
       
  1713     if (iFocused != KErrNotFound)
       
  1714     {
       
  1715         //If there is layout request pending, the array of rows is probably
       
  1716         //empty. So we need to do layout of form, which fills the array of rows.
       
  1717         //Then row, where current focused item is, will be found.
       
  1718         if (iRows.Count() == 0)
       
  1719         {
       
  1720             TrappedLayoutAndDraw(ETrue);
       
  1721         }
       
  1722         TInt row = Row(ControlItem(iFocused));
       
  1723         if (row == KErrNotFound)
       
  1724         {
       
  1725             CMIDControlItem& ci = ControlItem(iFocused);
       
  1726             if (IsStringItem(ci))
       
  1727             {
       
  1728                 // find the first row either above or below (depends on direction)
       
  1729                 // this unconstrained stringItem
       
  1730                 CMIDStringItem& stringItem =
       
  1731                     *(static_cast<CMIDStringItem*>(&ci));
       
  1732                 if (aDirection == EDown)
       
  1733                 {
       
  1734                     startIdx = FirstRowBelowUnconstrainedStringItem(stringItem);
       
  1735                 }
       
  1736                 else
       
  1737                 {
       
  1738                     startIdx = FirstRowAboveUnconstrainedStringItem(stringItem);
       
  1739                 }
       
  1740             }
       
  1741             else
       
  1742             {
       
  1743                 // shouldn't get here
       
  1744                 ASSERT(EFalse);
       
  1745             }
       
  1746         }
       
  1747         else
       
  1748         {
       
  1749             startIdx = row + ((aDirection == EDown) ? 1 : -1);
       
  1750         }
       
  1751     }
       
  1752     else
       
  1753     {
       
  1754         // There is no focused item on Form (iFocused value is KErrNotFound).
       
  1755         // So we need to try to find another Item which could gain focus.
       
  1756         startIdx = FirstRowOnScreen(aDirection);
       
  1757     }
       
  1758 
       
  1759     if (startIdx == KErrNotFound)
       
  1760     {
       
  1761         return KErrNotFound;
       
  1762     }
       
  1763 
       
  1764     if (aDirection == EDown)
       
  1765     {
       
  1766         TInt idx = startIdx - 1;
       
  1767         TInt rowCount = iRows.Count();
       
  1768         while (++idx < rowCount)
       
  1769         {
       
  1770             CMIDFormRow* row = iRows[idx];
       
  1771             if (row->Position().iY > Height())
       
  1772             {
       
  1773                 break;
       
  1774             }
       
  1775             if (row->HasFocusableItemOnOrBelowScreen())
       
  1776             {
       
  1777                 return idx;
       
  1778             }
       
  1779         }
       
  1780     }
       
  1781     else
       
  1782     {
       
  1783         TInt idx = startIdx + 1;
       
  1784         while (--idx >= 0)
       
  1785         {
       
  1786             CMIDFormRow* row = iRows[idx];
       
  1787 
       
  1788             if (row->HasFocusableItemOnOrAboveScreen())
       
  1789             {
       
  1790                 return idx;
       
  1791             }
       
  1792 
       
  1793             if ((row->Position().iY + row->Size().iHeight) < 0)
       
  1794             {
       
  1795                 break;
       
  1796             }
       
  1797         }
       
  1798     }
       
  1799 
       
  1800     return KErrNotFound;
       
  1801 }
       
  1802 
       
  1803 // if aFromTop is false we look from the bottom up
       
  1804 TInt CMIDForm::FirstRowOnScreen(TDirection aDirection)
       
  1805 {
       
  1806     ASSERT(aDirection == EUp || aDirection == EDown);
       
  1807 
       
  1808     TInt idx = 0;
       
  1809     if (aDirection == EDown)
       
  1810     {
       
  1811         idx = -1;
       
  1812         TInt rowCount = iRows.Count();
       
  1813         while (++idx < rowCount)
       
  1814         {
       
  1815             CMIDFormRow* row = iRows[idx];
       
  1816             TInt bottom = row->Position().iY + row->Size().iHeight;
       
  1817             if (bottom > 0)
       
  1818             {
       
  1819                 return idx;
       
  1820             }
       
  1821         }
       
  1822     }
       
  1823     else
       
  1824     {
       
  1825         idx = iRows.Count();
       
  1826         while (--idx >= 0)
       
  1827         {
       
  1828             CMIDFormRow* row = iRows[idx];
       
  1829             TInt top = row->Position().iY;
       
  1830             if (top < Height())
       
  1831             {
       
  1832                 return idx;
       
  1833             }
       
  1834         }
       
  1835     }
       
  1836 
       
  1837     return KErrNotFound;
       
  1838 }
       
  1839 
       
  1840 // Returns the item index of the next focusable item in the given direction.
       
  1841 // Note: this may return an object that is not on the current row if there is
       
  1842 //       an unconstrained string item on the current row.
       
  1843 //
       
  1844 //       --------
       
  1845 //       |      |
       
  1846 //       |  A   |
       
  1847 //       |      | --------
       
  1848 //       -------- --------
       
  1849 //       -----------------
       
  1850 //       __________ ------
       
  1851 //                  |    |
       
  1852 //                  | B  |
       
  1853 //                  |    |
       
  1854 //                  ------
       
  1855 // In the above diagram we see a selectable item A, an unconstrained stringItem,
       
  1856 // and another selectable item B. If A has focus and the stringItem is not focusable
       
  1857 // then calling NextFocusableHorizontalIdx( ERight ) should return the index of B.
       
  1858 // If the string item is selectable then its index would get returned and a further
       
  1859 // call to NextFocusableHorizontalIdx( ERight ) would return the index of B.
       
  1860 // If B has focus calling NextFocusableHorizontalIdx( ELeft ) would simply return the
       
  1861 // index of the stringItem if it is selectable or A if not.
       
  1862 TInt CMIDForm::NextFocusableHorizontalIdx(TDirection aDirection)
       
  1863 {
       
  1864     ASSERT(aDirection == ELeft || aDirection == ERight);
       
  1865 
       
  1866     TInt idx = KErrNotFound;
       
  1867 
       
  1868     if (iFocused != KErrNotFound)
       
  1869     {
       
  1870         CMIDFormRow* rowPtr = NULL;
       
  1871         CMIDControlItem& controlItem = ControlItem(iFocused);
       
  1872 
       
  1873         TInt rowIdx = Row(controlItem, rowPtr);
       
  1874 
       
  1875         if (rowIdx != KErrNotFound)
       
  1876         {
       
  1877 
       
  1878             idx = rowPtr->Find(&controlItem);
       
  1879 
       
  1880             if (aDirection == ELeft)
       
  1881             {
       
  1882                 while (--idx >= 0)
       
  1883                 {
       
  1884                     if (rowPtr->Item(idx)->IsSelectable())
       
  1885                     {
       
  1886                         return ItemIndex(*(rowPtr->Item(idx)));
       
  1887                     }
       
  1888                 }
       
  1889 
       
  1890             }
       
  1891             else
       
  1892             {
       
  1893                 // direction is ERight
       
  1894                 while (++idx < rowPtr->NumItems())
       
  1895                 {
       
  1896                     if (rowPtr->Item(idx)->IsSelectable())
       
  1897                     {
       
  1898                         return ItemIndex(*(rowPtr->Item(idx)));
       
  1899                     }
       
  1900                 }
       
  1901 
       
  1902             }
       
  1903         }
       
  1904         else
       
  1905         {
       
  1906             // there is something focused but we failed to find a row index for it,
       
  1907             // so it is probably an unconstrained stringItem
       
  1908             if (aDirection == ELeft)
       
  1909             {
       
  1910                 if (IsStringItem(controlItem))
       
  1911                 {
       
  1912                     CMIDStringItem* si = static_cast<CMIDStringItem*>(&controlItem);
       
  1913                     idx = FirstFocusableItemBeforeStartOfUnconstrainedStringItemIdx(*si);
       
  1914                     return idx;
       
  1915                 }
       
  1916             }
       
  1917             else
       
  1918             {
       
  1919                 // direction ie ERight
       
  1920                 if (IsStringItem(controlItem))
       
  1921                 {
       
  1922                     CMIDStringItem* si = static_cast<CMIDStringItem*>(&controlItem);
       
  1923                     idx = FirstFocusableItemOnLastLineOfUnconstrainedStringItemIdx(*si);
       
  1924                     return idx;
       
  1925                 }
       
  1926             }
       
  1927         }
       
  1928     }
       
  1929 
       
  1930     return KErrNotFound;
       
  1931 }
       
  1932 
       
  1933 /** Replaces the currently focused item. This is called when the focused item is removed
       
  1934 or it loses focusability, for example a string item that loses all its commands. So this
       
  1935 is always triggered by a java call, never by the user. We call the same methods that are
       
  1936 used by Scroll(), ie TryMovingFocusHorizontally() and TryMovingFocusVertically(). However
       
  1937 in this case we don't want the form to scroll if the focused item is not on screen. So
       
  1938 these two methods will move the focus if a focusable item is either completely or partially
       
  1939 visible on screen following the good direction (right-down for left to right devices and
       
  1940 vice-versa for right to left devices). TryMovingFocusVertically() will set the focused item
       
  1941 to KErrNotFound if no focusable item is currently visible. */
       
  1942 void CMIDForm::ReplaceFocusedItem()
       
  1943 {
       
  1944     if (LayoutPending())
       
  1945     {
       
  1946         DEBUG("CMIDForm::ReplaceFocusedItem - calling layout");
       
  1947         TRAP_IGNORE(LayoutFormL());
       
  1948     }
       
  1949 
       
  1950     CMIDForm::TDirection direction = (iInitialAlignment == MMIDItem::ERight) ? ELeft : ERight;
       
  1951 
       
  1952     if (!TryMovingFocusHorizontally(direction))
       
  1953     {
       
  1954         if (iInitialAlignment == MMIDItem::ERight)
       
  1955         {//RIGHT TO LEFT
       
  1956             if (!TryMovingFocusVertically(direction == ELeft ? EDown : EUp, EFalse, EFalse))
       
  1957             {
       
  1958                 SetFocusedItem(KErrNotFound);
       
  1959             }
       
  1960         }
       
  1961         else
       
  1962         {//LEFT TO RIGHT
       
  1963             if (!TryMovingFocusVertically(direction == ELeft ? EUp : EDown, EFalse, EFalse))
       
  1964             {
       
  1965                 SetFocusedItem(KErrNotFound);
       
  1966             }
       
  1967         }
       
  1968     }
       
  1969 }
       
  1970 
       
  1971 void CMIDForm::SetFocusedItem(TInt aFocusIdx, TDirection aDirection /*= ENone*/,
       
  1972                               TBool aDoScroll /*= ETrue*/)
       
  1973 {
       
  1974     TInt oldFocused = iFocused;
       
  1975     TInt focusIndexDelta = aFocusIdx - iFocused;
       
  1976     if (iFocused != KErrNotFound)
       
  1977     { // actions for the item loosing focus
       
  1978         CMIDControlItem& control = ControlItem(iFocused);
       
  1979         control.PostFocusTransferEvent(EFalse, aDirection);
       
  1980         control.SetFocus(EFalse);
       
  1981         UpdateItemCommands(NULL, NULL);
       
  1982     }
       
  1983 
       
  1984     iFocused = aFocusIdx;
       
  1985 
       
  1986     //If there is traverse from visible to invisible TextField, Form has to scroll first
       
  1987     //before actions for the item which gaining focus are done. Form scrolling provides
       
  1988     //position settings to all visible items in form.
       
  1989     //When TextField gains focus, cursor values are calculated. Because this step was done before
       
  1990     //scrolling, position of edwin in TextField was not set (@see CMIDFormRow::SizeChanged())
       
  1991     //and cursor was drawn to wrong position.
       
  1992     //So Form has to scroll first -> this action provides proper position settings
       
  1993     //to item and items which are part of it (e.g. edwin in TextField) and after that
       
  1994     //changing focus makes proper cursor drawing.
       
  1995     if (focusIndexDelta != 0 && aDoScroll)
       
  1996     {
       
  1997         if (oldFocused != KErrNotFound)
       
  1998         {
       
  1999             aDirection = (focusIndexDelta > 0) ? EDown : EUp;
       
  2000         }
       
  2001 
       
  2002         ScrollToFocused(aDirection, EFalse);
       
  2003     }
       
  2004 
       
  2005     if (iFocused != KErrNotFound)
       
  2006     { // actions for the item gaining focus
       
  2007         CMIDControlItem& control = ControlItem(iFocused);
       
  2008 
       
  2009         SetHighlightBackgroundRects();
       
  2010 
       
  2011         control.PostFocusTransferEvent(ETrue, aDirection);
       
  2012         control.SetFocus(ETrue);
       
  2013         // msk: deliver also the possible MSK command to displayable
       
  2014         UpdateItemCommands(control.CommandList(), control.GetMSKCommand());
       
  2015     }
       
  2016 }
       
  2017 
       
  2018 /** Updates the model of the scrollbar and moves the thumb. Scroll bar must have
       
  2019 already been layouted.*/
       
  2020 void CMIDForm::UpdateScrollBar()
       
  2021 {
       
  2022     ASSERT(iSBFrame);
       
  2023     DEBUG_INT("CMIDForm::UpdateScrollBar - iScroll is %D", iScroll);
       
  2024 
       
  2025     TInt heightOfAllItems = HeightOfAllItems();
       
  2026     TInt height = heightOfAllItems > Height() ? heightOfAllItems : Height();
       
  2027 
       
  2028     TEikScrollBarModel vSbarModel(height, Height(), -iScroll);
       
  2029     iSBFrame->Tile(&vSbarModel);
       
  2030     iSBFrame->MoveVertThumbTo(-iScroll);
       
  2031 
       
  2032     iPopupController->HidePopup(); // hide info popup window if visible
       
  2033 }
       
  2034 
       
  2035 CMIDForm* CMIDForm::NewL(MMIDEnv& aEnv,MMIDDisplayable& aDisplayable)
       
  2036 {
       
  2037     CMIDForm* form = new(ELeave) CMIDForm(aEnv, static_cast<CMIDDisplayable&>(aDisplayable));
       
  2038     CleanupStack::PushL(form);
       
  2039     form->ConstructL();
       
  2040     CleanupStack::Pop(form);
       
  2041     return form;
       
  2042 }
       
  2043 
       
  2044 CMIDForm::CMIDForm(MMIDEnv& aEnv, CMIDDisplayable& aDisplayable)
       
  2045         : iDisplayable(aDisplayable), iEnv(&aEnv), iFocused(KErrNotFound),
       
  2046         iInitialAlignment(MMIDItem::ELeft), iHasScrolled(EFalse),
       
  2047         iLastFadeMessage(0)
       
  2048 {
       
  2049 }
       
  2050 
       
  2051 CMIDForm::~CMIDForm()
       
  2052 {
       
  2053     TRAP_IGNORE(DeleteAllItemsL());
       
  2054     DeleteRows();
       
  2055     iCurrentRow = NULL;
       
  2056 
       
  2057     delete iSBFrame;
       
  2058     SetItemsFormPointersToVal(NULL);
       
  2059     iItems.Close();
       
  2060     iRows.Close();
       
  2061 
       
  2062     delete iLayoutTimer;
       
  2063     delete iNoDataText;
       
  2064 
       
  2065     if (iBackgroundControlContext)
       
  2066     {
       
  2067         delete iBackgroundControlContext;
       
  2068         iBackgroundControlContext = NULL;
       
  2069     }
       
  2070     if (iHighlightedBackgroundCc)
       
  2071     {
       
  2072         delete iHighlightedBackgroundCc;
       
  2073         iHighlightedBackgroundCc = NULL;
       
  2074     }
       
  2075 
       
  2076     // Displayable is notified about content control deletion
       
  2077     iDisplayable.NotifyContentDestroyed();
       
  2078 
       
  2079     delete iPopupController;
       
  2080 
       
  2081     if (iHighlightTimer)
       
  2082     {
       
  2083         iHighlightTimer->Cancel();
       
  2084     }
       
  2085     delete iHighlightTimer;
       
  2086 
       
  2087     delete iPhysics;
       
  2088 }
       
  2089 
       
  2090 #include "javaoslayer.h"
       
  2091 
       
  2092 void CMIDForm::Draw(const TRect& aRect) const
       
  2093 {
       
  2094     if (!iStartUpTraceDone)
       
  2095     {
       
  2096         java::util::JavaOsLayer::startUpTrace("MIDP: CMIDForm::Draw starts", -1, -1);
       
  2097     }
       
  2098     if (LayoutPending())
       
  2099     {
       
  2100         return;
       
  2101     }
       
  2102 
       
  2103     CWindowGc& gc = SystemGc();
       
  2104 
       
  2105     MAknsSkinInstance* skin = AknsUtils::SkinInstance();
       
  2106     AknsDrawUtils::Background(skin, iBackgroundControlContext, this, gc, aRect);
       
  2107 
       
  2108     // Draw focus highlight
       
  2109     if (iFocused != KErrNotFound)
       
  2110     {
       
  2111         TRect focusedRect = ControlItem(iFocused).Rect();
       
  2112         if (focusedRect.Intersects(aRect))
       
  2113         {
       
  2114             AknsDrawUtils::Background(AknsUtils::SkinInstance(),
       
  2115                                       iHighlightedBackgroundCc, this,
       
  2116                                       SystemGc(), focusedRect);
       
  2117         }
       
  2118     }
       
  2119 
       
  2120     // If there is no items, "No data" string is printed to the middle of the screen
       
  2121     if (iItems.Count() == 0)
       
  2122     {
       
  2123         TRAP_IGNORE(DrawNoDataStringL());
       
  2124     }
       
  2125     if (!iStartUpTraceDone)
       
  2126     {
       
  2127         java::util::JavaOsLayer::startUpTrace("MIDP: CMIDForm::Draw done", -1, -1);
       
  2128         iStartUpTraceDone = ETrue;
       
  2129     }
       
  2130 }
       
  2131 
       
  2132 void CMIDForm::DrawNoDataStringL() const
       
  2133 {
       
  2134     CWindowGc& gc = SystemGc();
       
  2135 
       
  2136     // Actual skin instance
       
  2137     MAknsSkinInstance* skin = AknsUtils::SkinInstance();
       
  2138 
       
  2139     // If there is not the color fot the particular skin and id found, default (black) is used
       
  2140     TRgb color;
       
  2141     // Try to receive the color by skin and color Id, if not successful, black is used
       
  2142     TInt err = AknsUtils::GetCachedColor(skin, color, KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG6);
       
  2143     if (err != KErrNone)
       
  2144     {
       
  2145         color = AKN_LAF_COLOR(AknLayout::Title_pane_texts_Line_1(0, 0).iC);
       
  2146     }
       
  2147 
       
  2148     const CFont* font = CMIDFont::DefaultFont(CMIDFont::EDefaultTextId);
       
  2149     TInt textWidth = font->TextWidthInPixels(iNoDataText->Des());
       
  2150 
       
  2151     // Rectangle for computing the center
       
  2152     TRect screenRect;
       
  2153     AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EScreen, screenRect);
       
  2154 
       
  2155     // Centers the string to the middle of the screen
       
  2156     TInt x = (screenRect.Width() - textWidth) / 2;
       
  2157     TInt y = (iInnerHeight - font->HeightInPixels()) / 2;
       
  2158     TPoint point(x, y);
       
  2159     //Reserve extra space for biditext formatting
       
  2160     HBufC* bidiTextBuffer = HBufC::NewLC(iNoDataText->Size() + KAknBidiExtraSpacePerLine);
       
  2161     TPtr bidiText = bidiTextBuffer->Des();
       
  2162     TPtr caption = iNoDataText->Des();
       
  2163     bidiText = caption;
       
  2164     // Handle (bidi)text formatting for all languages
       
  2165     AknBidiTextUtils::ConvertToVisualAndClipL(bidiText, *font, textWidth, textWidth);
       
  2166 
       
  2167     gc.SetPenColor(color);
       
  2168     gc.UseFont(font);
       
  2169     gc.DrawText(bidiText, point);
       
  2170     CleanupStack::PopAndDestroy(bidiTextBuffer);
       
  2171     gc.DiscardFont();
       
  2172 }
       
  2173 
       
  2174 
       
  2175 /** Request a layout operaiton. We must delete the rows if postponing layout
       
  2176 in case java side some of the controls have been deleted. Otherwise because those
       
  2177 controls may be on existing rows we would get a panic in a draw request outside
       
  2178 our control. By deleting the rows in the worse scenario we'll get a blank form
       
  2179 drawn temporarily until the next layout operation. */
       
  2180 void CMIDForm::RequestLayoutL(TBool aImmediately /*= EFalse*/)
       
  2181 {
       
  2182     if (aImmediately)
       
  2183     {
       
  2184         iLayoutTimer->Cancel();
       
  2185         LayoutAndDrawL();
       
  2186     }
       
  2187     else
       
  2188     {
       
  2189         if (LayoutPending())
       
  2190         {
       
  2191             TTime now;
       
  2192             now.HomeTime();
       
  2193 
       
  2194             if (now.MicroSecondsFrom(iLayoutRequestTime) > KLayoutCap)
       
  2195             {
       
  2196                 LayoutAndDrawL();
       
  2197             }
       
  2198             else
       
  2199             {
       
  2200                 iLayoutTimer->Cancel();
       
  2201             }
       
  2202         }
       
  2203         else
       
  2204         {
       
  2205             iLayoutRequestTime.HomeTime();
       
  2206             DeleteRows();
       
  2207         }
       
  2208 
       
  2209         if (iLayoutRequestTime != -1)
       
  2210         {
       
  2211             iLayoutTimer->After(KLayoutTimeout);
       
  2212         }
       
  2213     }
       
  2214 }
       
  2215 
       
  2216 /** Return true if a layout request has been made. */
       
  2217 TBool CMIDForm::LayoutPending() const
       
  2218 {
       
  2219     return (iLayoutRequestTime != -1) && (iLayoutTimer->IsActive());
       
  2220 }
       
  2221 
       
  2222 /**
       
  2223 Layout the form, do scrolling and draw. Reset any previous layout request.
       
  2224 
       
  2225 @see RequestLayout(), LayoutPending(), LayoutFormL() and DoScroll()
       
  2226 */
       
  2227 void CMIDForm::LayoutAndDrawL()
       
  2228 {
       
  2229     DEBUG("CMIDForm::LayoutAndDrawL");
       
  2230 
       
  2231     LayoutFormL();
       
  2232 
       
  2233     HandleItemVisibilityChange();
       
  2234     UpdateScrollBar();
       
  2235     SetHighlightBackgroundRects();
       
  2236     DrawDeferred();
       
  2237 
       
  2238     UpdatePhysics();
       
  2239 }
       
  2240 
       
  2241 /** Call LayoutAndDrawL() inside a trap harness and log an error message if it
       
  2242 levaes.
       
  2243 
       
  2244     @param aOnlyIfPending Call LayoutAndDrawL() only if there is one pending,
       
  2245            @see LayoutPending(). By default this parameter is EFalse, i.e. always do layout
       
  2246 
       
  2247     @return The leave code returned by LayoutAndDrawL()
       
  2248 */
       
  2249 TInt CMIDForm::TrappedLayoutAndDraw(TBool aOnlyIfPending /* = EFalse */)
       
  2250 {
       
  2251     if (aOnlyIfPending  && !LayoutPending())
       
  2252     {
       
  2253         return KErrNone;
       
  2254     }
       
  2255 
       
  2256     TRAPD(err, LayoutAndDrawL());
       
  2257     return err;
       
  2258 }
       
  2259 
       
  2260 /* Called when the form becomes current and after the focus was set
       
  2261  * @see CMIDDisplayable::HandleCurrentL()
       
  2262  */
       
  2263 void CMIDForm::HandleCurrentL(TBool aCurrent)
       
  2264 {
       
  2265     if (iFocused != KErrNotFound)
       
  2266     {
       
  2267         CMIDControlItem& control = ControlItem(iFocused);
       
  2268         control.HandleCurrentL(aCurrent);
       
  2269     }
       
  2270 
       
  2271     if (!aCurrent)
       
  2272     {
       
  2273         iPopupController->HidePopup();
       
  2274     }
       
  2275 
       
  2276 #ifdef RD_SCALABLE_UI_V2
       
  2277     iCanDragFocus = EFalse;
       
  2278 #endif
       
  2279 }
       
  2280 
       
  2281 void CMIDForm::ConstructL()
       
  2282 {
       
  2283     UpdateMemberVariables();
       
  2284 
       
  2285     SetContainerWindowL(iDisplayable);
       
  2286 
       
  2287     iPopupController = CMIDPopupNoteController::NewL();
       
  2288 
       
  2289     // Scroll initialisations
       
  2290 #ifdef RD_SCALABLE_UI_V2
       
  2291     iSBFrame = new(ELeave) CEikScrollBarFrame(this, this, ETrue);
       
  2292     Window().SetPointerGrab(ETrue);
       
  2293 #else
       
  2294     iSBFrame = new(ELeave) CEikScrollBarFrame(this, NULL, ETrue);
       
  2295 #endif //RD_SCALABLE_UI_V2
       
  2296 
       
  2297     iSBFrame->SetScrollBarVisibilityL(
       
  2298         CEikScrollBarFrame::EOff, CEikScrollBarFrame::EAuto);
       
  2299     iSBFrame->CreateDoubleSpanScrollBarsL(ETrue, EFalse);
       
  2300 
       
  2301     // Background initialisation
       
  2302     iBackgroundControlContext = CAknsListBoxBackgroundControlContext::NewL(
       
  2303                                     KAknsIIDQsnBgAreaMainListGene, Rect(), ETrue,
       
  2304                                     KAknsIIDQsnBgColumnAB, Rect())  ;  // Rect parameters are only place-holders
       
  2305 
       
  2306     // Background for highlighted item, frame rects are set later
       
  2307     iHighlightedBackgroundCc = CAknsFrameBackgroundControlContext::NewL(
       
  2308                                    KAknsIIDQsnFrInput,
       
  2309                                    TRect(), TRect(), ETrue);
       
  2310 
       
  2311     iDisplayable.SetComponentL(*this);
       
  2312 
       
  2313     // get the layout from shared data so we can tell what our
       
  2314     // initial alignment should be
       
  2315     TInt layoutId = 0;
       
  2316 
       
  2317     CRepository* repository = CRepository::NewL(KCRUidAvkon);
       
  2318     repository->Get(KAknLayoutId, layoutId);
       
  2319     delete repository;
       
  2320 
       
  2321     if (layoutId == EAknLayoutIdABRW)
       
  2322     {
       
  2323         iInitialAlignment = MMIDItem::ERight;
       
  2324     }
       
  2325 
       
  2326     iLayoutTimer = CTimeOutTimer::NewL(CActive::EPriorityIdle, *this);
       
  2327     iNoDataText =  iEikonEnv->AllocReadResourceL(R_AVKON_NO_DATA);
       
  2328 
       
  2329 #ifdef RD_TACTILE_FEEDBACK
       
  2330     iFeedback = MTouchFeedback::Instance();
       
  2331 #endif
       
  2332     //index of pointed control is set to not active
       
  2333     iIndexPointedControl=-1;
       
  2334 
       
  2335     if (CMIDFormPhysics::FeatureEnabled())
       
  2336     {
       
  2337         iPhysics = CMIDFormPhysics::NewL(*this);
       
  2338 
       
  2339         // Destroy iPhysics immediately if physics is not allowed.
       
  2340         // This should happen in error situation only, when implementation
       
  2341         // dll couldn't be loaded although the feature was enabled.
       
  2342         if (iPhysics && !iPhysics->PhysicsAllowed())
       
  2343         {
       
  2344             delete iPhysics;
       
  2345             iPhysics = NULL;
       
  2346         }
       
  2347         else
       
  2348         {
       
  2349             iHighlightTimer = CPeriodic::NewL(CActive::EPriorityStandard);
       
  2350         }
       
  2351     }
       
  2352 
       
  2353     LayoutAndDrawL();
       
  2354 }
       
  2355 
       
  2356 void CMIDForm::UpdateMemberVariables()
       
  2357 {
       
  2358     TAknLayoutRect mainMidpPane;
       
  2359 
       
  2360 #ifdef RD_JAVA_S60_RELEASE_9_2
       
  2361     TRect mainPaneRect;
       
  2362     AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, mainPaneRect);
       
  2363     mainMidpPane.LayoutRect(mainPaneRect,
       
  2364                             AknLayoutScalable_Avkon::main_midp_pane().LayoutLine());
       
  2365 #else
       
  2366     mainMidpPane.LayoutRect(iEikonEnv->ScreenDevice()->SizeInPixels(),
       
  2367                             AknLayoutScalable_Avkon::main_midp_pane().LayoutLine());
       
  2368 #endif // RD_JAVA_S60_RELEASE_9_2
       
  2369 
       
  2370     TInt variety = Layout_Meta_Data::IsLandscapeOrientation() ? 1 : 0;
       
  2371     iMidpFormRect.LayoutRect(mainMidpPane.Rect(),
       
  2372                              AknLayoutScalable_Avkon::midp_form_pane(variety).LayoutLine());
       
  2373 
       
  2374     TAknLayoutRect listForm2MidpPane;
       
  2375     listForm2MidpPane.LayoutRect(iMidpFormRect.Rect(),
       
  2376                                  AknLayoutScalable_Avkon::list_form2_midp_pane().LayoutLine());
       
  2377 
       
  2378     iFormRect.LayoutRect(listForm2MidpPane.Rect(),
       
  2379                          AknLayoutScalable_Avkon::form2_midp_field_pane().LayoutLine());
       
  2380 
       
  2381     iInnerWidth = iFormRect.Rect().Width();
       
  2382 
       
  2383     iInnerHeight = iFormRect.Rect().Height();
       
  2384     iFormHeight = iMidpFormRect.Rect().Height();
       
  2385 }
       
  2386 
       
  2387 MMIDItem* CMIDForm::CurrentItem() const
       
  2388 {
       
  2389     return iFocused == KErrNotFound ? NULL : iItems[iFocused];
       
  2390 }
       
  2391 
       
  2392 CMIDItem& CMIDForm::Item(TInt aIndex) const
       
  2393 {
       
  2394     MMIDItem* item = iItems[aIndex];
       
  2395     return ControlItem(item->Type());
       
  2396 }
       
  2397 
       
  2398 CMIDControlItem& CMIDForm::ControlItem(TInt aIndex) const
       
  2399 {
       
  2400     return ControlItem(iItems[aIndex]);
       
  2401 }
       
  2402 
       
  2403 CMIDControlItem& CMIDForm::ControlItem(MMIDItem* aMMidItem)
       
  2404 {
       
  2405     CMIDControlItem* base = NULL;
       
  2406     TInt type  = (TInt) aMMidItem->Type();
       
  2407     switch (type)
       
  2408     {
       
  2409     case MMIDComponent::EImageItem:
       
  2410         base = static_cast<CMIDImageItem*>(aMMidItem);
       
  2411         break;
       
  2412     case MMIDComponent::EStringItem:
       
  2413         base = static_cast<CMIDStringItem*>(aMMidItem);
       
  2414         break;
       
  2415     case MMIDComponent::ESpacer:
       
  2416         base = static_cast<CMIDSpacer*>(aMMidItem);
       
  2417         break;
       
  2418     case MMIDComponent::EGauge:
       
  2419         base = static_cast<CMIDGaugeItem*>(aMMidItem);
       
  2420         break;
       
  2421     case MMIDComponent::ETextField:
       
  2422         base = static_cast<CMIDTextFieldItem*>(aMMidItem);
       
  2423         break;
       
  2424     case MMIDComponent::EChoiceGroup:
       
  2425         base = static_cast<CMIDChoiceGroupItem*>(aMMidItem);
       
  2426         break;
       
  2427     case MMIDComponent::EDateField:
       
  2428         base = static_cast<CMIDDateFieldItem*>(aMMidItem);
       
  2429         break;
       
  2430     case MMIDComponent::ECustomItem:
       
  2431         base = static_cast<CMIDCustomItem*>(aMMidItem);
       
  2432         break;
       
  2433     default:
       
  2434         ASSERT(EFalse);
       
  2435         break;
       
  2436     }
       
  2437 
       
  2438     return *base;
       
  2439 }
       
  2440 
       
  2441 TInt CMIDForm::Index(CCoeControl* aControl) const
       
  2442 {
       
  2443     TInt itemCount = iItems.Count();
       
  2444     for (TInt i=0; i < itemCount; i++)
       
  2445     {
       
  2446         CCoeControl* control = static_cast<CCoeControl*>(&(ControlItem(i)));
       
  2447         if (control == aControl)
       
  2448         {
       
  2449             return i;
       
  2450         }
       
  2451     }
       
  2452     return KErrNotFound;
       
  2453 }
       
  2454 
       
  2455 TInt CMIDForm::FormWidth()
       
  2456 {
       
  2457     return CMIDForm::StaticFormRect().Width();
       
  2458 }
       
  2459 
       
  2460 /*static*/ TRect CMIDForm::StaticFormRect()
       
  2461 {
       
  2462     TInt variety = Layout_Meta_Data::IsLandscapeOrientation() ? 1 : 0;
       
  2463     TRect mainPaneRect;
       
  2464 
       
  2465 #ifdef RD_JAVA_S60_RELEASE_9_2
       
  2466     AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, mainPaneRect);
       
  2467 #else
       
  2468     mainPaneRect = iAvkonAppUi->ApplicationRect();
       
  2469 #endif // RD_JAVA_S60_RELEASE_9_2
       
  2470 
       
  2471     TAknLayoutRect mainMidpPane;
       
  2472     mainMidpPane.LayoutRect(mainPaneRect,
       
  2473                             AknLayoutScalable_Avkon::main_midp_pane().LayoutLine());
       
  2474 
       
  2475     TAknLayoutRect midpFormRect;
       
  2476     midpFormRect.LayoutRect(mainMidpPane.Rect(),
       
  2477                             AknLayoutScalable_Avkon::midp_form_pane(variety).LayoutLine());
       
  2478 
       
  2479     TAknLayoutRect listForm2MidpPane;
       
  2480     listForm2MidpPane.LayoutRect(midpFormRect.Rect(),
       
  2481                                  AknLayoutScalable_Avkon::list_form2_midp_pane().LayoutLine());
       
  2482 
       
  2483     TAknLayoutRect formRect;
       
  2484     formRect.LayoutRect(listForm2MidpPane.Rect(),
       
  2485                         AknLayoutScalable_Avkon::form2_midp_field_pane().LayoutLine());
       
  2486 
       
  2487     return formRect.Rect();
       
  2488 }
       
  2489 
       
  2490 
       
  2491 TBool CMIDForm::IsCurrentItem(CMIDItem* aItem) const
       
  2492 {
       
  2493     return (iFocused != KErrNotFound) &&
       
  2494            (iFocused == Index(static_cast<CCoeControl*>(aItem)));
       
  2495 }
       
  2496 
       
  2497 
       
  2498 void CMIDForm::HandleControlEventL(CCoeControl* aControl,TCoeEvent aEventType)
       
  2499 {
       
  2500     switch (aEventType)
       
  2501     {
       
  2502     case MCoeControlObserver::EEventStateChanged:
       
  2503     {
       
  2504         TInt index = KErrNotFound;
       
  2505         User::LeaveIfError(index = Index(aControl));
       
  2506         MMIDComponent::TType type = iItems[index]->Type();
       
  2507         if (type == EStringItem || type == EImageItem || type == ECustomItem)
       
  2508         {
       
  2509             // These don't change state in the MIDP sense, so it must be a button
       
  2510             // press so we need to post a default command event, if there is one
       
  2511 
       
  2512             // msk: this is needed if msk is not enabled
       
  2513             PostDefaultItemCommandEvent(index);
       
  2514         }
       
  2515         else
       
  2516         {
       
  2517             iEnv->PostJavaEvent(*this,EDisplayable,index);
       
  2518         }
       
  2519     }
       
  2520     break;
       
  2521     case MCoeControlObserver::EEventRequestFocus:
       
  2522         if (!aControl->IsNonFocusing())
       
  2523         {
       
  2524             SetFocusedItem(Index(aControl));
       
  2525         }
       
  2526         break;
       
  2527     default:
       
  2528         break;
       
  2529     }
       
  2530 }
       
  2531 
       
  2532 
       
  2533 /*
       
  2534  * Pointer events from different Items are are routed via this function to private HandleControlEventL.
       
  2535  * Focus is not accepted if Item is not focusable.
       
  2536  */
       
  2537 void CMIDForm::HandleTouchControlEventL(CCoeControl* aControl,TCoeEvent aEventType)
       
  2538 {
       
  2539 
       
  2540     CMIDControlItem& ci = ControlItem(Index(aControl));
       
  2541     if (ci.IsSelectable())
       
  2542     {
       
  2543         HandleControlEventL(aControl, aEventType);
       
  2544     }
       
  2545 }
       
  2546 
       
  2547 
       
  2548 void CMIDForm::TimerExpired()
       
  2549 {
       
  2550     TrappedLayoutAndDraw();
       
  2551 }
       
  2552 
       
  2553 /*
       
  2554  * Called whenever something's happened which could change the visibility of an item
       
  2555  * controls. e.g. when made current, when update Items, when scroll.
       
  2556  */
       
  2557 void CMIDForm::HandleItemVisibilityChange()
       
  2558 {
       
  2559 
       
  2560     // CUSTOM ITEM ONLY
       
  2561     TInt count = iItems.Count();
       
  2562     for (TInt i=0; i<count; i++)
       
  2563     {
       
  2564         if (iItems[i]->Type() == MMIDComponent::ECustomItem)
       
  2565         {
       
  2566             // this will get the CustomItem's FocusChanged method called which will cause
       
  2567             // some visibility events to be sent
       
  2568             CMIDControlItem& ci = ControlItem(i);
       
  2569             ((CMIDCustomItem&) ci).HandleVisibilityChange();
       
  2570         }
       
  2571     }
       
  2572     // END CUSTOM ITEM
       
  2573 
       
  2574 }
       
  2575 
       
  2576 /** Handles an item size change event. This is called by within the plugin, not by java
       
  2577 side unlike RefreshItemL(TInt).
       
  2578 
       
  2579 First of all we check if there is a layout pending operation.
       
  2580 If there is one we don't do anything. This is because this method is called during
       
  2581 control creation when items are inserted in the form. However, it is also called later
       
  2582 on when the control is already displaying and its size changes. During control creation
       
  2583 we should do a delayed layout (for performance reasons) wheras if we delay layout in the
       
  2584 second case we get an unpleasant redraw effect because the item control usually draws
       
  2585 immediately. So we should try and layout+draw immediately in the second case.
       
  2586 We distinguish between the two cases by checking if there is a layout
       
  2587 operation (which is requested by InsertItemL()). Also, in the second case, instead of
       
  2588 doing a full LayoutAndDrawL() we only resize elements already assigned to rows and
       
  2589 update the scroll bars. And then we draw. This is a bit more efficient than recreating
       
  2590 the rows. Because this method is only called by items that fill an entire row anyway,
       
  2591 we shouln't need to re-create rows.
       
  2592 */
       
  2593 void CMIDForm::RefreshItemL(MMIDItem* aItem)
       
  2594 {
       
  2595     TInt index = iItems.Find(aItem);
       
  2596 
       
  2597     if (!LayoutPending() && index != KErrNotFound)
       
  2598     {
       
  2599         SizeItemsInFormRowsL();
       
  2600         SetRowExtentsWithRespectToScrolledLocation();
       
  2601 
       
  2602         if ((aItem->Type() == MMIDComponent::ETextField) && (index == iFocused))
       
  2603         {
       
  2604             CMIDTextFieldItem* tf = static_cast<CMIDTextFieldItem*>(aItem);
       
  2605             TPoint p;
       
  2606             TBool success = tf->GetCursorPosL(p);
       
  2607             if (success)
       
  2608             {
       
  2609                 if (p.iY < 0)
       
  2610                 {
       
  2611                     RawScrollRelative(p.iY + 10);
       
  2612                 }
       
  2613                 else if (p.iY > Height())
       
  2614                 {
       
  2615                     RawScrollRelative(Height() - (p.iY + 10));
       
  2616                 }
       
  2617             }
       
  2618         }
       
  2619         RawScrollFinalize(ETrue);
       
  2620     }
       
  2621 }
       
  2622 
       
  2623 /**
       
  2624  * If the item at aIndex has a default command set for it, then this will be invoked and True
       
  2625  * will be returned. False if a command has not been posted
       
  2626  */
       
  2627 // msk: this method is needed if msk is not enabled
       
  2628 TBool CMIDForm::PostDefaultItemCommandEvent(TInt aIndex)
       
  2629 {
       
  2630     if (aIndex != KErrNotFound)
       
  2631     {
       
  2632         CMIDCommand* defaultCommand = ControlItem(iItems[aIndex]).DefaultCommand();
       
  2633         if (defaultCommand)
       
  2634         {
       
  2635             iEnv->PostJavaEvent(*iItems[aIndex],EItem,ECommand,defaultCommand->Id());
       
  2636             return ETrue;
       
  2637         }
       
  2638     }
       
  2639     return EFalse;
       
  2640 }
       
  2641 
       
  2642 void CMIDForm::AddItemToFormL(CMIDControlItem& aControlItem)
       
  2643 {
       
  2644     aControlItem.SetForm(this);
       
  2645     aControlItem.SetContainerWindowL(*this);
       
  2646     aControlItem.ItemAddedToFormL();
       
  2647 }
       
  2648 
       
  2649 void CMIDForm::RemoveItemFromForm(CMIDControlItem& aControlItem)
       
  2650 {
       
  2651     aControlItem.MakeVisible(EFalse);
       
  2652     aControlItem.SetPosition(TPoint(-Width(), 0));
       
  2653     // Item is not allowed to access container window from now.
       
  2654     aControlItem.ItemRemovedFromForm();
       
  2655     aControlItem.SetForm(NULL);
       
  2656 }
       
  2657 
       
  2658 void CMIDForm::UpdateItemCommands(CMIDCommandList* aCommandList, CMIDCommand* aMSKCommand)
       
  2659 {
       
  2660     iDisplayable.SetItemCommandList(aCommandList, aMSKCommand);
       
  2661 }
       
  2662 
       
  2663 // msk: this method is needed if msk is not enabled
       
  2664 TBool CMIDForm::DoDefaultCommand()
       
  2665 {
       
  2666     if (iFocused != KErrNotFound)
       
  2667     {
       
  2668         CMIDControlItem& ci = ControlItem(iFocused);
       
  2669 
       
  2670         CMIDCommand* defaultCommand = ci.DefaultCommand();
       
  2671         if (defaultCommand)
       
  2672         {
       
  2673             iEnv->PostJavaEvent(*(iItems[iFocused]), EItem, ECommand, defaultCommand->Id());
       
  2674             return ETrue;
       
  2675         }
       
  2676     }
       
  2677 
       
  2678     return EFalse;
       
  2679 }
       
  2680 
       
  2681 
       
  2682 TInt CMIDForm::Row(const CMIDControlItem& aItem) const
       
  2683 {
       
  2684     CMIDFormRow* rowPtr = NULL;
       
  2685     return Row(aItem, rowPtr);
       
  2686 }
       
  2687 
       
  2688 TInt CMIDForm::Row(const CMIDControlItem& aItem, CMIDFormRow*& aRowPtr) const
       
  2689 {
       
  2690     aRowPtr = NULL;
       
  2691     TInt rowCount = iRows.Count();
       
  2692     for (TInt i=0; i < rowCount; i++)
       
  2693     {
       
  2694         TInt idx = iRows[i]->Find(&aItem);
       
  2695         if (idx != KErrNotFound)
       
  2696         {
       
  2697             aRowPtr = iRows[i];
       
  2698             return i;
       
  2699         }
       
  2700     }
       
  2701     return KErrNotFound;
       
  2702 }
       
  2703 
       
  2704 CMIDForm::TDirection CMIDForm::ConvertKeyToDirection(TUint aCode)
       
  2705 {
       
  2706     switch (aCode)
       
  2707     {
       
  2708     case EKeyDownArrow:
       
  2709         return EDown;
       
  2710     case EKeyUpArrow:
       
  2711         return EUp;
       
  2712     case EKeyLeftArrow:
       
  2713         return ELeft;
       
  2714     case EKeyRightArrow:
       
  2715         return ERight;
       
  2716     default:
       
  2717         return ENone;
       
  2718     }
       
  2719 }
       
  2720 
       
  2721 // returns the index of a CMIDControlItem in the iItems array. If the
       
  2722 // CMIDControlItem is a CMIDLabelContainerItem, then the index
       
  2723 // of the stringItem associated with it is returned.
       
  2724 TInt CMIDForm::ItemIndex(CMIDControlItem& aItem)
       
  2725 {
       
  2726     MMIDItem* item = aItem.iMMidItem;
       
  2727 
       
  2728     TInt idx = 0;
       
  2729     TInt itemCount = iItems.Count();
       
  2730     while (idx < itemCount)
       
  2731     {
       
  2732         if (iItems[idx] == item)
       
  2733         {
       
  2734             return idx;
       
  2735         }
       
  2736         idx++;
       
  2737     }
       
  2738 
       
  2739     // OK, so we didn't find it. Maybe it is a CMIDLabelContainerItem
       
  2740     if (IsLabelContainerItem(aItem))
       
  2741     {
       
  2742         CMIDLabelContainerItem* usil = static_cast<CMIDLabelContainerItem*>(&aItem);
       
  2743         return ItemIndex(usil->StringItem());
       
  2744     }
       
  2745 
       
  2746     return KErrNotFound;
       
  2747 }
       
  2748 
       
  2749 // this method will return the index of the row ABOVE the indicated unconstrained string item
       
  2750 // if the string item was on the top row then KErrNotFound is returned, also if the string item
       
  2751 // could not be found or was not an unconstrained string item.
       
  2752 TInt CMIDForm::FirstRowAboveUnconstrainedStringItem(CMIDStringItem& aStringItem) const
       
  2753 {
       
  2754     TInt idx = FirstRowOfUnconstrainedStringItem(aStringItem);
       
  2755     return (idx == KErrNotFound) ? KErrNotFound : idx - 1;
       
  2756 }
       
  2757 
       
  2758 // returns the index of the first row of an unconstrained string item.
       
  2759 // Returns KErrNotFound if the string item could not be found (or if it was not
       
  2760 // an unconstrained string item).
       
  2761 TInt CMIDForm::FirstRowOfUnconstrainedStringItem(CMIDStringItem& aStringItem) const
       
  2762 {
       
  2763     TInt idx = -1;
       
  2764     TInt rowCount = iRows.Count();
       
  2765     while (++idx < rowCount)
       
  2766     {
       
  2767         CMIDFormRow* row = iRows[idx];
       
  2768         TInt innerIdx = -1;
       
  2769         while (++innerIdx < row->NumItems())
       
  2770         {
       
  2771             CMIDControlItem* ci = row->Item(innerIdx);
       
  2772             if (IsLabelContainerItem(*ci))
       
  2773             {
       
  2774                 CMIDLabelContainerItem* ucsi = static_cast<CMIDLabelContainerItem*>(ci);
       
  2775                 if (&(ucsi->StringItem()) == &aStringItem)
       
  2776                 {
       
  2777                     return idx;
       
  2778                 }
       
  2779             }
       
  2780         }
       
  2781     }
       
  2782     return KErrNotFound;
       
  2783 }
       
  2784 
       
  2785 TInt CMIDForm::FirstRowBelowUnconstrainedStringItem(CMIDStringItem& aStringItem) const
       
  2786 {
       
  2787     TInt idx = iRows.Count();
       
  2788     TInt rowCount = iRows.Count();
       
  2789     while (--idx < rowCount)
       
  2790     {
       
  2791         CMIDFormRow* row = iRows[idx];
       
  2792         TInt innerIdx = -1;
       
  2793         while (++innerIdx < row->NumItems())
       
  2794         {
       
  2795             CMIDControlItem* ci = row->Item(innerIdx);
       
  2796             if (IsLabelContainerItem(*ci))
       
  2797             {
       
  2798                 CMIDLabelContainerItem* ucsi = static_cast<CMIDLabelContainerItem*>(ci);
       
  2799                 if (&(ucsi->StringItem()) == &aStringItem)
       
  2800                 {
       
  2801                     return ((idx + 1) >= rowCount) ? KErrNotFound : idx + 1;
       
  2802                 }
       
  2803             }
       
  2804         }
       
  2805     }
       
  2806     return KErrNotFound;
       
  2807 }
       
  2808 
       
  2809 TInt CMIDForm::FirstFocusableItemBeforeStartOfUnconstrainedStringItemIdx(CMIDStringItem& aStringItem)
       
  2810 {
       
  2811     TInt rowIdx = FirstRowOfUnconstrainedStringItem(aStringItem);
       
  2812     if (rowIdx != KErrNotFound)
       
  2813     {
       
  2814         CMIDFormRow* row = iRows[rowIdx];
       
  2815         TInt idxOnRow = row->NumItems();
       
  2816         while (--idxOnRow >= 0)  // search backward along the row for the unconstrained string item
       
  2817             // we probably could assume it is the last element
       
  2818         {
       
  2819             CMIDControlItem* ci = row->Item(idxOnRow);
       
  2820             if (IsLabelContainerItem(*ci))
       
  2821             {
       
  2822                 CMIDLabelContainerItem* usil = static_cast<CMIDLabelContainerItem*>(ci);
       
  2823                 CMIDStringItem* si = &(usil->StringItem());
       
  2824                 if (si == &aStringItem)
       
  2825                 {
       
  2826                     break;
       
  2827                 }
       
  2828             }
       
  2829         }
       
  2830         if (idxOnRow > 0)
       
  2831         {
       
  2832             // there are some items on the row before the start of the unconstrained string item
       
  2833             while (--idxOnRow >= 0)  // search backward along the row for the first focusable item
       
  2834             {
       
  2835                 CMIDControlItem* ci = row->Item(idxOnRow);
       
  2836                 if (ci->IsSelectable())
       
  2837                 {
       
  2838                     return ItemIndex(*ci);
       
  2839                 }
       
  2840             }
       
  2841         }
       
  2842     }
       
  2843     return KErrNotFound;
       
  2844 }
       
  2845 
       
  2846 TInt CMIDForm::FirstFocusableItemOnLastLineOfUnconstrainedStringItemIdx(CMIDStringItem& aStringItem)
       
  2847 {
       
  2848     TInt rowIdx = FirstRowBelowUnconstrainedStringItem(aStringItem) - 1;
       
  2849 
       
  2850     if (rowIdx == -2)
       
  2851     {
       
  2852         rowIdx = iRows.Count() -1;
       
  2853     }
       
  2854 
       
  2855     if (rowIdx > KErrNotFound)  // if FirstRowBelowUnconstrainedStringItem returned KErrNotFound then we have -2 so check with '>'
       
  2856     {
       
  2857         CMIDFormRow* row = iRows[rowIdx];
       
  2858         TInt idxOnRow = -1;
       
  2859 
       
  2860         TBool found = EFalse;
       
  2861         while (++idxOnRow < row->NumItems())
       
  2862         {
       
  2863             CMIDControlItem* ci = row->Item(idxOnRow);
       
  2864 
       
  2865             if (ControlBelongsToSameUnconstrainedItem(ci,aStringItem))
       
  2866             {//ok we found our item, if the next one is selectable we return
       
  2867                 found = ETrue;
       
  2868             }
       
  2869             else if (found && ci->IsSelectable())
       
  2870             {
       
  2871                 return ItemIndex(*ci);
       
  2872             }
       
  2873         }
       
  2874     }
       
  2875     return KErrNotFound;
       
  2876 }
       
  2877 
       
  2878 /** Return true if aCi belongs to the same unconstrained string item (aStringItem) */
       
  2879 TBool CMIDForm::ControlBelongsToSameUnconstrainedItem(CMIDControlItem* aCi, CMIDStringItem& aStringItem) const
       
  2880 {
       
  2881     if (IsLabelContainerItem(*aCi))
       
  2882     {
       
  2883         CMIDLabelContainerItem* usil = static_cast<CMIDLabelContainerItem*>(aCi);
       
  2884         if (&(usil->StringItem()) == &aStringItem)
       
  2885         {
       
  2886             return ETrue;
       
  2887         }
       
  2888     }
       
  2889 
       
  2890     return EFalse;
       
  2891 }
       
  2892 
       
  2893 /** */
       
  2894 void CMIDForm::RemoveDeletedItem(CMIDControlItem& aItem)
       
  2895 {
       
  2896     iFocused = KErrNotFound;
       
  2897     TInt i=-1;
       
  2898     TInt rowCount = iRows.Count();
       
  2899     while (++i < rowCount)
       
  2900     {
       
  2901         CMIDFormRow* row = iRows[i];
       
  2902         if (row->RemoveItemIfExists(aItem))
       
  2903         {
       
  2904             break;
       
  2905         }
       
  2906     }
       
  2907 
       
  2908     i = -1;
       
  2909     TInt itemCount = iItems.Count();
       
  2910     while (++i < itemCount)
       
  2911     {
       
  2912         if (aItem.iMMidItem)
       
  2913         {
       
  2914             if (aItem.iMMidItem == iItems[i])
       
  2915             {
       
  2916                 iItems.Remove(i);
       
  2917                 break;
       
  2918             }
       
  2919         }
       
  2920     }
       
  2921 
       
  2922 }
       
  2923 
       
  2924 
       
  2925 /////////////////////////////////////////////////////////////////////////////////////////
       
  2926 // new layout methods
       
  2927 /////////////////////////////////////////////////////////////////////////////////////////
       
  2928 
       
  2929 // does the layout for the entire form
       
  2930 void CMIDForm::LayoutFormL()
       
  2931 {
       
  2932     DEBUG("CMIDForm::LayoutFormL");
       
  2933 
       
  2934     if (LayoutPending())
       
  2935     {
       
  2936         iLayoutRequestTime = -1;
       
  2937         iLayoutTimer->Cancel();
       
  2938     }
       
  2939 
       
  2940     TReal prevHeight = HeightOfAllItems() - Height();
       
  2941     TInt prevFocusedYPos = 0; // by default it is on top of screen
       
  2942     TInt focusedItem = iFocused;
       
  2943 
       
  2944     if (focusedItem != KErrNotFound)
       
  2945     {
       
  2946         TRect rect = GetControlRect(focusedItem);
       
  2947         prevFocusedYPos    = rect.iTl.iY;
       
  2948     }
       
  2949 
       
  2950 
       
  2951     // scroll bar layouting
       
  2952     AknLayoutUtils::LayoutVerticalScrollBar(iSBFrame, Rect(),
       
  2953                                             AknLayoutScalable_Avkon::scroll_pane_cp51().LayoutLine());
       
  2954     ResetItemsPreferredSizes();
       
  2955 
       
  2956     // this prevents items from calling layout recursively
       
  2957     SetItemsFormPointersToVal(NULL);
       
  2958 
       
  2959     AssignItemsToRowsL();
       
  2960     SizeItemsInFormRowsL();
       
  2961 
       
  2962     SetItemsFormPointersToVal(this);
       
  2963 
       
  2964     SetRowExtentsWithRespectToScrolledLocation();
       
  2965 
       
  2966     TReal newHeight = HeightOfAllItems() - Height();
       
  2967 
       
  2968     if (newHeight != prevHeight)
       
  2969     {
       
  2970         // layout has changed significantly, but we need to keep focused component scrolled so that
       
  2971         // user sees it at the same level in viewport
       
  2972         TInt newFocusedYPos = 0;
       
  2973         if (focusedItem != KErrNotFound)
       
  2974         {
       
  2975             TRect rect = GetControlRect(focusedItem);
       
  2976             newFocusedYPos    = rect.iTl.iY;
       
  2977             TInt delta = prevFocusedYPos - newFocusedYPos;
       
  2978             if (iScroll != 0)
       
  2979             {
       
  2980                 // correct only if not on top of window
       
  2981                 ScrollRelative(delta);
       
  2982             }
       
  2983         }
       
  2984         else
       
  2985         {
       
  2986             if (newHeight < prevHeight)
       
  2987             {
       
  2988                 // no focused item, just try to keep same component visible
       
  2989                 iScroll  = newHeight > 0 ? ((TReal) iScroll * (newHeight / prevHeight)) : 0;
       
  2990             }
       
  2991         }
       
  2992 
       
  2993         SetRowExtentsWithRespectToScrolledLocation();
       
  2994     }
       
  2995 }
       
  2996 
       
  2997 void CMIDForm::ResetItemsPreferredSizes()
       
  2998 {
       
  2999     TInt itemCount = iItems.Count();
       
  3000     for (TInt i=0; i < itemCount; i++)
       
  3001     {
       
  3002         CMIDControlItem& ci = ControlItem(i);
       
  3003         ci.ResetPreferredSize();
       
  3004     }
       
  3005 }
       
  3006 
       
  3007 void CMIDForm::SetItemsFormPointersToVal(CMIDForm* aVal)
       
  3008 {
       
  3009     TInt itemCount = iItems.Count();
       
  3010     for (TInt i=0; i < itemCount; i++)
       
  3011     {
       
  3012         CMIDControlItem& ci = ControlItem(i);
       
  3013         ci.SetForm(aVal);
       
  3014     }
       
  3015 }
       
  3016 
       
  3017 /** If an items preferred size is zero
       
  3018 we shouldn't add it to the form row and so we skip it */
       
  3019 TBool CMIDForm::SkipNullItem(TInt aIndex)
       
  3020 {
       
  3021     CMIDControlItem& ci = ControlItem(iItems[aIndex]);
       
  3022     if (ci.PreferredSize() == TSize(0, 0))
       
  3023     {
       
  3024         if (iFocused == aIndex)
       
  3025         {
       
  3026             SetFocusedItem(KErrNotFound);
       
  3027         }
       
  3028 
       
  3029         return ETrue;
       
  3030     }
       
  3031 
       
  3032     return EFalse;
       
  3033 }
       
  3034 
       
  3035 /**
       
  3036     If the current row index is the same as the row count,
       
  3037     create and append to iRows a new row and store it into
       
  3038     iCurrentRow. Increment the current row index. Also reset
       
  3039     the current alignment.
       
  3040 */
       
  3041 void CMIDForm::CreateNewRowAndSetAsCurrentL()
       
  3042 {
       
  3043     CMIDFormRow* row = CMIDFormRow::NewL(*this);
       
  3044     CleanupStack::PushL(row);
       
  3045 
       
  3046     User::LeaveIfError(iRows.Append(row));
       
  3047     CleanupStack::Pop(row);
       
  3048 
       
  3049     iCurrentRow = row;
       
  3050     iCurrentRow->SetAlignment(iCurrentAlignment);
       
  3051 }
       
  3052 
       
  3053 /** Verify the current alignment and change it if the current row
       
  3054 is empty. If the row is not empty and the item alignement is different
       
  3055 and the item requires a row break, then add a new row. */
       
  3056 void CMIDForm::VerifyRowAlignmentL(TInt aIndex)
       
  3057 {
       
  3058     TInt leftRightMask = MMIDItem::ELeft | MMIDItem::ERight;
       
  3059     CMIDControlItem& ci = ControlItem(iItems[aIndex]);
       
  3060 
       
  3061     if (iCurrentRow->NumItems() == 0)
       
  3062     {
       
  3063         // this is the first item in the row
       
  3064         if (!LayoutDefault(ci))
       
  3065         {
       
  3066             // we take the items alignment for the row
       
  3067             iCurrentAlignment = MMIDItem::TLayout(ci.Layout() & leftRightMask);
       
  3068             iCurrentRow->SetAlignment(iCurrentAlignment);
       
  3069         }
       
  3070     }
       
  3071     else if (!LayoutMatchesCurrentAlignment(ci, iCurrentAlignment))
       
  3072     {
       
  3073         // the new layout doesn't match the current so go to the next row
       
  3074         CreateNewRowAndSetAsCurrentL();
       
  3075         iCurrentAlignment = MMIDItem::TLayout(ci.Layout() & leftRightMask);
       
  3076         iCurrentRow->SetAlignment(iCurrentAlignment);
       
  3077     }
       
  3078 }
       
  3079 
       
  3080 /**
       
  3081      Inserts the specified number of new rows (aNumNewLines). If there is a control
       
  3082     item passed as a parameter it means the lines to be inserted are empty lines
       
  3083     preceeding the control and therefore should have their empty size set to the
       
  3084     size of the control.
       
  3085 
       
  3086      @param aControlItem The control item used to set the size of empty rows.
       
  3087 
       
  3088     @param aNumNewLines    The number of rows to be added, if equal to zero this method does
       
  3089                         nothing
       
  3090  */
       
  3091 void CMIDForm::InsertNewlinesL(TInt aNumNewlines, CMIDControlItem* aControlItem)
       
  3092 {
       
  3093     for (TInt idx = 0; idx < aNumNewlines; idx++)
       
  3094     {
       
  3095         if (aControlItem && aControlItem->LabelControl() && iCurrentRow && iCurrentRow->NumItems() == 0)
       
  3096         {
       
  3097             iCurrentRow->SetEmptyRowSize(TSize(iInnerWidth,aControlItem->OneLineLabelHeight()));
       
  3098         }
       
  3099 
       
  3100         CreateNewRowAndSetAsCurrentL();
       
  3101     }
       
  3102 }
       
  3103 
       
  3104 
       
  3105 /**
       
  3106  * Creates a new string item, using special type CMIDLabelContainerItem.
       
  3107  * This is a special string item which has no label and is added to wrap
       
  3108  * content of a previous string item across several rows.
       
  3109  *
       
  3110  *  @see CMIDLabelContainerItem
       
  3111  */
       
  3112 void CMIDForm::CreateAndAddLabelContainerItemL(CMIDStringItem& aStringItem,
       
  3113         CEikLabel& aLabel, TBool aIsStringItemContent)
       
  3114 {
       
  3115     // Label container items items have an horizontal margin only
       
  3116     // when at the beginning of the row
       
  3117     TBool hasHMargin = (iCurrentRow->NumItems() == 0);
       
  3118 
       
  3119     CMIDLabelContainerItem* usil =
       
  3120         CMIDLabelContainerItem::NewL(aStringItem, aLabel, hasHMargin);
       
  3121 
       
  3122     CleanupStack::PushL(usil);
       
  3123     usil->SetContainerWindowL(*this);
       
  3124     // sets flag for detecting if label container item is created
       
  3125     // from string item label or content
       
  3126     usil->SetIsStringItemContent(aIsStringItemContent);
       
  3127 
       
  3128     iCurrentRow->AppendL(usil);
       
  3129     CleanupStack::Pop(usil);
       
  3130 }
       
  3131 
       
  3132 /**
       
  3133  *  Inserts a CMIDLabelContainerItem for each line in aTextControl.
       
  3134  *
       
  3135  *  @see CreateAndAddLabelContainerItemL()
       
  3136  */
       
  3137 void CMIDForm::InsertContainerItemsL(CMIDStringItem& aStringItem,
       
  3138                                      CMIDItemLabel& aTextControl, TBool aIsStringItemContent)
       
  3139 {
       
  3140     TInt numLines = aTextControl.NumLines();
       
  3141     for (TInt j = 0; j < numLines; j++)
       
  3142     { // insert every line as a CMIDLabelContainerItem
       
  3143         CreateAndAddLabelContainerItemL(
       
  3144             aStringItem, *(aTextControl.LabelAtIdx(j)), aIsStringItemContent);
       
  3145 
       
  3146         if (j != (numLines-1))
       
  3147         { // insert a row break except for the last line
       
  3148             CreateNewRowAndSetAsCurrentL();
       
  3149         }
       
  3150     }
       
  3151 }
       
  3152 
       
  3153 /**
       
  3154     Adds an unconstrained string item to one or more rows. If the item
       
  3155     has a label always insert a line break (new row) before and if it
       
  3156     is followed by constrained item also after the label. Crop the label
       
  3157     to the full line width and insert is as a CMIDLabelContainerItem.
       
  3158 
       
  3159     If the item has no label we can start anywhere in the current row.
       
  3160     Split its content across the remaining width for the first line
       
  3161     and then across the full line width. Insert a CMIDLabelContainerItem
       
  3162     for each line and insert a row break after each CMIDLabelContainerItem
       
  3163     except the last one.
       
  3164 
       
  3165     Item with label can be inserted as default item when one of this
       
  3166     situation occurs:
       
  3167     - it is the last item in form
       
  3168     - following item is constrained
       
  3169     - following item is unconstrained but has a label
       
  3170 
       
  3171     Item without label can be inserted as default item when:
       
  3172     - it is the only item in form
       
  3173     - it is the first item in form and following item is
       
  3174     unconstrained but has a label (it starts in a new row)
       
  3175 
       
  3176     @see CMILabelContainerItem, InsertContainerItemsL(),
       
  3177          CreateNewRowAndSetAsCurrentL(), InsertNewlinesL()
       
  3178 */
       
  3179 void CMIDForm::AddUnconstrainedStringItemL(TInt& aIndex)
       
  3180 {
       
  3181     CMIDStringItem* si = (CMIDStringItem*)iItems[aIndex];
       
  3182 
       
  3183     TInt widthForText = Width();
       
  3184 
       
  3185     // check if next item is unconstrained and has label
       
  3186     TBool nextUnconstrainedHasLabel(EFalse);
       
  3187     if (aIndex < iItems.Count()-1 && ItemIsUnconstrained(aIndex + 1))
       
  3188     {
       
  3189         CMIDStringItem* nextItem = (CMIDStringItem*)iItems[aIndex+1];
       
  3190         if (nextItem->LabelControl() &&
       
  3191                 (nextItem->LabelControl()->Text()->Length() > 0))
       
  3192         {
       
  3193             nextUnconstrainedHasLabel = ETrue;
       
  3194         }
       
  3195     }
       
  3196 
       
  3197     if (si->LabelControl() && (si->LabelControl()->Text()->Length() > 0))
       
  3198     {//item has a label - it should be placed in a new row
       
  3199         if (iCurrentRow->NumItems() > 0)
       
  3200         {
       
  3201             CreateNewRowAndSetAsCurrentL();
       
  3202         }
       
  3203 
       
  3204         // If the item is last or next item is constrained or next item
       
  3205         // is unconstrained but has a label (it will be placed in a new row)
       
  3206         // this item is placed as default item.
       
  3207         if ((aIndex == iItems.Count()-1) || !ItemIsUnconstrained(aIndex + 1)
       
  3208                 || nextUnconstrainedHasLabel)
       
  3209         {
       
  3210             AddDefaultItemL(aIndex);
       
  3211             return;
       
  3212         }
       
  3213 
       
  3214         // otherwise place the label in one row and then insert the text
       
  3215         si->LabelControl()->SetWidthL(widthForText);
       
  3216         // label of string item is inserted as label container item
       
  3217         // EFalse identifies that label container item is created from string item label
       
  3218         InsertContainerItemsL(*si, *(si->LabelControl()), EFalse);
       
  3219         // string items is divided to label container items due to concatenation of contents
       
  3220         // contained in adjacent string items
       
  3221         si->SetIsDivided(ETrue);
       
  3222         CreateNewRowAndSetAsCurrentL();
       
  3223     }
       
  3224     else
       
  3225     { // item has no label
       
  3226 
       
  3227         // If the item is the only item in form or it is the first item in form
       
  3228         // and the next item is unconstrained with label (it starts at a new row)
       
  3229         // this item is placed as default item
       
  3230         if ((iItems.Count() == 1) || (aIndex == 0 && nextUnconstrainedHasLabel))
       
  3231         {
       
  3232             AddDefaultItemL(aIndex);
       
  3233             return;
       
  3234         }
       
  3235     }
       
  3236 
       
  3237     // this is either the remaining width on the current row or the full
       
  3238     // line width if we are on a new row
       
  3239     TInt remainingLineWidth = widthForText - iCurrentRow->CurrentWidth();
       
  3240 
       
  3241     if ((remainingLineWidth < si->StringContentControl()->FirstWordWidth())
       
  3242             && (iCurrentRow->NumItems() != 0))
       
  3243     { // if not even one word fits then go to the next line unless
       
  3244         // we are already on a new line
       
  3245         CreateNewRowAndSetAsCurrentL();
       
  3246         remainingLineWidth = widthForText;
       
  3247     }
       
  3248 
       
  3249     // wrap the content to the remaining width for the first line and to
       
  3250     // the full width for any other line
       
  3251     si->StringContentControl()->SetVariableWidthL(remainingLineWidth, widthForText);
       
  3252     // content of string item is inserted as label container item
       
  3253     // ETrue identifies that label container item is created from string item content
       
  3254     InsertContainerItemsL(*si, *(si->StringContentControl()), ETrue);
       
  3255 }
       
  3256 
       
  3257 /**
       
  3258  * Adds a standard case item to the current row. It verifies if a new
       
  3259  * row should be added and adds one if so. Then it appends the item
       
  3260  * to the current row.
       
  3261  *
       
  3262  * @see CMIDControlItem, OkToMoveToNextRow()
       
  3263  */
       
  3264 void CMIDForm::AddDefaultItemL(TInt& aIndex)
       
  3265 {
       
  3266     CMIDControlItem& ci = ControlItem(iItems[aIndex]);
       
  3267 
       
  3268     TSize itemSize = LayoutShrink(ci) ? ci.MinimumSize() : ci.PreferredSize();
       
  3269     ci.SetSizeQuiet(itemSize);
       
  3270 
       
  3271     if (OkToMoveToNextRow(itemSize))
       
  3272     {
       
  3273         CreateNewRowAndSetAsCurrentL();
       
  3274     }
       
  3275 
       
  3276     iCurrentRow->AppendL(&ci);
       
  3277 }
       
  3278 
       
  3279 /**
       
  3280     Return true if the given size does not fit into the current
       
  3281     row and the row is not empty and the size is not bigger than
       
  3282     an empty row.
       
  3283 */
       
  3284 TBool CMIDForm::OkToMoveToNextRow(const TSize& aItemSize) const
       
  3285 {
       
  3286     return ((iCurrentRow->CurrentWidth() + aItemSize.iWidth) > iInnerWidth) &&
       
  3287            !((aItemSize.iWidth > iInnerWidth) && (iCurrentRow->NumItems() == 0));
       
  3288 }
       
  3289 
       
  3290 /**
       
  3291     Assigns the items to the rows, which are re-created.
       
  3292 */
       
  3293 void CMIDForm::AssignItemsToRowsL()
       
  3294 {
       
  3295     DeleteRows();
       
  3296 
       
  3297     //reset current alignment
       
  3298     iCurrentAlignment = InitialAlignment();
       
  3299 
       
  3300     //Create a row, the form must have at least an empty row
       
  3301     CreateNewRowAndSetAsCurrentL();
       
  3302 
       
  3303     for (TInt i = 0;  i < iItems.Count(); i++)
       
  3304     {
       
  3305         if (SkipNullItem(i))
       
  3306         { //zero size items are ignored
       
  3307             continue;
       
  3308         }
       
  3309 
       
  3310         // if the current alignment changes we may need to change row
       
  3311         VerifyRowAlignmentL(i);
       
  3312 
       
  3313         CMIDControlItem& ci = ControlItem(iItems[i]);
       
  3314 
       
  3315         // add any extra rows before the current item if needed
       
  3316         InsertNewlinesL(NumNewLinesBefore(ci), &ci);
       
  3317 
       
  3318         if (ItemIsUnconstrained(i))
       
  3319         { // unconstrained string items are processed specially
       
  3320             AddUnconstrainedStringItemL(i);
       
  3321         }
       
  3322         else
       
  3323         { // any other item is processed in here
       
  3324             AddDefaultItemL(i);
       
  3325         }
       
  3326 
       
  3327         // add any additional row breaks if needed
       
  3328         InsertNewlinesL(NumNewLinesAfter(ci), &ci);
       
  3329     }
       
  3330 }
       
  3331 
       
  3332 /** Return true if the item is an unconstrained string item, false otherwise */
       
  3333 TBool CMIDForm::ItemIsUnconstrained(TInt aIndex) const
       
  3334 {
       
  3335     if (aIndex >= 0 && aIndex < iItems.Count())
       
  3336     {
       
  3337         CMIDControlItem& ci = ControlItem(iItems[aIndex]);
       
  3338         return (IsStringItem(ci) && ((CMIDStringItem*)&ci)->IsUnconstrainedStringItem());
       
  3339     }
       
  3340 
       
  3341     return EFalse;
       
  3342 }
       
  3343 
       
  3344 TBool CMIDForm::LayoutMatchesCurrentAlignment(CMIDControlItem& aControlItem,
       
  3345         MMIDItem::TLayout aCurrentAlignment)
       
  3346 {
       
  3347     TInt leftRightMask = MMIDItem::ELeft | MMIDItem::ERight;
       
  3348 
       
  3349     return ((aControlItem.Layout() & leftRightMask) == MMIDItem::EDefault) ||
       
  3350            ((aControlItem.Layout() & leftRightMask) == aCurrentAlignment);
       
  3351 }
       
  3352 
       
  3353 TBool CMIDForm::LayoutDefault(CMIDControlItem& aControlItem)
       
  3354 {
       
  3355     TInt leftRightMask = MMIDItem::ELeft | MMIDItem::ERight;
       
  3356 
       
  3357     return ((aControlItem.Layout() & leftRightMask) == MMIDItem::EDefault);
       
  3358 }
       
  3359 
       
  3360 TBool CMIDForm::LayoutNewLineBefore(CMIDControlItem& aControlItem)
       
  3361 {
       
  3362     return (aControlItem.Layout() & MMIDItem::ENewLineBefore);
       
  3363 }
       
  3364 
       
  3365 TBool CMIDForm::LayoutNewLineAfter(CMIDControlItem& aControlItem)
       
  3366 {
       
  3367     return (aControlItem.Layout() & MMIDItem::ENewLineAfter);
       
  3368 }
       
  3369 
       
  3370 /** Return true if the LAYOUT_SHRINK directive has been set. For
       
  3371 string items which have one or both dimensions of the preferred
       
  3372 size set the layout shrink directive is ignored. */
       
  3373 TBool CMIDForm::LayoutShrink(CMIDControlItem& aControlItem)
       
  3374 {
       
  3375     if (IsStringItem(aControlItem))
       
  3376     {
       
  3377         CMIDStringItem* si = (CMIDStringItem*)(&aControlItem);
       
  3378 
       
  3379         if (si->WidthOrHeightSpecified())
       
  3380         {
       
  3381             return EFalse;
       
  3382         }
       
  3383     }
       
  3384 
       
  3385     return (aControlItem.Layout() & MMIDItem::EShrink);
       
  3386 }
       
  3387 
       
  3388 /** Return true if the LAYOUT_EXPAND directive has been set. For
       
  3389 string items which have one or both dimensions of the preferred
       
  3390 size set the layout expand directive is ignored. */
       
  3391 TBool CMIDForm::LayoutExpand(CMIDControlItem& aControlItem)
       
  3392 {
       
  3393     if (IsStringItem(aControlItem))
       
  3394     {
       
  3395         CMIDStringItem* si = (CMIDStringItem*)(&aControlItem);
       
  3396 
       
  3397         if (si->WidthOrHeightSpecified())
       
  3398         {
       
  3399             return EFalse;
       
  3400         }
       
  3401     }
       
  3402 
       
  3403     return (aControlItem.Layout() & MMIDItem::EExpand);
       
  3404 }
       
  3405 
       
  3406 /** Return true if the LAYOUT_VSHIRNK directive has been set. For
       
  3407 string items which have one or both dimensions of the preferred
       
  3408 size set the layout vertical shrink directive is ignored. */
       
  3409 TBool CMIDForm::LayoutVerticalShrink(CMIDControlItem& aControlItem)
       
  3410 {
       
  3411     if (IsStringItem(aControlItem))
       
  3412     {
       
  3413         CMIDStringItem* si = (CMIDStringItem*)(&aControlItem);
       
  3414 
       
  3415         if (si->WidthOrHeightSpecified())
       
  3416         {
       
  3417             return EFalse;
       
  3418         }
       
  3419     }
       
  3420 
       
  3421     return (aControlItem.Layout() & MMIDItem::EVerticalShrink);
       
  3422 }
       
  3423 
       
  3424 /** Return true if the LAYOUT_VEXPAND directive has been set. For
       
  3425 string items which have one or both dimensions of the preferred
       
  3426 size set the layout vertical expand directive is ignored. */
       
  3427 TBool CMIDForm::LayoutVerticalExpand(CMIDControlItem& aControlItem)
       
  3428 {
       
  3429     if (IsStringItem(aControlItem))
       
  3430     {
       
  3431         CMIDStringItem* si = (CMIDStringItem*)(&aControlItem);
       
  3432 
       
  3433         if (si->WidthOrHeightSpecified())
       
  3434         {
       
  3435             return EFalse;
       
  3436         }
       
  3437     }
       
  3438 
       
  3439     return (aControlItem.Layout() & MMIDItem::EVerticalExpand);
       
  3440 }
       
  3441 
       
  3442 TBool CMIDForm::LayoutVerticalCenter(CMIDControlItem& aControlItem)
       
  3443 {
       
  3444     TInt layout = aControlItem.Layout();
       
  3445     layout &= MMIDItem::EVerticalCenter;
       
  3446     return (layout == MMIDItem::EVerticalCenter);
       
  3447 }
       
  3448 
       
  3449 TBool CMIDForm::LayoutBottom(CMIDControlItem& aControlItem)
       
  3450 {
       
  3451     TInt layout = aControlItem.Layout();
       
  3452     layout &= MMIDItem::EVerticalCenter;
       
  3453     return (layout == MMIDItem::EBottom) || (layout == 0);
       
  3454 }
       
  3455 
       
  3456 TBool CMIDForm::IsStringItem(CMIDControlItem& aControlItem)
       
  3457 {
       
  3458     if (!aControlItem.iMMidItem)
       
  3459     {
       
  3460         return EFalse;
       
  3461     }
       
  3462     return (aControlItem.iMMidItem->Type() == MMIDComponent::EStringItem);
       
  3463 }
       
  3464 
       
  3465 TBool CMIDForm::IsStringItemHyperlink(CMIDControlItem& aControlItem)
       
  3466 {
       
  3467     if (!aControlItem.iMMidItem)
       
  3468     {
       
  3469         return EFalse;
       
  3470     }
       
  3471     if (aControlItem.iMMidItem->Type() == MMIDComponent::EStringItem)
       
  3472     {
       
  3473         return (((CMIDStringItem&) aControlItem).Appearance() == MMIDItem::EHyperLink);
       
  3474     }
       
  3475     else
       
  3476     {
       
  3477         return EFalse;
       
  3478     }
       
  3479 }
       
  3480 
       
  3481 TBool CMIDForm::IsStringItemButton(CMIDControlItem& aControlItem)
       
  3482 {
       
  3483     if (!aControlItem.iMMidItem)
       
  3484     {
       
  3485         return EFalse;
       
  3486     }
       
  3487     if (aControlItem.iMMidItem->Type() == MMIDComponent::EStringItem)
       
  3488     {
       
  3489         return (((CMIDStringItem&) aControlItem).Appearance() == MMIDItem::EButton);
       
  3490     }
       
  3491     else
       
  3492     {
       
  3493         return EFalse;
       
  3494     }
       
  3495 }
       
  3496 
       
  3497 TBool CMIDForm::IsCustomItem(CMIDControlItem& aControlItem)
       
  3498 {
       
  3499     if (!aControlItem.iMMidItem)
       
  3500     {
       
  3501         return EFalse;
       
  3502     }
       
  3503     return (aControlItem.iMMidItem->Type() == MMIDComponent::ECustomItem);
       
  3504 }
       
  3505 
       
  3506 TBool CMIDForm::IsGaugeItem(CMIDControlItem& aControlItem)
       
  3507 {
       
  3508     if (!aControlItem.iMMidItem)
       
  3509     {
       
  3510         return EFalse;
       
  3511     }
       
  3512     return (aControlItem.iMMidItem->Type() == MMIDComponent::EGauge);
       
  3513 }
       
  3514 
       
  3515 TBool CMIDForm::IsTextFieldItem(CMIDControlItem& aControlItem)
       
  3516 {
       
  3517     if (!aControlItem.iMMidItem)
       
  3518     {
       
  3519         return EFalse;
       
  3520     }
       
  3521     return (aControlItem.iMMidItem->Type() == MMIDComponent::ETextField);
       
  3522 }
       
  3523 
       
  3524 TBool CMIDForm::IsChoiceGroup(CMIDControlItem& aControlItem)
       
  3525 {
       
  3526     if (!aControlItem.iMMidItem)
       
  3527     {
       
  3528         return EFalse;
       
  3529     }
       
  3530     return (aControlItem.iMMidItem->Type() == MMIDComponent::EChoiceGroup);
       
  3531 }
       
  3532 
       
  3533 TBool CMIDForm::IsDateField(CMIDControlItem& aControlItem)
       
  3534 {
       
  3535     if (!aControlItem.iMMidItem)
       
  3536     {
       
  3537         return EFalse;
       
  3538     }
       
  3539     return (aControlItem.iMMidItem->Type() == MMIDComponent::EDateField);
       
  3540 }
       
  3541 
       
  3542 TBool CMIDForm::IsLabelContainerItem(CMIDControlItem& aControlItem)
       
  3543 {
       
  3544     return (aControlItem.Type() == KLabelContainerItem);
       
  3545 }
       
  3546 
       
  3547 TBool CMIDForm::IsSpacerUsedForFormatting(CMIDControlItem& aControlItem)
       
  3548 {
       
  3549     if (!aControlItem.iMMidItem)
       
  3550     {
       
  3551         return EFalse;
       
  3552     }
       
  3553     if (aControlItem.iMMidItem->Type() == MMIDComponent::ESpacer)
       
  3554     {
       
  3555         CMIDSpacer* spacer = static_cast<CMIDSpacer*>(&aControlItem);
       
  3556         return spacer->UsedForStringFormatting();
       
  3557     }
       
  3558     return EFalse;
       
  3559 }
       
  3560 
       
  3561 TBool CMIDForm::IsImageItem(CMIDControlItem& aControlItem)
       
  3562 {
       
  3563     if (!aControlItem.iMMidItem)
       
  3564     {
       
  3565         return EFalse;
       
  3566     }
       
  3567     return (aControlItem.iMMidItem->Type() == MMIDItem::EImageItem);
       
  3568 }
       
  3569 
       
  3570 #ifdef RD_JAVA_S60_RELEASE_9_2
       
  3571 void CMIDForm::PostPendingUpEventL()
       
  3572 {
       
  3573     MMIDItem* curItem = CurrentItem();
       
  3574     if (curItem)
       
  3575     {
       
  3576         CMIDControlItem& item = ControlItem(curItem);
       
  3577 
       
  3578         if (IsChoiceGroup(item))
       
  3579         {
       
  3580             CMIDChoiceGroupItem* cgItem = static_cast<CMIDChoiceGroupItem*>(&item);
       
  3581             cgItem->PostPendingUpEventL();
       
  3582         }
       
  3583     }
       
  3584 }
       
  3585 #endif // RD_JAVA_S60_RELEASE_9_2
       
  3586 
       
  3587 // returns: The number of new lines before an item.
       
  3588 //          This only takes into account new lines that come from
       
  3589 //          preceeding a string item with new line characters.
       
  3590 TInt CMIDForm::NumNewLinesBefore(CMIDControlItem& aControlItem)
       
  3591 {
       
  3592     if (IsStringItem(aControlItem))
       
  3593     {
       
  3594         CMIDStringItem* si = (CMIDStringItem*)(&aControlItem);
       
  3595         TInt nLinesBefore = si->NumNewlinesBefore();
       
  3596         if (nLinesBefore > 0)
       
  3597         {
       
  3598             return nLinesBefore;
       
  3599         }
       
  3600     }
       
  3601     if (iCurrentRow && iCurrentRow->NumItems() == 0)
       
  3602     {
       
  3603         return 0;
       
  3604     }
       
  3605     return LayoutNewLineBefore(aControlItem) ? 1 : 0;
       
  3606 }
       
  3607 
       
  3608 // returns: The number of new lines that should appear after an item
       
  3609 //          This takes into account the new lines that can occour from
       
  3610 //          newlines at the end of a string item, and if there are none
       
  3611 //          of these, then it returns 1 if the Layout NewLineAfter
       
  3612 //          directive has been used and 0 otherwise.
       
  3613 TInt CMIDForm::NumNewLinesAfter(CMIDControlItem& aControlItem)
       
  3614 {
       
  3615     if (IsStringItem(aControlItem))
       
  3616     {
       
  3617         CMIDStringItem* si = (CMIDStringItem*)(&aControlItem);
       
  3618         if (si->NumNewlinesAfter() > 0)
       
  3619         {
       
  3620             TInt nLinesAfter = si->NumNewlinesAfter();
       
  3621             if (nLinesAfter > 0)
       
  3622             {
       
  3623                 return nLinesAfter;
       
  3624             }
       
  3625         }
       
  3626     }
       
  3627     return LayoutNewLineAfter(aControlItem) ? 1 : 0;
       
  3628 }
       
  3629 
       
  3630 // effects:  Sizes the items within the rows based on their layout characteristics
       
  3631 // modifies: CMIDFormRow
       
  3632 void CMIDForm::SizeItemsInFormRowsL()
       
  3633 {
       
  3634     TInt rowCount = iRows.Count();
       
  3635     for (TInt i=0; i < rowCount; i++)
       
  3636     {
       
  3637         iRows[i]->SizeItemsL();
       
  3638     }
       
  3639 }
       
  3640 
       
  3641 // effects:  Deletes all rows in the Form. It doesn't affect the items that have
       
  3642 //           been added to the form.
       
  3643 // modifies: CMIDForm, CMIDFormRow
       
  3644 void CMIDForm::DeleteRows()
       
  3645 {
       
  3646     for (TInt i=0; i < iRows.Count(); i++)
       
  3647     {
       
  3648         delete iRows[i];
       
  3649     }
       
  3650 
       
  3651     iRows.Reset();
       
  3652     iCurrentRow = NULL;
       
  3653 }
       
  3654 
       
  3655 TInt CMIDForm::HeightOfAllItems()
       
  3656 {
       
  3657     return iTotalFormHeight;
       
  3658 }
       
  3659 
       
  3660 void CMIDForm::UpdateHeightOfAllItems()
       
  3661 {
       
  3662     TInt yTopMargin = iFormRect.Rect().iTl.iY - iMidpFormRect.Rect().iTl.iY;
       
  3663     TInt yBottomMargin = iMidpFormRect.Rect().iBr.iY - iFormRect.Rect().iBr.iY;
       
  3664 
       
  3665     iTotalFormHeight = yTopMargin;
       
  3666 
       
  3667     TInt rowCount = iRows.Count();
       
  3668     for (TInt i=0; i < rowCount; i++)
       
  3669     {
       
  3670         iTotalFormHeight += iRows[i]->Size().iHeight;
       
  3671     }
       
  3672     // Form bottom margin is added
       
  3673     iTotalFormHeight += yBottomMargin;
       
  3674 }
       
  3675 
       
  3676 /* HandleResourceChange
       
  3677  *
       
  3678  * This method is called after a resource change event, for example after
       
  3679  * screen dynamic resolution change.
       
  3680  *
       
  3681  * In the case of a screen dynamic resolution change we notify all items and
       
  3682  * repeat the entire form layout.
       
  3683  *
       
  3684  * We calculate the % of form that has been scrolled so far and we
       
  3685  * modify iScroll so that we have scrolled the same % of form after resolution
       
  3686  * change. Note that the max extent of iScroll is HeightOfAllItems() - Height()
       
  3687  * and not simply HeightOfAllItems() as one may think, see
       
  3688  * SetRowExtentsWithRespectToScrolledLocation(). Also note that applying a %
       
  3689  * scrolling does not necessarily mean the same items will be on screen after a
       
  3690  * resolution change.
       
  3691  * Especially when changing from portrait to landscape or vice-versa the
       
  3692  * number of items on a row vary greatly and as a consequence the number of
       
  3693  * rows may vary. Therefore, if there is a focused item on screen before
       
  3694  * resolution change (iFocused not KErrNotFound) we make sure this item is
       
  3695  * visible and focused after res change by scrolling to it, see SetFocusedItem()
       
  3696  * and ScrollToFocused().
       
  3697  */
       
  3698 void CMIDForm::HandleResourceChange(TInt aType)
       
  3699 {
       
  3700     TInt maxScrollExtentOld = HeightOfAllItems() - Height(); //max extent of iScroll
       
  3701     CCoeControl::HandleResourceChange(aType);
       
  3702 
       
  3703     if (aType == KEikDynamicLayoutVariantSwitch)
       
  3704     { // dynamic resolution change
       
  3705         TInt focusedItem = iFocused;
       
  3706 
       
  3707         UpdateMemberVariables();
       
  3708         UpdateHeightOfAllItems();
       
  3709 
       
  3710         TInt itemCount = iItems.Count();
       
  3711         for (TInt i=0; i < itemCount; i++)
       
  3712         {
       
  3713             CMIDControlItem& controlItem = ControlItem(i);
       
  3714             controlItem.ResolutionChange(aType);
       
  3715 
       
  3716             if (controlItem.LabelControl())
       
  3717             {
       
  3718                 controlItem.LabelControl()->ResolutionChange();
       
  3719             }
       
  3720         }
       
  3721 
       
  3722         TInt maxScrollExtentNew = HeightOfAllItems() - Height(); //max extent of iScroll
       
  3723 
       
  3724         TRAPD(err,LayoutFormL());
       
  3725 
       
  3726         if (err == KErrNone)
       
  3727         {
       
  3728             if ((maxScrollExtentNew <= 0) && (maxScrollExtentOld > 0))
       
  3729             {
       
  3730                 // scroll on top
       
  3731                 RawScroll(0);
       
  3732                 if (focusedItem != KErrNotFound)
       
  3733                 {
       
  3734                     // restore the form item focus
       
  3735                     CMIDControlItem& control = ControlItem(focusedItem);
       
  3736                     control.RestoreInnerFocus();
       
  3737                 }
       
  3738             }
       
  3739             else
       
  3740             {
       
  3741                 if ((maxScrollExtentNew > 0) || (maxScrollExtentOld > 0))
       
  3742                 {
       
  3743                     // if there is something focused
       
  3744                     if (focusedItem != KErrNotFound)
       
  3745                     {
       
  3746                         // restore the form item focus
       
  3747                         CMIDControlItem& control = ControlItem(focusedItem);
       
  3748                         ScrollToFocused();
       
  3749                         control.RestoreInnerFocus();
       
  3750                     }
       
  3751                     // if scroll out of maxScrollExtent
       
  3752                     if (maxScrollExtentNew+iScroll < 0)
       
  3753                     {
       
  3754                         // scroll to bottom
       
  3755                         RawScroll(-maxScrollExtentNew);
       
  3756                     }
       
  3757 
       
  3758                 }
       
  3759             }
       
  3760         }
       
  3761 
       
  3762         SetHighlightBackgroundRects();
       
  3763         HandleItemVisibilityChange();
       
  3764         UpdateScrollBar();
       
  3765         DrawDeferred();
       
  3766     }
       
  3767     else if (aType == KEikColorResourceChange || aType == KAknsMessageSkinChange ||
       
  3768              aType == KUidValueCoeColorSchemeChangeEvent)
       
  3769     {//skin or color scheme change
       
  3770         TInt itemCount = iItems.Count();
       
  3771         for (TInt i=0; i < itemCount; i++)
       
  3772         {
       
  3773             CMIDControlItem& controlItem = ControlItem(i);
       
  3774             controlItem.ColorChange(aType);
       
  3775         }
       
  3776 
       
  3777         // send this event also to form scrollbar
       
  3778         CEikScrollBar* sb = iSBFrame->GetScrollBarHandle(CEikScrollBar::EVertical);
       
  3779         if (sb)
       
  3780         {
       
  3781             sb->HandleResourceChange(aType);
       
  3782         }
       
  3783     }
       
  3784     else if ((aType == KEikMessageUnfadeWindows) ||
       
  3785              (aType == KEikMessageFadeAllWindows))
       
  3786     {
       
  3787         iLastFadeMessage = aType;
       
  3788     }
       
  3789     else if ((aType == KEikMessageWindowsFadeChange) &&
       
  3790              ((iLastFadeMessage == KEikMessageUnfadeWindows) ||
       
  3791               (iLastFadeMessage == KEikMessageFadeAllWindows)))
       
  3792     {
       
  3793         TInt itemCount = iItems.Count();
       
  3794         for (TInt i=0; i < itemCount; i++)
       
  3795         {
       
  3796             CMIDControlItem& controlItem = ControlItem(i);
       
  3797             controlItem.HandleWindowFade(iLastFadeMessage == KEikMessageFadeAllWindows);
       
  3798         }
       
  3799         iLastFadeMessage = 0;
       
  3800     }
       
  3801 
       
  3802     UpdatePhysics();
       
  3803 }
       
  3804 
       
  3805 TBool CMIDForm::TryDetectLongTapL(const TPointerEvent &aPointerEvent)
       
  3806 {
       
  3807     return iDisplayable.TryDetectLongTapL(aPointerEvent);
       
  3808 }
       
  3809 
       
  3810 #ifdef RD_SCALABLE_UI_V2
       
  3811 void CMIDForm::HandleScrollEventL(CEikScrollBar* aScrollBar, TEikScrollEvent aEventType)
       
  3812 {
       
  3813     if (AknLayoutUtils::PenEnabled())
       
  3814     {
       
  3815 
       
  3816         if (LayoutPending())
       
  3817         {
       
  3818             LayoutFormL();
       
  3819         }
       
  3820 
       
  3821         TInt pixelIndex;
       
  3822 
       
  3823         switch (aEventType)
       
  3824         {
       
  3825         case EEikScrollUp:
       
  3826         {
       
  3827             pixelIndex = iScroll + (Height() / KScrollAmountDivider);
       
  3828             break;
       
  3829         }
       
  3830 
       
  3831         case EEikScrollDown:
       
  3832         {
       
  3833             pixelIndex = iScroll - (Height() / KScrollAmountDivider);
       
  3834             break;
       
  3835         }
       
  3836 
       
  3837         case EEikScrollPageUp:
       
  3838         {
       
  3839             pixelIndex = iScroll + Height();
       
  3840             break;
       
  3841         }
       
  3842 
       
  3843         case EEikScrollPageDown:
       
  3844         {
       
  3845             pixelIndex = iScroll - Height();
       
  3846             break;
       
  3847         }
       
  3848 
       
  3849         default://thumb drag
       
  3850         {
       
  3851             //scroll form if thumb position has moved more than 1/10 of the screen height either up or down
       
  3852             //or thumb position is at top or at bottom of the scrollbar.
       
  3853             if (-aScrollBar->ThumbPosition() < (iScroll - (Height() / KScrollAmountDividerForThumbDrag))
       
  3854                     || -aScrollBar->ThumbPosition() > (iScroll + (Height() / KScrollAmountDividerForThumbDrag))
       
  3855                     || aScrollBar->ThumbPosition() == 0
       
  3856                     || aScrollBar->ThumbPosition() == aScrollBar->Model()->MaxThumbPos())
       
  3857             {
       
  3858                 aScrollBar->DrawNow();
       
  3859                 pixelIndex = - aScrollBar->ThumbPosition();
       
  3860             }
       
  3861             else
       
  3862             {
       
  3863                 return;
       
  3864             }
       
  3865             break;
       
  3866         }
       
  3867         }
       
  3868         RawScroll(pixelIndex);
       
  3869         RawScrollFinalize(ETrue);
       
  3870         UpdatePhysics();
       
  3871     }
       
  3872 }
       
  3873 
       
  3874 
       
  3875 TBool CMIDForm::StringItemContainsPoint(CMIDStringItem* aStringItem, const TPoint& aPoint) const
       
  3876 {
       
  3877     CMIDControlItem* ci = ControlItemAtPoint(aPoint);
       
  3878 
       
  3879     if (ci)
       
  3880     {
       
  3881         if (IsLabelContainerItem(*ci))
       
  3882         {
       
  3883             CMIDLabelContainerItem *lci = static_cast<CMIDLabelContainerItem*>(ci);
       
  3884             CMIDStringItem& si = lci->StringItem();
       
  3885             if (&si == aStringItem)
       
  3886             { // LabelContainer item is (part of) StringItem
       
  3887                 if (si.IsDivided())
       
  3888                 { // StringItem was divided due to concatenation of contents
       
  3889                     if (lci->IsStringItemContent())
       
  3890                     { // return ETrue if is pointed to StringItem content
       
  3891                         return ETrue;
       
  3892                     }
       
  3893                     else
       
  3894                     { // return EFasle if is pointed to StringItem label
       
  3895                         return EFalse;
       
  3896                     }
       
  3897                 }
       
  3898                 else
       
  3899                 { // StringItem was not divided, pointed directly to unconstrained StringItem
       
  3900                     return ETrue;
       
  3901                 }
       
  3902             }
       
  3903         }
       
  3904         else
       
  3905         {
       
  3906             return (ci == aStringItem && aStringItem->TappingActionRect().Contains(aPoint));
       
  3907         }
       
  3908     }
       
  3909 
       
  3910     return EFalse;
       
  3911 }
       
  3912 
       
  3913 TBool CMIDForm::IsFocusChangingWithPen() const
       
  3914 {
       
  3915     return iFocusChangingWithPen;
       
  3916 }
       
  3917 
       
  3918 #endif //RD_SCALABLE_UI_V2
       
  3919 
       
  3920 
       
  3921 void CMIDForm::HandleForegroundL(TBool aForeground)
       
  3922 {
       
  3923     // send HandleForegroundL notification to gauge items
       
  3924     TInt itemsCount = iItems.Count();
       
  3925     for (TInt i=0; i < itemsCount; i++)
       
  3926     {
       
  3927         if (iItems[i]->Type() == MMIDComponent::EGauge)
       
  3928         {
       
  3929             CMIDGaugeItem* gauge = static_cast<CMIDGaugeItem*>(iItems[i]);
       
  3930             ASSERT(gauge);
       
  3931             gauge->HandleForegroundL(aForeground);
       
  3932         }
       
  3933     }
       
  3934 }
       
  3935 
       
  3936 CMIDPopupNoteController* CMIDForm::GetPopupNoteController() const
       
  3937 {
       
  3938     return  iPopupController;
       
  3939 }
       
  3940 
       
  3941 TInt CMIDForm::GetMidpNaviPos()
       
  3942 {
       
  3943     // get main pane size from CEikAppU
       
  3944     TRect mainPane = iAvkonAppUi->ApplicationRect();
       
  3945 
       
  3946     // get screen size in pixels
       
  3947     TAknLayoutRect mainMidpPane;
       
  3948     mainMidpPane.LayoutRect(iEikonEnv->ScreenDevice()->SizeInPixels(),
       
  3949                             AknLayoutScalable_Avkon::main_midp_pane().LayoutLine());
       
  3950 
       
  3951     // getting form size depends on screen orientation
       
  3952     TInt variety = Layout_Meta_Data::IsLandscapeOrientation() ? 1 : 0;
       
  3953     iMidpFormRect.LayoutRect(mainMidpPane.Rect(),
       
  3954                              AknLayoutScalable_Avkon::midp_form_pane(variety).LayoutLine());
       
  3955 
       
  3956     // different between screen size and form size
       
  3957     TInt xFormDiff = mainMidpPane.Rect().iBr.iX - iMidpFormRect.Rect().iBr.iX;
       
  3958     // width of navi bar position only for ( iAlignment == MMIDItem::ERight )
       
  3959     TInt xNaviPos  = iMidpFormRect.Rect().iTl.iX - xFormDiff;
       
  3960 
       
  3961     return xNaviPos;
       
  3962 }
       
  3963 
       
  3964 void CMIDForm::UpdatePhysics()
       
  3965 {
       
  3966     if (iPhysics)
       
  3967     {
       
  3968         TSize worldSize(Width(), HeightOfAllItems());
       
  3969         TSize viewSize(Width(), Height());
       
  3970         TPoint viewCenter(Width() / 2, -iScroll + Height() / 2);
       
  3971         TRAP_IGNORE(iPhysics->InitPhysicsL(worldSize, viewSize, viewCenter));
       
  3972     }
       
  3973 }
       
  3974 
       
  3975 TInt CMIDForm::HighlightTimerCallback(TAny* aPtr)
       
  3976 {
       
  3977     CMIDForm* me = static_cast<CMIDForm*>(aPtr);
       
  3978     me->HandleHighlightTimer();
       
  3979     return 0;
       
  3980 }
       
  3981 
       
  3982 void CMIDForm::HandleHighlightTimer()
       
  3983 {
       
  3984     iHighlightTimer->Cancel();
       
  3985 
       
  3986     if (iPointedControl && iPointedControl->IsSelectable())
       
  3987     {
       
  3988         // If tactile feedback has not been given already
       
  3989         // give basic tactile feedback when focus changes.
       
  3990         // Don't give tactile feedback for button because it is handled
       
  3991         // by button implementation.
       
  3992 #ifdef RD_TACTILE_FEEDBACK
       
  3993         if (!iFeedbackExecutedInPointerDown)
       
  3994         {
       
  3995             DoFeedbackOnFocusChange(*iPointedControl);
       
  3996             iFeedbackExecutedInPointerDown = ETrue;
       
  3997         }
       
  3998 #endif // RD_TACTILE_FEEDBACK
       
  3999 
       
  4000         TInt itemIndex = ItemIndex(*iPointedControl);
       
  4001 
       
  4002         if (itemIndex != iFocused)
       
  4003         {
       
  4004             SetFocusedItem(itemIndex, ENone, EFalse);
       
  4005             DrawDeferred();
       
  4006         }
       
  4007 
       
  4008         if (!PhysicsScrolling() && !iUpEventSent)
       
  4009         {
       
  4010             TRAP_IGNORE(ForwardPointerEventToItemL(iLastPointerDownEvent));
       
  4011         }
       
  4012     }
       
  4013 }
       
  4014 
       
  4015 void CMIDForm::SetHighlightBackgroundRects()
       
  4016 {
       
  4017     if (iFocused == KErrNotFound)
       
  4018     {
       
  4019         return;
       
  4020     }
       
  4021 
       
  4022     CMIDControlItem& ci = ControlItem(iFocused);
       
  4023 
       
  4024     // Limit rect size to screen size. If Rect() is way larger
       
  4025     // than screen, the svg engine will not cope handling that.
       
  4026     TRect r(ci.Size());
       
  4027     TRect s;
       
  4028     AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EScreen, s);
       
  4029 
       
  4030     if (r.Intersects(s))
       
  4031     {
       
  4032         s.Intersection(r);
       
  4033     }
       
  4034 
       
  4035     TRect rect(s);
       
  4036     rect.Normalize(); // ensure positive w & h, just in case
       
  4037 
       
  4038     TAknLayoutRect topLeft ;
       
  4039     topLeft.LayoutRect(rect, SkinLayout::Input_field_skin_placing__general__Line_2());
       
  4040 
       
  4041     TAknLayoutRect bottomRight;
       
  4042     bottomRight.LayoutRect(rect, SkinLayout::Input_field_skin_placing__general__Line_5());
       
  4043 
       
  4044     TRect outerRect = TRect(topLeft.Rect().iTl, bottomRight.Rect().iBr);
       
  4045     TRect innerRect = TRect(topLeft.Rect().iBr, bottomRight.Rect().iTl);
       
  4046 
       
  4047     iHighlightedBackgroundCc->SetParentContext(iDisplayable.BackGroundControlContext());
       
  4048     iHighlightedBackgroundCc->SetFrameRects(outerRect, innerRect);
       
  4049 
       
  4050     UpdateHighlightBackgroundPosition();
       
  4051 }
       
  4052 
       
  4053 void CMIDForm::UpdateHighlightBackgroundPosition()
       
  4054 {
       
  4055 
       
  4056     if (iFocused != KErrNotFound)
       
  4057     {
       
  4058         CMIDControlItem& ci = ControlItem(iFocused);
       
  4059         TPoint highlightPosition = ci.PositionRelativeToScreen();
       
  4060         TRect focusedRect = ci.Rect();
       
  4061 
       
  4062         // Max size of the higlight background is limited to screen size,
       
  4063         // see SetHighlightBackgroundRects().
       
  4064         // Need to adjust the highlight position if focused item is partially visible
       
  4065         // on top of the form and it is larger than screen.
       
  4066         if (focusedRect.iTl.iY < 0 && focusedRect.iBr.iY > 0)
       
  4067         {
       
  4068             TRect screen;
       
  4069             AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EScreen, screen);
       
  4070             if (focusedRect.Height() > screen.Height())
       
  4071             {
       
  4072                 if (focusedRect.iBr.iY > iSize.iHeight)
       
  4073                 {
       
  4074                     // Focused item fills the visible form area fully
       
  4075                     highlightPosition.iY = 0;
       
  4076                 }
       
  4077                 else
       
  4078                 {
       
  4079                     // Bottom of focused item is in the visible form area
       
  4080                     highlightPosition.iY += focusedRect.Height() - screen.Height();
       
  4081                 }
       
  4082             }
       
  4083         }
       
  4084 
       
  4085         iHighlightedBackgroundCc->SetParentPos(highlightPosition);
       
  4086     }
       
  4087 }
       
  4088 
       
  4089 void CMIDForm::HandlePhysicsPointerEventL(const TPointerEvent& aPointerEvent)
       
  4090 {
       
  4091     if (iPhysics && iPhysics->CanBeStopped())
       
  4092     {
       
  4093         switch (aPointerEvent.iType)
       
  4094         {
       
  4095         case TPointerEvent::EButton1Down:
       
  4096         {
       
  4097             iPreventPhysicsScrolling = EFalse;
       
  4098             iFlickStoppedOnDownEvent = iFlickOngoing;
       
  4099             iFeedbackExecutedInPointerDown = EFalse;
       
  4100             iPhysics->Stop();
       
  4101             CMIDControlItem* ci = ControlItemAtPoint(aPointerEvent.iPosition);
       
  4102 
       
  4103             // Physics scrolling was not ongoing and tap hit already selected item.
       
  4104             // Then forward pointer event to the item.
       
  4105             if (ci && IsCurrentItem((CMIDItem*)ci) && !iFlickStoppedOnDownEvent)
       
  4106             {
       
  4107                 iPointedControl = ci;
       
  4108                 ForwardPointerEventToItemL(aPointerEvent);
       
  4109             }
       
  4110             else
       
  4111             {
       
  4112                 // Tactile fedback is executed when kinetic scrolling is stopped on down event.
       
  4113                 if (iFlickStoppedOnDownEvent)
       
  4114                 {
       
  4115 #ifdef RD_TACTILE_FEEDBACK
       
  4116 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  4117                     iFeedback->InstantFeedback(ETouchFeedbackList);
       
  4118 #else
       
  4119                     iFeedback->InstantFeedback(ETouchFeedbackBasic);
       
  4120 #endif // RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  4121                     iFeedbackExecutedInPointerDown = ETrue;
       
  4122 #endif // RD_TACTILE_FEEDBACK
       
  4123                 }
       
  4124 
       
  4125                 // Pointed control changes.
       
  4126                 if (ci && ci->IsSelectable() && (MMIDItem*)ci != CurrentItem())
       
  4127                 {
       
  4128                     iFocusChangingWithPen = ETrue;
       
  4129                 }
       
  4130 
       
  4131                 // Start highlight timer
       
  4132                 iPointedControl = ci;
       
  4133                 iHighlightTimer->Cancel();
       
  4134                 // Start highlight timer if some any control is tapped.
       
  4135                 if (iPointedControl)
       
  4136                 {
       
  4137                     TInt highlightTimeout = iPhysics->HighlightDelay() * 1000;
       
  4138                     iHighlightTimer->Start(TTimeIntervalMicroSeconds32(highlightTimeout),
       
  4139                                            TTimeIntervalMicroSeconds32(highlightTimeout),
       
  4140                                            TCallBack(HighlightTimerCallback, this));
       
  4141                 }
       
  4142             }
       
  4143             // Setup members
       
  4144             iStartPosition = aPointerEvent.iPosition;
       
  4145             iLastPointerDownEvent = aPointerEvent;
       
  4146             iUpEventSent = EFalse;
       
  4147             iStartTime.HomeTime();
       
  4148             iLastDragPosition = aPointerEvent.iPosition;
       
  4149 
       
  4150             break;
       
  4151         }
       
  4152         // EDrag
       
  4153         case TPointerEvent::EDrag:
       
  4154         {
       
  4155             TInt dragY = iStartPosition.iY - aPointerEvent.iPosition.iY;
       
  4156             TInt dragX = iStartPosition.iX - aPointerEvent.iPosition.iX;
       
  4157             iDisplayable.TryDetectLongTapL(aPointerEvent);
       
  4158 
       
  4159             // Override triggering of physicsScrolling in case of doing text painting in TextField-item
       
  4160             // or moving slider in Gauge-item.
       
  4161             if (!iPreventPhysicsScrolling && iPointedControl && iPointedControl->iMMidItem &&
       
  4162                     iPointedControl->iMMidItem->Type() == MMIDComponent::ETextField)
       
  4163             {
       
  4164                 if ((Abs(dragX) > iPhysics->DragThreshold()) && (Abs(dragY) < iPhysics->DragThreshold()))
       
  4165                 {
       
  4166                     iPreventPhysicsScrolling = ETrue;
       
  4167                 }
       
  4168             }
       
  4169 
       
  4170             // Check whether DragTreshold for panning is exceeded. If yes, then cancel timer and longtap.
       
  4171             if (!iPanningOngoing && Abs(dragY) > iPhysics->DragThreshold() && !iPreventPhysicsScrolling)
       
  4172             {
       
  4173                 iPanningOngoing = ETrue;
       
  4174                 iHighlightTimer->Cancel();
       
  4175                 iPhysics->SetPanningPosition(iLastDragPosition - aPointerEvent.iPosition);
       
  4176                 iLastDragPosition = aPointerEvent.iPosition;
       
  4177                 //Forward one drag event to the focused textField or Gauge when panning is triggered
       
  4178                 if ((iFocused != KErrNotFound)
       
  4179                         && IsTextFieldItem(ControlItem(iFocused)))
       
  4180                 {
       
  4181                     ControlItem(iFocused).HandlePointerEventL(aPointerEvent);
       
  4182                 }
       
  4183             }
       
  4184             // If panning is already ongoing. Update panning position. Also we redraw entire Form
       
  4185             // to prevent unexpected behavior(artifacts on the screen) during flick scrolling and
       
  4186             // to make scrolling smoother.
       
  4187             else if (iPanningOngoing)
       
  4188             {
       
  4189                 iPhysics->SetPanningPosition(iLastDragPosition - aPointerEvent.iPosition);
       
  4190                 iLastDragPosition = aPointerEvent.iPosition;
       
  4191                 DrawDeferred();
       
  4192             }
       
  4193             // If dragged outside of StringItem area or panning starts, then up event is sent to the item.
       
  4194             if (!iUpEventSent && iPointedControl && IsStringItem(*iPointedControl)  && (iPanningOngoing ||
       
  4195                     (iPointedControl && !iPointedControl->Rect().Contains(aPointerEvent.iPosition)))
       
  4196                )
       
  4197             {
       
  4198                 TPointerEvent pointerEvent = aPointerEvent;
       
  4199                 pointerEvent.iType = TPointerEvent::EButton1Up;
       
  4200                 ForwardPointerEventToItemL(pointerEvent);
       
  4201                 iPointedControl = ControlItemAtPoint(aPointerEvent.iPosition);
       
  4202                 iUpEventSent = ETrue;
       
  4203             }
       
  4204             // If physics scrolling is not ongoing forward event to the item.
       
  4205             else if (!iHighlightTimer->IsActive() && !PhysicsScrolling() &&
       
  4206                      (iPointedControl && iPointedControl->Rect().Contains(aPointerEvent.iPosition)))
       
  4207             {
       
  4208                 ForwardPointerEventToItemL(aPointerEvent);
       
  4209             }
       
  4210 #ifdef RD_JAVA_S60_RELEASE_9_2
       
  4211             // ChoiceGroup gets drag events while physics scrolling.
       
  4212             // Enables internal highlight disappearing when panning begins.
       
  4213             // We have control if there is any Item on Form.
       
  4214             else if (!iHighlightTimer->IsActive()
       
  4215                      && (iFocused > KErrNotFound)
       
  4216                      && IsChoiceGroup(ControlItem(iFocused))
       
  4217                      && PhysicsScrolling())
       
  4218             {
       
  4219                 ForwardPointerEventToItemL(aPointerEvent);
       
  4220             }
       
  4221 #endif // RD_JAVA_S60_RELEASE_9_2             
       
  4222             break;
       
  4223         }
       
  4224 
       
  4225         // EButton1Up
       
  4226         case TPointerEvent::EButton1Up:
       
  4227         {
       
  4228             TPoint distance = iStartPosition - aPointerEvent.iPosition;
       
  4229             if (Abs(distance.iY) > iPhysics->DragThreshold() && !iPreventPhysicsScrolling)
       
  4230             {
       
  4231                 iFlickOngoing = iPhysics->StartFlick(distance, iStartTime);
       
  4232                 if (!iUpEventSent)
       
  4233                 {
       
  4234                     ForwardPointerEventToItemL(aPointerEvent);
       
  4235                     iUpEventSent = ETrue;
       
  4236                 }
       
  4237             }
       
  4238             else
       
  4239             {
       
  4240                 if (!iUpEventSent)
       
  4241                 {
       
  4242                     ForwardPointerEventToItemL(aPointerEvent);
       
  4243                     iUpEventSent = ETrue;
       
  4244                 }
       
  4245             }
       
  4246             iPanningOngoing = EFalse;
       
  4247             iCanDragFocus = EFalse;
       
  4248             break;
       
  4249         }
       
  4250         default:
       
  4251         {
       
  4252             ForwardPointerEventToItemL(aPointerEvent);
       
  4253             break;
       
  4254         }
       
  4255         }
       
  4256     }
       
  4257     else
       
  4258     {
       
  4259         IgnoreEventsUntilNextPointerUp();
       
  4260         return;
       
  4261     }
       
  4262 }
       
  4263 
       
  4264 void CMIDForm::ForwardPointerEventToItemL(const TPointerEvent& aPointerEvent)
       
  4265 {
       
  4266     if (iPointedControl)
       
  4267     {
       
  4268         // Drag events are not forwarded to CustomItem
       
  4269         if (!iFlickStoppedOnDownEvent &&
       
  4270                 !(IsCustomItem(*iPointedControl) && aPointerEvent.iType == TPointerEvent::EDrag))
       
  4271         {
       
  4272             if (iFocused != KErrNotFound)
       
  4273             {
       
  4274                 ControlItem(iFocused).HandlePointerEventL(aPointerEvent);
       
  4275             }
       
  4276 
       
  4277             if (LayoutPending())
       
  4278             {
       
  4279                 LayoutFormL();
       
  4280                 DrawDeferred();
       
  4281             }
       
  4282         }
       
  4283 
       
  4284         if (aPointerEvent.iType == TPointerEvent::EButton1Up)
       
  4285         {
       
  4286             iFocusChangingWithPen = EFalse;
       
  4287         }
       
  4288     }
       
  4289 }
       
  4290 
       
  4291 void CMIDForm::HandlePhysicsScroll(TInt aScroll, TBool aDrawNow, TUint /*aFlags*/)
       
  4292 {
       
  4293 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  4294     //Dragging/flicking of Form content should give tactile feedback.
       
  4295     //This implementation is similar to native List: during dragging/flicking
       
  4296     //feedback is given when new item appears ont top/bottom of Form
       
  4297     //visible area.
       
  4298     //
       
  4299     //First we have to reset current visibility for all items in Form.
       
  4300     TInt count = iItems.Count();
       
  4301     for (TInt i=0; i<count; i++)
       
  4302     {
       
  4303         CMIDControlItem& ci = ControlItem(i);
       
  4304         ci.SetVisibilityInForm(RectPartiallyVisible(ci.Rect()));
       
  4305     }
       
  4306 #endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  4307 
       
  4308     iScroll = iScroll + aScroll;
       
  4309     if (aScroll)
       
  4310     {
       
  4311         iHasScrolled = ETrue;
       
  4312     }
       
  4313     iScrollDelta = aScroll;
       
  4314     SetRowPositionsWithRespectToScrolledLocation();
       
  4315 
       
  4316     if (aDrawNow)
       
  4317     {
       
  4318         RawScrollFinalize(ETrue, ETrue);
       
  4319         DrawNow();
       
  4320     }
       
  4321     else
       
  4322     {
       
  4323         RawScrollFinalize(ETrue, EFalse);
       
  4324     }
       
  4325 
       
  4326 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  4327     //Tactile feedback on dragging/flicking.
       
  4328     if (aScroll > 0)
       
  4329     {
       
  4330         //scrolling up (pointer dragged down)
       
  4331         DoFeedbackOnDraggingUp();
       
  4332     }
       
  4333     if (aScroll < 0)
       
  4334     {
       
  4335         //scrolling down (pointer dragged up)
       
  4336         DoFeedbackOnDraggingDown();
       
  4337     }
       
  4338 #endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  4339 }
       
  4340 
       
  4341 void CMIDForm::PhysicsScrollingEnd()
       
  4342 {
       
  4343     iFlickOngoing = EFalse;
       
  4344     iPanningOngoing = EFalse;
       
  4345 }
       
  4346 
       
  4347 TBool CMIDForm::PhysicsEnabled()
       
  4348 {
       
  4349     if (iPhysics)
       
  4350     {
       
  4351         return ETrue;
       
  4352     }
       
  4353     else
       
  4354     {
       
  4355         return EFalse;
       
  4356     }
       
  4357 }
       
  4358 
       
  4359 TBool CMIDForm::PhysicsScrolling()
       
  4360 {
       
  4361     return iFlickOngoing | iPanningOngoing;
       
  4362 }
       
  4363 
       
  4364 TInt CMIDForm::ScrollDelta()
       
  4365 {
       
  4366     return iScrollDelta;
       
  4367 }
       
  4368 
       
  4369 void CMIDForm::DoFeedbackOnFocusChange(CMIDControlItem& aControlItem)
       
  4370 {
       
  4371     //Tapping on StringItem BUTTON should not do feedback, here.
       
  4372     //Native class CAknButton does it by itself
       
  4373     if (!IsStringItemButton(aControlItem))
       
  4374     {
       
  4375         //Other items should do some feedback
       
  4376 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  4377         if (IsStringItemHyperlink(aControlItem))
       
  4378         {
       
  4379             //if StringItem is HYPERLIK it should give sensitive button feedback
       
  4380             iFeedback->InstantFeedback(ETouchFeedbackSensitiveButton);
       
  4381         }
       
  4382         else if (IsImageItem(aControlItem))
       
  4383         {
       
  4384             //if pointed control is ImageItem, its focusable, it has to be either
       
  4385             //HYPERLIK ot BUTTON, so it should give sensitive button feedback
       
  4386             iFeedback->InstantFeedback(ETouchFeedbackSensitiveButton);
       
  4387         }
       
  4388         else if (IsChoiceGroup(aControlItem))
       
  4389         {
       
  4390             //tapping on unfocused ChoiceGroup makes also activation, so it should
       
  4391             //give basic list feedback
       
  4392             iFeedback->InstantFeedback(ETouchFeedbackList);
       
  4393         }
       
  4394         else
       
  4395         {
       
  4396             //changing focus to other items should give sensitive list feedback
       
  4397             iFeedback->InstantFeedback(ETouchFeedbackSensitiveList);
       
  4398         }
       
  4399 #else
       
  4400         iFeedback->InstantFeedback(ETouchFeedbackBasic);
       
  4401 #endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK                
       
  4402     }
       
  4403 }
       
  4404 
       
  4405 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  4406 void CMIDForm::DoFeedbackOnDraggingUp()
       
  4407 {
       
  4408     TInt count = iItems.Count();
       
  4409     //If dragging/flicking reaches the first/last item in Form,
       
  4410     //tactile feedback shouldn't be given. There should be only
       
  4411     //'bounce' effect, when first/last item goes back to to/bottom
       
  4412     //of screen. Flag firstOrLastItemReached determines this case.
       
  4413     //NOTE: feedback for 'bounce' is implemented in CAknPhysics.
       
  4414     TBool firstOrLastItemReached = EFalse;
       
  4415     for (TInt i = 0; i < count; i++)
       
  4416     {
       
  4417         //Try find first item from top, which changed its visibility
       
  4418         CMIDControlItem& ci = ControlItem(i);
       
  4419         CMIDControlItem& last = ControlItem(count-1);
       
  4420         TBool visibility = RectPartiallyVisible(ci.Rect());
       
  4421         //In case of 'bounce' effect, there shouldn't be any feedback
       
  4422         //on dragging/flicking (as in native side):
       
  4423         if (RectFullyVisible(last.Rect()))
       
  4424         {
       
  4425             firstOrLastItemReached = ETrue;
       
  4426         }
       
  4427         if (i == 0 && RectFullyVisible(ci.Rect()))
       
  4428         {
       
  4429             firstOrLastItemReached = ETrue;
       
  4430         }
       
  4431         if (ci.GetVisibilityInForm() != visibility)
       
  4432         {
       
  4433             //item changed its visibility form invisible to visible
       
  4434             if (visibility && !firstOrLastItemReached)
       
  4435             {
       
  4436                 //if there isn't 'bounce' effect, do feedback
       
  4437                 iFeedback->InstantFeedback(ETouchFeedbackSensitiveList);
       
  4438                 break;
       
  4439             }
       
  4440         }
       
  4441     }
       
  4442 }
       
  4443 
       
  4444 void CMIDForm::DoFeedbackOnDraggingDown()
       
  4445 {
       
  4446     TInt count = iItems.Count();
       
  4447     //If dragging/flicking reaches the first/last item in Form,
       
  4448     //tactile feedback shouldn't be given. There should be only
       
  4449     //'bounce' effect, when first/last item goes back to to/bottom
       
  4450     //of screen. Flag firstOrLastItemReached determines this case.
       
  4451     //NOTE: feedback for 'bounce' is implemented in CAknPhysics.
       
  4452     TBool firstOrLastItemReached = EFalse;
       
  4453     for (TInt i = count-1; i >= 0; i--)
       
  4454     {
       
  4455         CMIDControlItem& ci = ControlItem(i);
       
  4456         CMIDControlItem& first = ControlItem(0);
       
  4457         TBool visibility = RectPartiallyVisible(ci.Rect());
       
  4458         if (RectFullyVisible(first.Rect()))
       
  4459         {
       
  4460             firstOrLastItemReached = ETrue;
       
  4461         }
       
  4462         if (i == count-1 && RectFullyVisible(ci.Rect()))
       
  4463         {
       
  4464             firstOrLastItemReached = ETrue;
       
  4465         }
       
  4466         if (ci.GetVisibilityInForm() != visibility)
       
  4467         {
       
  4468             //item changed its visibility form invisible to visible
       
  4469             if (visibility && !firstOrLastItemReached)
       
  4470             {
       
  4471                 iFeedback->InstantFeedback(ETouchFeedbackSensitiveList);
       
  4472                 break;
       
  4473             }
       
  4474         }
       
  4475     }
       
  4476 }
       
  4477 #endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK