javauis/lcdui_akn/lcdui/src/CMIDChoiceGroupControl.cpp
branchRCL_3
changeset 66 2455ef1f5bbc
child 77 7cee158cb8cd
equal deleted inserted replaced
65:ae942d28ec0e 66:2455ef1f5bbc
       
     1 /*
       
     2 * Copyright (c) 2003-2006 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:  The CMIDChoiceGroup control container. Owns and manipulates
       
    15 *                the choicegroup model and creates / deletes the actual
       
    16 *                control as needed.
       
    17 *
       
    18 */
       
    19 
       
    20 
       
    21 #include <e32def.h>
       
    22 #include <e32err.h>
       
    23 #include <w32std.h>
       
    24 #include <gdi.h>
       
    25 #include <gulutil.h>
       
    26 
       
    27 #include <eiktxlbm.h>
       
    28 // CColumnListBoxData API
       
    29 #include <eikclbd.h>
       
    30 
       
    31 #include <aknenv.h>
       
    32 #include <aknconsts.h>
       
    33 #include <avkon.mbg>
       
    34 #include <aknPopup.h>
       
    35 #include <AknLayoutDef.h>
       
    36 #include <AknBidiTextUtils.h>
       
    37 #include <gulcolor.h>
       
    38 
       
    39 #include <skinlayout.cdl.h>
       
    40 #include <AknLayoutFont.h>
       
    41 #include <aknlayoutscalable_avkon.cdl.h> // LAF
       
    42 #include <AknsDrawUtils.h>// skin
       
    43 #include <AknsBasicBackgroundControlContext.h> //skin
       
    44 
       
    45 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
    46 #include <akntranseffect.h>
       
    47 #include <akntransitionutils.h>
       
    48 #endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
    49 
       
    50 // using MMIDBitmapImage API in NewElement and SetElement functions - setting icon to element
       
    51 #include <lcdgr.h>
       
    52 // macros definitions for resources
       
    53 #include <lcdui.rsg>
       
    54 #ifndef RD_SCALABLE_UI_V2
       
    55 #include "CMIDForm.h"
       
    56 #endif
       
    57 
       
    58 // API used in HandlePointerEventL function
       
    59 #include "CMIDDisplayable.h"
       
    60 
       
    61 #include "CMIDFont.h"
       
    62 // using CMIDUtils::CopyBitmapL in NewElement and SetElement functions - setting icon to element
       
    63 #include "CMIDUtils.h"
       
    64 #include "CMIDChoiceGroupControl.h"
       
    65 // needed for CMIDChoiceGroupItem API in several places
       
    66 #include "CMIDChoiceGroupItem.h"
       
    67 // using SetTitleL in DoPopupL function - setting popup title
       
    68 #include "CMIDItemLabel.h"
       
    69 // using GetPopupNoteController in ShowInfoPopup function - showing popup with text
       
    70 #include "CMIDPopupNoteController.h"
       
    71 
       
    72 
       
    73 #include <j2me/jdebug.h>
       
    74 
       
    75 // For disabling transition effects
       
    76 #include <aknlistloadertfx.h>
       
    77 #include <aknlistboxtfx.h>
       
    78 
       
    79 
       
    80 /** This macro is executed each time a trapped call returns an error code different than KErrNone */
       
    81 #undef  TRAP_INSTRUMENTATION_LEAVE
       
    82 #define TRAP_INSTRUMENTATION_LEAVE(aResult) DEBUG_INT2("In CMIDChoiceGroupControl.cpp, trapped method was called at line %D and got exception %D", __LINE__, aResult);
       
    83 
       
    84 
       
    85 // Constant used for calculation of ChoiceGroup, which is not in Form yet
       
    86 // (from eiklbx.cpp)
       
    87 const TInt KEikListBoxItemVGap = 6;
       
    88 
       
    89 
       
    90 CMIDChoiceGroupPopupList* CMIDChoiceGroupPopupList::NewL(CEikListBox* aListBox, TInt aCbaResource,
       
    91         AknPopupLayouts::TAknPopupLayouts aType)
       
    92 {
       
    93     CMIDChoiceGroupPopupList* self = new(ELeave) CMIDChoiceGroupPopupList;
       
    94     CleanupStack::PushL(self);
       
    95     self->ConstructL(aListBox, aCbaResource, aType);
       
    96     CleanupStack::Pop(self);
       
    97     return self;
       
    98 }
       
    99 
       
   100 CMIDChoiceGroupPopupList::~CMIDChoiceGroupPopupList()
       
   101 {
       
   102 }
       
   103 
       
   104 void CMIDChoiceGroupPopupList::ResizeList()
       
   105 {
       
   106     CAknPopupList::SetupWindowLayout(AknPopupLayouts::EMenuUnknownColumnWindow);
       
   107 }
       
   108 
       
   109 #ifdef RD_SCALABLE_UI_V2
       
   110 void CMIDChoiceGroupPopupList::HandlePointerEventL(const TPointerEvent& aPointerEvent)
       
   111 {
       
   112     if (aPointerEvent.iType == TPointerEvent::EButton1Down &&
       
   113             !Rect().Contains(aPointerEvent.iPosition))
       
   114     {
       
   115         AttemptExitL(EFalse);
       
   116     }
       
   117     else
       
   118     {
       
   119         CAknPopupList::HandlePointerEventL(aPointerEvent);
       
   120     }
       
   121 }
       
   122 #endif //RD_SCALABLE_UI_V2
       
   123 
       
   124 CMIDChoiceGroupPopupList::CMIDChoiceGroupPopupList()
       
   125 {
       
   126 }
       
   127 
       
   128 CMIDChoiceGroupControl::CMIDChoiceGroupControl(
       
   129     MMIDChoiceGroup::TChoiceType aType,
       
   130     CMIDChoiceGroupItem* aItem)
       
   131         : iType(aType),
       
   132         iItem(aItem)
       
   133 {
       
   134 }
       
   135 
       
   136 
       
   137 CMIDChoiceGroupControl::~CMIDChoiceGroupControl()
       
   138 {
       
   139     // Do not allow the listbox data to delete the icon
       
   140     // array. It will be deleted by the model.
       
   141     DeleteListBox(iListBox);
       
   142 
       
   143     // No need to delete iPopupList here. The popup list is created and deleted in DoPopupL().
       
   144     delete iModel;
       
   145 }
       
   146 
       
   147 
       
   148 // Constructs the model and adds any given elements into it.
       
   149 // NOTE that the actual control is not yet created, it comes
       
   150 // to life when the item is added to a form (that has a window
       
   151 // for the control to draw in). Constructing and storing the model
       
   152 // outside the actual control enables elements to be manipulated
       
   153 // (in Java code) even when the ChoiceGroup is not (yet) added to a form.
       
   154 void CMIDChoiceGroupControl::ConstructL(
       
   155     RArray<TPtrC>& aStringArray,
       
   156     RArray<MMIDImage*>& aImageArray)
       
   157 {
       
   158     // Create the listbox model
       
   159     iModel = new(ELeave) CMIDChoiceGroupModel(iType);
       
   160     iModel->ConstructL(iEikonEnv);
       
   161 
       
   162     // Start observing model events
       
   163     iModel->SetObserver(this);
       
   164 
       
   165     // Stuff any given arrays in the model
       
   166     PopulateModelL(aStringArray, aImageArray);
       
   167 
       
   168     UpdateMargins();
       
   169 
       
   170     SetComponentsToInheritVisibility(ETrue);
       
   171 
       
   172 #ifdef RD_SCALABLE_UI_V2
       
   173     SetAllowStrayPointers();
       
   174 #endif
       
   175 
       
   176 #ifdef RD_TACTILE_FEEDBACK
       
   177     iFeedback = MTouchFeedback::Instance();
       
   178     // Disabling default tactile feedback to prevent a 'double feedback' while tapping on focused item
       
   179     iFeedback->EnableFeedbackForControl(this, FALSE);
       
   180 #endif
       
   181 
       
   182 }
       
   183 
       
   184 
       
   185 // Creates the actual choicegroup control, sets all kinds of
       
   186 // properties and associates the model with the created control
       
   187 void CMIDChoiceGroupControl::CreateControlL(
       
   188     const CCoeControl* aParent,
       
   189     const TRect& aRect)
       
   190 {
       
   191     // Model should be created before the control (this is true for
       
   192     // popup as well)
       
   193     ASSERT(iModel);
       
   194 
       
   195     // In dynamic resolution case store the current item index, so that it can be
       
   196     // restored once the listbox is recreated
       
   197     TInt currentItem = KErrNotFound;
       
   198     if (iListBox)
       
   199     {
       
   200         currentItem = iListBox->View()->CurrentItemIndex();
       
   201     }
       
   202 
       
   203     DeleteControl();
       
   204     ASSERT(!iListBox);
       
   205 
       
   206     // Set parent to the existing (form) window and use the rect given
       
   207     SetContainerWindowL(*aParent);
       
   208     SetRect(aRect);
       
   209 
       
   210     UpdateMargins();
       
   211 
       
   212     // If this is a popup, there's nothing to else create really
       
   213     if (IsPopup())
       
   214     {
       
   215         return;
       
   216     }
       
   217 
       
   218     //in case skin or resolution has changed
       
   219     iModel->ReConstructSelectionIconsL();
       
   220     iModel->UpdateIconArrayL();
       
   221 
       
   222     iListBox = CreateListBoxL(aParent);
       
   223 
       
   224     // Disable transition effects for iListBox, this is needed to get
       
   225     // rid of artifacts caused by transition effects when list box controls
       
   226     // are scrolled up/down.
       
   227     CWindowGc* gc = iListBox->View()->ItemDrawer()->Gc();
       
   228     MAknListBoxTfx* transApi = CAknListLoader::TfxApi(gc);
       
   229     if (transApi)
       
   230     {
       
   231         transApi->EnableEffects(EFalse);
       
   232     }
       
   233 
       
   234     // setup listbox
       
   235     iListBox->SetListBoxObserver(this);
       
   236     iListBox->SetRect(ListBoxRect(Rect()));
       
   237 
       
   238     if (currentItem != KErrNotFound)
       
   239     {
       
   240         iListBox->View()->SetCurrentItemIndex(currentItem);
       
   241     }
       
   242 
       
   243     // Ready to draw
       
   244     ActivateL();
       
   245 }
       
   246 
       
   247 
       
   248 // Deletes the actual listbox control (when item is removed from a form)
       
   249 // and disassociates the model from the control.
       
   250 // Maintains the model so that elements can be accessed even
       
   251 // if the item is not attached to a form
       
   252 void CMIDChoiceGroupControl::DeleteControl()
       
   253 {
       
   254     ClosePopup();
       
   255 
       
   256     // Gets rid of the listbox when choicegroup is removed from
       
   257     // a form, but does not yet kill the model (ie elements that
       
   258     // may have been added)
       
   259     DeleteListBox(iListBox);
       
   260 
       
   261     // Set to null, otherwise destructor will double-delete
       
   262     iListBox = NULL;
       
   263 }
       
   264 
       
   265 
       
   266 void CMIDChoiceGroupControl::HiliteFirstElement(TBool aEnableHighlight)
       
   267 {
       
   268     if (iListBox)
       
   269     {
       
   270         iListBox->View()->SetCurrentItemIndex(0);
       
   271         EnableListHighlight(aEnableHighlight);
       
   272     }
       
   273 }
       
   274 
       
   275 void CMIDChoiceGroupControl::HiliteLastElement(TBool aEnableHighlight)
       
   276 {
       
   277     if (iListBox)
       
   278     {
       
   279         iListBox->View()->SetCurrentItemIndex(iListBox->View()->BottomItemIndex());
       
   280         EnableListHighlight(aEnableHighlight);
       
   281     }
       
   282 }
       
   283 
       
   284 void CMIDChoiceGroupControl::EnableListHighlight(TBool aEnable)
       
   285 {
       
   286     if (iListBox)
       
   287     {
       
   288         CListItemDrawer* drawer = iListBox->View()->ItemDrawer();
       
   289 
       
   290         if (aEnable)
       
   291         {
       
   292             drawer->ClearFlags(CListItemDrawer::EDisableHighlight);
       
   293         }
       
   294         else
       
   295         {
       
   296             drawer->SetFlags(CListItemDrawer::EDisableHighlight);
       
   297 
       
   298 #ifdef RD_SCALABLE_UI_V2
       
   299             // If the focus is dragged to another form item, the highlight is
       
   300             // disabled in this cg. Set the flag to true to be sure that selection is not
       
   301             // changed if the pointer up happens on same cg element where the drag started.
       
   302             iPointerDragHasStarted = ETrue;
       
   303 #endif
       
   304         }
       
   305 
       
   306         TRAP_IGNORE(iListBox->View()->UpdateSelectionL(CListBoxView::ESingleSelection));
       
   307     }
       
   308 }
       
   309 
       
   310 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   311 /**
       
   312  * Fuction sets ESingleClickDisabledHighlight - item drawer flags
       
   313  * and reports current highlight element change event
       
   314  */
       
   315 void CMIDChoiceGroupControl::SingleClickDisableHighlightL(TBool aDisable)
       
   316 {
       
   317     // Highlight should be disabled when listbox element taped
       
   318     if (iListBox)
       
   319     {
       
   320         iListBox->SingleClickDisableHighlightL(aDisable);
       
   321     }
       
   322 }
       
   323 #endif
       
   324 
       
   325 // msk
       
   326 void CMIDChoiceGroupControl::CurrentItemChanged()
       
   327 {
       
   328     if (iItem)
       
   329     {
       
   330         // delegate the information to the item; commands may need to be updated
       
   331         iItem->UpdateCommands();
       
   332     }
       
   333     // redraw
       
   334     DrawNow();
       
   335 }
       
   336 
       
   337 // msk
       
   338 TBool CMIDChoiceGroupControl::IsCurrentItemSelected()
       
   339 {
       
   340     if (iListBox)
       
   341     {
       
   342         return IsSelected(iListBox->View()->CurrentItemIndex());
       
   343     }
       
   344 
       
   345     return EFalse;
       
   346 }
       
   347 
       
   348 // msk
       
   349 // Posts always the java event
       
   350 void CMIDChoiceGroupControl::ToggleCurrentItemSelectionL()
       
   351 {
       
   352     if (iListBox)
       
   353     {
       
   354         // SelectElementL must not be called if the unselection of the selected element is
       
   355         // attempted in exclusive choice group because it would cause the itemStateChanged event.
       
   356         if (iType != MMIDChoiceGroup::EExclusive || !IsCurrentItemSelected())
       
   357         {
       
   358 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   359             if (Form() && !Form()->PhysicsScrolling())
       
   360             {
       
   361 #endif // RD_JAVA_S60_RELEASE_9_2             
       
   362                 TInt currentIndex = iListBox->View()->CurrentItemIndex();
       
   363                 SelectElementL(currentIndex, !IsSelected(currentIndex), ETrue);
       
   364 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   365             }
       
   366 #endif // RD_JAVA_S60_RELEASE_9_2
       
   367         }
       
   368     }
       
   369 }
       
   370 
       
   371 // returns the numbers of elements in this choice group
       
   372 TInt CMIDChoiceGroupControl::NumberOfElements() const
       
   373 {
       
   374     ASSERT(iModel);
       
   375     return iModel->NumberOfItems();
       
   376 }
       
   377 
       
   378 // --- CMIDChoiceGroupItem delegated methods (java Choice interface)
       
   379 
       
   380 
       
   381 // Inserts a new element in the choice
       
   382 void CMIDChoiceGroupControl::InsertElementL(TInt aIndex, const TDesC& aText, MMIDImage* aImage)
       
   383 {
       
   384     ASSERT(iModel);
       
   385 
       
   386     CMIDChoiceGroupElement* pElement = NewElementLC(aText, aImage);
       
   387 
       
   388     // Reserve space for the new element
       
   389     iModel->SetReserveL(iModel->NumberOfItems() + 1);
       
   390 
       
   391     // Stuff it in
       
   392     iModel->InsertElementL(aIndex, pElement);
       
   393 
       
   394     CListBoxView* view = NULL;
       
   395 
       
   396     if (iListBox)
       
   397     {
       
   398         view = iListBox->View();
       
   399     }
       
   400     else if (iPopupList)
       
   401     {
       
   402         view = iPopupList->ListBox()->View();
       
   403     }
       
   404 
       
   405     if (view)
       
   406     {
       
   407         TInt current = view->CurrentItemIndex();
       
   408 
       
   409         if (current >= aIndex && current < (iModel->NumberOfItems() - 1))
       
   410         {
       
   411             // If element was inserted before the highlighted element,
       
   412             // move the highlight so that it stays in the same element
       
   413             // as before insertion.
       
   414             view->SetCurrentItemIndex(++current);
       
   415         }
       
   416     }
       
   417 
       
   418     CleanupStack::Pop(pElement);
       
   419 }
       
   420 
       
   421 
       
   422 // Deletes an element from the choice
       
   423 void CMIDChoiceGroupControl::DeleteElementL(TInt aIndex)
       
   424 {
       
   425     ASSERT(iModel);
       
   426     TInt current = 0;
       
   427     if (iListBox)
       
   428     {
       
   429         current = iListBox->View()->CurrentItemIndex();
       
   430     }
       
   431     iModel->DeleteElementL(aIndex);
       
   432 
       
   433     if (iListBox && current != KErrNotFound &&
       
   434             iModel->NumberOfItems() > 0 &&
       
   435             aIndex <= current)
       
   436     {
       
   437         if (current < iModel->NumberOfItems())
       
   438         {
       
   439             if (current > 0 && aIndex < current)
       
   440             {
       
   441                 // Element was deleted before the current item, decrease
       
   442                 // current so that highlight stays in the same element
       
   443                 // as before the deletion
       
   444                 --current;
       
   445             }
       
   446             iListBox->SetCurrentItemIndex(current);
       
   447         }
       
   448         else
       
   449         {
       
   450             iListBox->SetCurrentItemIndex(iModel->NumberOfItems()-1);
       
   451         }
       
   452     }
       
   453 
       
   454 }
       
   455 
       
   456 
       
   457 // Deletes all elements
       
   458 void CMIDChoiceGroupControl::DeleteAllL()
       
   459 {
       
   460     ASSERT(iModel);
       
   461     if (iListBox)
       
   462     {
       
   463         iListBox->SetCurrentItemIndex(0);
       
   464     }
       
   465     iModel->DeleteAllL();
       
   466 }
       
   467 
       
   468 
       
   469 // Sets properties of element at <aIndex>
       
   470 void CMIDChoiceGroupControl::SetElementL(TInt aIndex, const TDesC& aText, MMIDImage* aImage)
       
   471 {
       
   472     ASSERT(iModel);
       
   473 
       
   474     if (aImage)
       
   475     {
       
   476         MMIDBitmapImage* bitmapImage = aImage->BitmapImage();
       
   477 
       
   478         CFbsBitmap* bitmap = CMIDUtils::CopyBitmapL(bitmapImage->ColorBitmap());
       
   479         CleanupStack::PushL(bitmap);
       
   480 
       
   481         CFbsBitmap* mask = NULL;
       
   482         if (bitmapImage->AlphaBitmap())
       
   483         {
       
   484             TDisplayMode alphaDisplayMode = bitmapImage->AlphaBitmap()->DisplayMode();
       
   485             TBool invert = alphaDisplayMode == EGray2 ? ETrue : EFalse;
       
   486             mask = bitmapImage->CreateAlphaBitmapL(alphaDisplayMode, invert);
       
   487         }
       
   488 
       
   489         CleanupStack::PushL(mask);
       
   490 
       
   491         iModel->SetElementL(aIndex, aText, bitmap, mask);
       
   492 
       
   493         CleanupStack::Pop(mask);
       
   494         CleanupStack::Pop(bitmap);
       
   495 
       
   496         bitmapImage->RemoveRef();
       
   497     }
       
   498     else
       
   499     {
       
   500         iModel->SetElementL(aIndex, aText, NULL, NULL);
       
   501     }
       
   502 }
       
   503 
       
   504 
       
   505 // Sets selection state of element at <aIndex>
       
   506 // This method is also declared in MMIDChoiceGroup. It's implementation
       
   507 // in CMIDChoiceGroupItem just simply calls this method.
       
   508 void CMIDChoiceGroupControl::SelectElementL(TInt aIndex, TBool aSelected)
       
   509 {
       
   510     SelectElementL(aIndex, aSelected, EFalse);
       
   511 }
       
   512 
       
   513 
       
   514 // Returns selection state of element at <aIndex>
       
   515 TBool CMIDChoiceGroupControl::IsSelected(TInt aIndex)
       
   516 {
       
   517     ASSERT(iModel);
       
   518     CMIDChoiceGroupElement* pElement = iModel->ElementAt(aIndex);
       
   519 
       
   520     if (pElement)
       
   521     {
       
   522         return pElement->IsSelected();
       
   523     }
       
   524 
       
   525     return EFalse;
       
   526 }
       
   527 
       
   528 
       
   529 // Sets element text font
       
   530 void CMIDChoiceGroupControl::SetFontL(TInt /*aIndex*/, MMIDFont* /*aFont*/)
       
   531 {
       
   532     ASSERT(iModel);
       
   533 }
       
   534 
       
   535 
       
   536 // Sets element text fit policy
       
   537 void CMIDChoiceGroupControl::SetFitPolicyL(TInt /*aFitPolicy*/)
       
   538 {
       
   539     ASSERT(iModel);
       
   540 }
       
   541 
       
   542 
       
   543 // --- from MMIDChoiceGroupModelObserver ---
       
   544 
       
   545 // Called when the model has changed. Based on the change, will cause
       
   546 // just a redraw of the control, or size recalculation
       
   547 void CMIDChoiceGroupControl::HandleChoiceGroupModelEventL(
       
   548     CMIDChoiceGroupModel* aModel,
       
   549     TChoiceGroupModelEvent aEvent)
       
   550 {
       
   551     ASSERT(iModel);
       
   552 
       
   553     // If not from our model, ignore
       
   554     if (aModel != iModel)
       
   555     {
       
   556         return;
       
   557     }
       
   558 
       
   559     // Assume everything needs to be done (makes the switch shorter)
       
   560     TBool bRedraw = ETrue;
       
   561     TBool bResize = ETrue;
       
   562 
       
   563     // Act upon the event, resize and redraw control as necessary
       
   564     switch (aEvent)
       
   565     {
       
   566     case EElementAdded:
       
   567         if (iListBox)
       
   568         {
       
   569             iListBox->HandleItemAdditionL();
       
   570         }
       
   571         break;
       
   572     case EElementDeleted:
       
   573         if (iListBox)
       
   574         {
       
   575             iListBox->HandleItemRemovalL();
       
   576         }
       
   577         break;
       
   578     case EUpdateEnded:
       
   579         if (iListBox)
       
   580         {
       
   581             iListBox->Reset();
       
   582         }
       
   583         break;
       
   584     case EElementModified:
       
   585         // after the LAF changes the icon column is dynamic, so redo the setup for the listbox
       
   586         // the columns by calling SizeChanged(). bResize is set to false because the relayout of
       
   587         // of the whole form is not needed.
       
   588         SizeChanged();
       
   589         bResize = EFalse;
       
   590         break;
       
   591     case EElementSelected:
       
   592         // Just a redraw will do
       
   593         bResize = EFalse;
       
   594         break;
       
   595     case EUpdateStarted:
       
   596     default:
       
   597         // No redraw, no resize. Do nothing.
       
   598         bRedraw = EFalse;
       
   599         bResize = EFalse;
       
   600         break;
       
   601     }
       
   602 
       
   603     // If popup is opened, it is handled separately
       
   604     if (iPopupList)
       
   605     {
       
   606         UpdatePopupListAppearanceL(aEvent);
       
   607     }
       
   608 
       
   609     // Reporting ESizeChanged event to iItem is not needed since the request
       
   610     // to update the form comes from java side (CMIDForm::RefreshItem(TInt) is called)
       
   611     // when items are added to or removed from choice group. See ChoiceGroup.java.
       
   612     // Redraw if needed and size has not changed, size change will
       
   613     // cause a form layout and redraw anyway.
       
   614     if (bRedraw && !bResize)
       
   615     {
       
   616         // Do safe redraw
       
   617         if (!IsPopup() && iListBox && iListBox->DrawableWindow())
       
   618         {
       
   619             iListBox->DrawDeferred();
       
   620         }
       
   621         else
       
   622         {
       
   623             // Seems to be a popup - redraw myself
       
   624             if (DrawableWindow())
       
   625             {
       
   626                 DrawDeferred();
       
   627             }
       
   628         }
       
   629     }
       
   630 }
       
   631 
       
   632 
       
   633 // --- from MEikListBoxObserver ---
       
   634 // Handles choice listbox events (as in selection)
       
   635 void CMIDChoiceGroupControl::HandleListBoxEventL(CEikListBox* aControl, TListBoxEvent aEventType)
       
   636 {
       
   637     if (aControl != iListBox)
       
   638     {
       
   639         return;
       
   640     }
       
   641 
       
   642     ASSERT(iModel);
       
   643 
       
   644     switch (aEventType)
       
   645     {
       
   646         // These should all cause a selection change
       
   647     case MEikListBoxObserver::EEventEnterKeyPressed:
       
   648     case MEikListBoxObserver::EEventItemActioned:
       
   649         ToggleCurrentItemSelectionL();
       
   650         break;
       
   651 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   652     case MEikListBoxObserver::EEventPenDownOnItem:
       
   653         if (iListBox)
       
   654         {
       
   655             iListBox->SetHighlight(EFalse);
       
   656         }
       
   657         break;
       
   658 #endif
       
   659 
       
   660     default:
       
   661         break;
       
   662     }
       
   663 }
       
   664 
       
   665 
       
   666 // Offers key events to the listbox, or handles popup events here
       
   667 TKeyResponse CMIDChoiceGroupControl::OfferKeyEventL(
       
   668     const TKeyEvent& aKeyEvent,
       
   669     TEventCode aType)
       
   670 {
       
   671     TKeyResponse resp = EKeyWasNotConsumed;
       
   672 
       
   673     // Pop popup if needed, otherwise do nothing (if popup)
       
   674     if (IsPopup())
       
   675     {
       
   676         if ((aKeyEvent.iCode == EKeyOK) || (aKeyEvent.iCode == EKeyEnter))
       
   677         {
       
   678             // It's a popup, and the OK key was pressed on it - start poppin'
       
   679             DoPopupL();
       
   680             resp = EKeyWasConsumed;
       
   681         }
       
   682 
       
   683         return resp;
       
   684     }
       
   685 
       
   686     // Not a popup then, handle some keys in clever ways
       
   687 
       
   688     // Save the currently selected item (if exclusive choice)
       
   689     TInt oldSelected = iModel->SelectedElement();
       
   690     TInt oldCurrentIndex = -1;
       
   691 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   692     TBool wasHighlighted = EFalse;
       
   693 #endif // RD_JAVA_S60_RELEASE_9_2
       
   694 
       
   695     if (iListBox)
       
   696     {
       
   697 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   698         wasHighlighted = iListBox->GetHighlight();
       
   699 #endif // RD_JAVA_S60_RELEASE_9_2
       
   700 
       
   701         oldCurrentIndex = iListBox->View()->CurrentItemIndex();
       
   702         // Let the listbox take a shot at the key
       
   703         resp = iListBox->OfferKeyEventL(aKeyEvent, aType);
       
   704 
       
   705 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   706         wasHighlighted = (iListBox->GetHighlight() && !wasHighlighted) ? EFalse : ETrue;
       
   707 #endif // RD_JAVA_S60_RELEASE_9_2
       
   708     }
       
   709 
       
   710     // If click (enter) on an already selected item in an exclusive choice,
       
   711     // do not consume the key. This allows the form to display a context menu.
       
   712     // Choicegroup element need to be focused and selected
       
   713     if ((iType == MMIDChoiceGroup::EExclusive) &&
       
   714             ((aKeyEvent.iCode == EKeyOK) || (aKeyEvent.iCode == EKeyEnter)) &&
       
   715             ((oldSelected != -1) || (oldSelected == -1 && oldCurrentIndex == -1)) &&
       
   716             (oldSelected == iModel->SelectedElement())
       
   717 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   718             && (wasHighlighted && iListBox->GetHighlight())
       
   719 #endif // RD_JAVA_S60_RELEASE_9_2
       
   720        )
       
   721     {
       
   722         // Do not consume the key, so that form can pop a menu
       
   723         CMIDDisplayable& displayable = iItem->Form()->CurrentDisplayable();
       
   724         TInt cntOpt = displayable.NumCommandsForOkOptionsMenu();
       
   725 
       
   726         // set first command from command list,
       
   727         // if command list <= 0 then command sets NULL
       
   728         const CMIDCommand* command = (iItem->CommandList()->Count() > 0 ?
       
   729                                       iItem->CommandList()->At(0).iCommand :
       
   730                                       NULL);
       
   731 
       
   732         // for default command will run ProcessCommandL( KItemCommandIdBase + 1 )
       
   733         if (iItem->DefaultCommand())
       
   734         {
       
   735             displayable.ProcessCommandL(iItem->CommandList()->CommandOffset() +
       
   736                                         iItem->CommandList()->FindCommandIndex(iItem->DefaultCommand()));
       
   737 
       
   738             resp =  EKeyWasConsumed;
       
   739         }
       
   740         else
       
   741         {
       
   742             TInt numScreenOrHelpCommands = displayable.NumCommandsForScreenOrHelpOptionsMenu();
       
   743 
       
   744             // if ( cntOpt > 1 ) will run menu, else execute ProcessCommandL( CommandOffset )
       
   745             if (cntOpt > 1)
       
   746             {
       
   747                 displayable.MenuHandler()->ShowMenuL(CMIDMenuHandler::EOkMenu);
       
   748                 resp = EKeyWasConsumed;
       
   749             }
       
   750             else if (cntOpt == 0 && numScreenOrHelpCommands > 1)
       
   751             {
       
   752                 // If there is more than one screen command on form
       
   753                 // and there is no ok/item commands then show menu
       
   754                 displayable.MenuHandler()->ShowMenuL(CMIDMenuHandler::EOptionsMenu);
       
   755                 resp = EKeyWasConsumed;
       
   756             }
       
   757             else if (command && command->CommandType() != MMIDCommand::EBack &&
       
   758                      command->CommandType() != MMIDCommand::ECancel)
       
   759             {
       
   760                 displayable.ProcessCommandL(iItem->CommandList()->CommandOffset());
       
   761                 resp =  EKeyWasConsumed;
       
   762             }
       
   763             else
       
   764             {
       
   765                 displayable.ProcessCommandL(displayable.MainCommandList()->CommandOffset());
       
   766                 resp =  EKeyWasConsumed;
       
   767             }
       
   768         }
       
   769     }
       
   770     // If the event caused current item change, and the new current item
       
   771     // is outside the visible area, should request the form to scroll a bit.
       
   772     // Current item has not changed, if the key was not consumed
       
   773     if (((aKeyEvent.iCode == EKeyUpArrow) ||
       
   774             (aKeyEvent.iCode == EKeyDownArrow)) &&
       
   775             (resp != EKeyWasNotConsumed))
       
   776     {
       
   777         // Calc scroll need and request one, if necessary
       
   778         RequestScrollIfNeededL();
       
   779     }
       
   780 
       
   781     if (iListBox && (oldCurrentIndex != iListBox->View()->CurrentItemIndex()))
       
   782     {
       
   783         CurrentItemChanged();
       
   784 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   785         ShowInfoPopup();
       
   786 #endif // RD_JAVA_S60_RELEASE_9_2        
       
   787     }
       
   788     return resp;
       
   789 }
       
   790 
       
   791 #ifdef RD_SCALABLE_UI_V2
       
   792 void CMIDChoiceGroupControl::HandlePointerEventL(const TPointerEvent& aPointerEvent)
       
   793 {
       
   794     if (!AknLayoutUtils::PenEnabled() || !iListBox)
       
   795     {
       
   796 
       
   797 #ifdef RD_TACTILE_FEEDBACK
       
   798         // this is to give tactile feedback when a POPUP type CG is focused
       
   799         // and user taps it to open the popup list
       
   800         // if focus is changing, tactile feedback is given already in Form
       
   801         if (IsPopup() &&
       
   802                 aPointerEvent.iType == TPointerEvent::EButton1Down &&
       
   803                 !iItem->Form()->IsFocusChangingWithPen())
       
   804         {
       
   805 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   806             iFeedback->InstantFeedback(ETouchFeedbackList);
       
   807 #else
       
   808             iFeedback->InstantFeedback(ETouchFeedbackBasic);
       
   809 #endif // RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   810         }
       
   811 #endif // RD_TACTILE_FEEDBACK
       
   812 
       
   813         return;
       
   814     }
       
   815 
       
   816     TInt nOldCurrent = iListBox->View()->CurrentItemIndex();
       
   817     TBool oldSelected = IsSelected(nOldCurrent);
       
   818 
       
   819     switch (aPointerEvent.iType)
       
   820     {
       
   821     case TPointerEvent::EDrag:
       
   822         // In order to enable highlight moving inside the choice group when the focus is dragged
       
   823         // on the form, forward drag events directly to listbox. This is needed beacuse it is not
       
   824         // always possible to set the wanted grabbing state for CMIDChoiceGroupListBox.
       
   825         // See also CCoeControl implementation of pointer event handling.
       
   826         iListBox->HandlePointerEventL(aPointerEvent);
       
   827         break;
       
   828     case TPointerEvent::EButtonRepeat:
       
   829         // EButtonRepeat events are requested by form. These events come only when pointer
       
   830         // is dragged out of main pane area.
       
   831         TimedScroll(aPointerEvent.iPosition.iY < 0 ? CMIDForm::EUp : CMIDForm::EDown);
       
   832         break;
       
   833     case TPointerEvent::EButton1Down:
       
   834     {
       
   835 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   836         // Hide pop-up note if visible.
       
   837         CMIDForm* form = iItem->Form();
       
   838         if (form)
       
   839         {
       
   840             form->GetPopupNoteController()->HidePopup();
       
   841         }
       
   842 #endif // RD_JAVA_S60_RELEASE_9_2
       
   843 
       
   844         iPointerDragHasStarted = EFalse;
       
   845 
       
   846 #ifdef RD_TACTILE_FEEDBACK
       
   847         // give tactile feedback here on ListBox only if it is already focused
       
   848         // if focus is changing, tactile feedback is given already in Form
       
   849         if (!iItem->Form()->IsFocusChangingWithPen())
       
   850         {
       
   851 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   852             iFeedback->InstantFeedback(ETouchFeedbackList);
       
   853 #else
       
   854             iFeedback->InstantFeedback(ETouchFeedbackBasic);
       
   855 #endif // RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   856         }
       
   857 #endif // RD_TACTILE_FEEDBACK
       
   858         CCoeControl::HandlePointerEventL(aPointerEvent);
       
   859 
       
   860         if (iListBox->Rect().Contains(aPointerEvent.iPosition) &&
       
   861                 !iItem->Form()->IsScrolledOnPointerDown())
       
   862         {
       
   863             TRect mainPane;
       
   864             AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, mainPane);
       
   865 
       
   866             TRect rect = iListBox->HighlightRect(); // highlight rect is in propotion to screen,
       
   867             rect.Move(0, -mainPane.iTl.iY);         // move it so that it's in propotion to main pane
       
   868 
       
   869             // Scroll the form so that highlighted list element becomes fully visible
       
   870             TInt scroll = 0;
       
   871             if (rect.iBr.iY > mainPane.Height())
       
   872             {
       
   873                 scroll = mainPane.Height() - rect.iBr.iY;
       
   874             }
       
   875             else if (rect.iTl.iY < 0)
       
   876             {
       
   877                 scroll = -rect.iTl.iY;
       
   878             }
       
   879 
       
   880             if (scroll != 0)
       
   881             {
       
   882                 ReportEventL(MMIDChoiceGroupControlObserver::EScrollRequest,
       
   883                              (TAny*)scroll);
       
   884             }
       
   885         }
       
   886         break;
       
   887     }
       
   888     case TPointerEvent::EButton1Up:
       
   889     {
       
   890 #ifdef RD_JAVA_S60_RELEASE_9_2
       
   891         // If up event comes when long tap has been detected, then
       
   892         // just forward the pointer event. In that case we do not
       
   893         // want to change selection, but update the listbox visually.
       
   894         // This is performed when pop-up menu is closed and we want to
       
   895         // hide listbox highlight.
       
   896         if (iItem->LongTapDetected())
       
   897         {
       
   898             CCoeControl::HandlePointerEventL(aPointerEvent);
       
   899             return;
       
   900         }
       
   901 #endif // RD_JAVA_S60_RELEASE_9_2
       
   902 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   903         switch (iType)
       
   904         {
       
   905         case MMIDChoiceGroup::EMultiple:
       
   906             iFeedback->InstantFeedback(ETouchFeedbackCheckbox);
       
   907             break;
       
   908         default:
       
   909             iFeedback->InstantFeedback(ETouchFeedbackList);
       
   910             break;
       
   911         }
       
   912 #endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
   913 
       
   914         CCoeControl::HandlePointerEventL(aPointerEvent);
       
   915 
       
   916         TInt idx;
       
   917 
       
   918         // Allow toggling the selection also in a case when form has been scrolled on pointer down event,
       
   919         // if the pointer up happens still on cg item area.
       
   920         TBool toggleAfterScroll = iItem->Form()->IsScrolledOnPointerDown() &&
       
   921                                   iItem->Rect().Contains(aPointerEvent.iPosition);
       
   922 
       
   923         if (!iPointerDragHasStarted &&
       
   924                 (iListBox->View()->XYPosToItemIndex(aPointerEvent.iPosition, idx) ||
       
   925                  toggleAfterScroll))
       
   926         {
       
   927             ToggleCurrentItemSelectionL();
       
   928         }
       
   929 
       
   930         // If selected item is tapped in the Exclusive ChoiceGroup
       
   931         // then possible default Command is executed.
       
   932         if (iItem->DefaultCommand() && !iItem->Form()->PhysicsScrolling())
       
   933         {
       
   934             if (iType == MMIDChoiceGroup::EExclusive && oldSelected
       
   935                     && !iFocusChangingWithPen && !iItem->Form()->IsFocusChangingWithPen())
       
   936             {
       
   937                 iItem->Form()->CurrentDisplayable().ProcessCommandL(iItem->DefaultCommand());
       
   938             }
       
   939         }
       
   940 
       
   941         iFocusChangingWithPen = EFalse;
       
   942         break;
       
   943     }
       
   944     default:
       
   945         CCoeControl::HandlePointerEventL(aPointerEvent);
       
   946         break;
       
   947     }
       
   948 
       
   949     // msk: notify if the current index has changed
       
   950     if (nOldCurrent != iListBox->View()->CurrentItemIndex())
       
   951     {
       
   952         iFocusChangingWithPen = ETrue;
       
   953         CurrentItemChanged();
       
   954         if (aPointerEvent.iType == TPointerEvent::EDrag)
       
   955         {
       
   956             iPointerDragHasStarted = ETrue;
       
   957         }
       
   958     }
       
   959 }
       
   960 
       
   961 #endif //RD_SCALABLE_UI_V2
       
   962 
       
   963 // Count component controls in this compound control
       
   964 TInt CMIDChoiceGroupControl::CountComponentControls() const
       
   965 {
       
   966     if (iListBox)
       
   967         return 1;
       
   968 
       
   969     return 0;
       
   970 }
       
   971 
       
   972 
       
   973 // Return requested component control
       
   974 CCoeControl* CMIDChoiceGroupControl::ComponentControl(TInt /*aIndex*/) const
       
   975 {
       
   976     return iListBox;
       
   977 }
       
   978 
       
   979 
       
   980 /** Called when the size adjustment need is detected, the item notified and
       
   981     the item caused the form to relayout. The form will calc the new
       
   982     position of the item and cause sizechanged to be called - this is
       
   983     this controls chance to update its position.
       
   984 
       
   985 */
       
   986 void CMIDChoiceGroupControl::SizeChanged()
       
   987 {
       
   988     if (iListBox)
       
   989     {
       
   990         iListBox->SetRect(ListBoxRect(Rect()));
       
   991         TRAP_IGNORE(SetupColumnsL(iListBox->ItemDrawer()->ColumnData()));
       
   992     }
       
   993 
       
   994     if (IsPopup())
       
   995     {
       
   996         TAknLayoutRect layoutRect; // used only temporarily for getting the layout for popup item's icons and text
       
   997 
       
   998         // Rect() includes also the margins so it cannot be used directly when layouting the popup icons and text.
       
   999         // popupRect is the rect that is available for the closed popup item (i.e. it does not include the margins).
       
  1000         // popupRect is used as a parent rect when updating the rects of the popup icons and text.
       
  1001         layoutRect.LayoutRect(Rect(),
       
  1002                               AknLayoutScalable_Avkon::form2_midp_field_choice_group_pane().LayoutLine());
       
  1003         TRect popupRect = layoutRect.Rect();
       
  1004 
       
  1005         // Layout for the element icon
       
  1006         layoutRect.LayoutRect(popupRect,
       
  1007                               AknLayoutScalable_Avkon::list_single_midp_graphic_pane_g4_cp(1).LayoutLine());
       
  1008         iPopupIconRect = layoutRect.Rect();
       
  1009 
       
  1010         // Layout for the text
       
  1011 
       
  1012         iPopupTextLayout.LayoutText(popupRect,
       
  1013                                     AknLayoutScalable_Avkon::list_single_midp_graphic_pane_t1_cp(1).LayoutLine());
       
  1014     }
       
  1015 }
       
  1016 
       
  1017 void CMIDChoiceGroupControl::PositionChanged()
       
  1018 {
       
  1019     if (IsPopup())
       
  1020     {
       
  1021         SizeChanged();
       
  1022     }
       
  1023 }
       
  1024 
       
  1025 // Calculates and returns the minimum size required by the control
       
  1026 // The size is based on the number of items in the listbox, so that
       
  1027 // the listbox does not need to be scrolled. In popup mode the height
       
  1028 // is fixed.
       
  1029 TSize CMIDChoiceGroupControl::MinimumSize() const
       
  1030 {
       
  1031     // Start with the current size
       
  1032     TSize size = Size();
       
  1033 
       
  1034     TInt height = 0;
       
  1035 
       
  1036     // Get height of list box, if not popup, and there is one
       
  1037     if (!IsPopup())
       
  1038     {
       
  1039         // Get current number of list box items.
       
  1040         TInt numberOfItems = iModel->NumberOfItems();
       
  1041 
       
  1042         if (iListBox)
       
  1043         {
       
  1044             // Use item count to calculate listbox height
       
  1045             height += iListBox->CalcHeightBasedOnNumOfItems(numberOfItems);
       
  1046         }
       
  1047         else
       
  1048         {
       
  1049             // If there is no iListBox, this cg is not added to form yet.
       
  1050             // In this case calculate the best estimate for the list box height
       
  1051             // here.
       
  1052             // Because none of layout seems to be suitable for this
       
  1053             // calculation, we have to do it in the same way as CEikLisBox
       
  1054             // (see CEikListBox::CalcHeightBasedOnNumOfItems in eiklbx.cpp).
       
  1055             height += (iEikonEnv->NormalFont()->HeightInPixels()
       
  1056                        + KEikListBoxItemVGap) * numberOfItems;
       
  1057         }
       
  1058 
       
  1059         height += (numberOfItems > 0)
       
  1060                   ? (iContentMargins.iTop + iContentMargins.iBottom)
       
  1061                   : iContentMargins.iBottom;
       
  1062     }
       
  1063     else // It is a popup
       
  1064     {
       
  1065         TAknLayoutRect layoutRect;
       
  1066         // layout in respect of the screen as only the height is needed
       
  1067         layoutRect.LayoutRect(iEikonEnv->ScreenDevice()->SizeInPixels(),
       
  1068                               AknLayoutScalable_Avkon::
       
  1069                               list_single_midp_graphic_pane_cp(1, 0).LayoutLine());
       
  1070         height += layoutRect.Rect().Height()
       
  1071                   + iContentMargins.iTop + iContentMargins.iBottom;
       
  1072     }
       
  1073 
       
  1074     // Adjust the size (height only) accordingly
       
  1075     size.iHeight = height;
       
  1076 
       
  1077     return size;
       
  1078 }
       
  1079 
       
  1080 void CMIDChoiceGroupControl::Draw(const TRect& /*aRect*/) const
       
  1081 {
       
  1082     if (IsPopup())
       
  1083     {
       
  1084         CMIDChoiceGroupElement* pElement = iModel->ElementAt(iModel->SelectedElement());
       
  1085 
       
  1086         if (pElement)
       
  1087         {
       
  1088             DrawIcon(pElement->Icon());
       
  1089             DrawText(pElement->Text());
       
  1090         }
       
  1091     }
       
  1092 }
       
  1093 
       
  1094 // Responds to focus change.
       
  1095 // From CCoeControl.
       
  1096 void CMIDChoiceGroupControl::FocusChanged(TDrawNow aDrawNow)
       
  1097 {
       
  1098     // call default CCoeControl's implementation
       
  1099     CCoeControl::FocusChanged(aDrawNow);
       
  1100 
       
  1101     // update focus state of listbox regarding to current focus state
       
  1102     if (iListBox)
       
  1103     {
       
  1104         iListBox->SetFocus(IsFocused(), aDrawNow);
       
  1105     }
       
  1106 }
       
  1107 
       
  1108 // Handles resource change.
       
  1109 // From CCoeControl.
       
  1110 void CMIDChoiceGroupControl::HandleResourceChange(TInt aType)
       
  1111 {
       
  1112     // call default CCoeControl's implementation
       
  1113     CCoeControl::HandleResourceChange(aType);
       
  1114 
       
  1115     // update listbox focus state when layout is switched
       
  1116     if (aType == KEikDynamicLayoutVariantSwitch && iListBox)
       
  1117     {
       
  1118         iListBox->SetFocus(IsFocused());
       
  1119     }
       
  1120 }
       
  1121 
       
  1122 TTypeUid::Ptr CMIDChoiceGroupControl::MopSupplyObject(TTypeUid aId)
       
  1123 {
       
  1124     return iItem->MopSupplyObject(aId);
       
  1125 }
       
  1126 
       
  1127 // Closes the popup if it is open
       
  1128 void CMIDChoiceGroupControl::ClosePopup()
       
  1129 {
       
  1130     if (iPopupList)
       
  1131     {
       
  1132         iPopupList->CancelPopup();
       
  1133     }
       
  1134 }
       
  1135 
       
  1136 // --- private functions ---
       
  1137 
       
  1138 // Draws an icon in the popup control using LAF as much as possible
       
  1139 void CMIDChoiceGroupControl::DrawIcon(CGulIcon* aIcon) const
       
  1140 {
       
  1141     // Sanity check
       
  1142     if (!aIcon)
       
  1143     {
       
  1144         return;
       
  1145     }
       
  1146 
       
  1147     // Extract parts - they're needed later anyway
       
  1148     CFbsBitmap* bmp = aIcon->Bitmap();
       
  1149     CFbsBitmap* mask = aIcon->Mask();
       
  1150 
       
  1151     CWindowGc& gc = SystemGc();
       
  1152     TRect iconRect = iPopupIconRect;
       
  1153 
       
  1154     // Draw the icon centered in its rect
       
  1155 
       
  1156     // Position in icon is (0,0), if the image fits. Else there's a
       
  1157     // need for a bit of recalc
       
  1158     TPoint posInIcon = TPoint(0, 0) + (bmp->SizeInPixels() - iconRect.Size());
       
  1159     posInIcon.iX /= 2;
       
  1160     posInIcon.iY /= 2;
       
  1161 
       
  1162     // If the thing is negative, the icon fits. Need to move the drawing
       
  1163     // rect a bit to make the icon draw in the middle
       
  1164     if (posInIcon.iX < 0)
       
  1165     {
       
  1166         // Shift right by amount left over
       
  1167         iconRect.iTl.iX -= posInIcon.iX;
       
  1168         posInIcon.iX = 0;
       
  1169     }
       
  1170 
       
  1171     if (posInIcon.iY < 0)
       
  1172     {
       
  1173         // Shift down by amount left over
       
  1174         iconRect.iTl.iY -= posInIcon.iY;
       
  1175         posInIcon.iY = 0;
       
  1176     }
       
  1177 
       
  1178     // Set the part of icon that is to be drawn
       
  1179     TRect drawRect(posInIcon, iconRect.Size());
       
  1180 
       
  1181     // Draw it
       
  1182     if (mask)
       
  1183     {
       
  1184         gc.BitBltMasked(iconRect.iTl, bmp, drawRect, mask, ETrue);
       
  1185     }
       
  1186     else
       
  1187     {
       
  1188         gc.BitBlt(iconRect.iTl, bmp, drawRect);
       
  1189     }
       
  1190 }
       
  1191 
       
  1192 
       
  1193 /** Draws the selected item text in the popup control */
       
  1194 void CMIDChoiceGroupControl::DrawText(const TDesC& aText) const
       
  1195 {
       
  1196     if (aText.Length())
       
  1197     {
       
  1198         // Get color from skin
       
  1199         TRgb rgb = AKN_LAF_COLOR(215);
       
  1200         TInt textColor;
       
  1201 
       
  1202         if (iItem && iItem->IsHighlighted())
       
  1203         {
       
  1204             textColor = EAknsCIQsnTextColorsCG8;
       
  1205         }
       
  1206         else
       
  1207         {
       
  1208             textColor = EAknsCIQsnTextColorsCG6;
       
  1209         }
       
  1210 
       
  1211         AknsUtils::GetCachedColor(AknsUtils::SkinInstance(),
       
  1212                                   rgb, KAknsIIDQsnTextColors, textColor);
       
  1213         iPopupTextLayout.DrawText(SystemGc(), aText, ETrue, rgb);
       
  1214     }
       
  1215 }
       
  1216 
       
  1217 
       
  1218 // Populates the listbox model from given arrays
       
  1219 void CMIDChoiceGroupControl::PopulateModelL(
       
  1220     RArray<TPtrC>& aStringArray,
       
  1221     RArray<MMIDImage*>& aImageArray)
       
  1222 {
       
  1223     if (!iModel)
       
  1224     {
       
  1225         // Should not happen.
       
  1226         ASSERT(EFalse);
       
  1227         return;
       
  1228     }
       
  1229 
       
  1230     // Begin model update. The model defers updating
       
  1231     // some of its internal stuff until EndUpdate()
       
  1232     iModel->BeginUpdate();
       
  1233 
       
  1234     // Loop through the string & image arrays and add elements,
       
  1235     // pass model from here so that it doesn't need to be retrieved
       
  1236     // from the box all the time
       
  1237     TInt nCount = aStringArray.Count();
       
  1238     for (TInt i = 0; i < nCount; i++)
       
  1239     {
       
  1240         iModel->AppendElementL(NewElementLC(aStringArray[i], aImageArray[i]));
       
  1241         CleanupStack::Pop();  // NewElementLC
       
  1242     }
       
  1243 
       
  1244     // End model update
       
  1245     iModel->EndUpdate();
       
  1246 }
       
  1247 
       
  1248 // Create a new element, initialise with string & image
       
  1249 CMIDChoiceGroupElement* CMIDChoiceGroupControl::NewElementLC(
       
  1250     const TDesC& aString, MMIDImage* aImage)
       
  1251 {
       
  1252     CMIDChoiceGroupElement* pElement = CMIDChoiceGroupElement::NewL();
       
  1253     CleanupStack::PushL(pElement);
       
  1254 
       
  1255     pElement->SetTextL(aString);
       
  1256 
       
  1257     if (aImage)
       
  1258     {
       
  1259         MMIDBitmapImage* bitmapImage = aImage->BitmapImage();
       
  1260 
       
  1261         CFbsBitmap* bitmap = CMIDUtils::CopyBitmapL(bitmapImage->ColorBitmap());
       
  1262         CleanupStack::PushL(bitmap);
       
  1263 
       
  1264         CFbsBitmap* mask = NULL;
       
  1265         if (bitmapImage->AlphaBitmap())
       
  1266         {
       
  1267             TDisplayMode alphaDisplayMode = bitmapImage->AlphaBitmap()->DisplayMode();
       
  1268             TBool invert = alphaDisplayMode == EGray2 ? ETrue : EFalse;
       
  1269             mask = bitmapImage->CreateAlphaBitmapL(alphaDisplayMode, invert);
       
  1270         }
       
  1271 
       
  1272         CleanupStack::PushL(mask);
       
  1273 
       
  1274         pElement->SetIconL(*bitmap, mask);
       
  1275         CleanupStack::Pop(mask);
       
  1276         CleanupStack::Pop(bitmap);
       
  1277 
       
  1278         bitmapImage->RemoveRef();
       
  1279     }
       
  1280 
       
  1281     return pElement;
       
  1282 }
       
  1283 
       
  1284 
       
  1285 // Reports control events to observer
       
  1286 void CMIDChoiceGroupControl::ReportEventL(
       
  1287     MMIDChoiceGroupControlObserver::TChoiceGroupControlEvent aEvent,
       
  1288     TAny* aParam /* == NULL */)
       
  1289 {
       
  1290     if (iObserver)
       
  1291     {
       
  1292         iObserver->HandleChoiceGroupControlEventL(this, aEvent, aParam);
       
  1293     }
       
  1294 }
       
  1295 
       
  1296 
       
  1297 // Calculates whether scrolling the current lbox item into view
       
  1298 // is in order, and requests a scroll from the form (informs item
       
  1299 // of a svcroll request event) if necessary
       
  1300 void CMIDChoiceGroupControl::RequestScrollIfNeededL()
       
  1301 {
       
  1302     // Scroll should never be needed in a popup CG, and definitely
       
  1303     // not, if there is no listbox
       
  1304     if ((IsPopup()) || (!iListBox))
       
  1305     {
       
  1306         return;
       
  1307     }
       
  1308 
       
  1309     // Start with the form rect
       
  1310     TRect formRect = iItem->FormRect();
       
  1311 
       
  1312     if (formRect.IsEmpty())
       
  1313     {
       
  1314         return;
       
  1315     }
       
  1316 
       
  1317     TInt currentItem = KErrNotFound;
       
  1318 #ifdef RD_JAVA_S60_RELEASE_9_2
       
  1319     // First check if top visible item was set (only in case that
       
  1320     // ChoiceGroup was panned and now it is partially visible and
       
  1321     // got highlight by starting HW keys interaction).
       
  1322     // If item was set, do not scroll at all.
       
  1323     currentItem = iListBox->TopVisibleItemIndex();
       
  1324     if (currentItem == KErrNotFound)
       
  1325     {
       
  1326         // Top visible item was not set, i.e. ChoiceGroup already
       
  1327         // have highlight or it is fully visible or it is fully invisible.
       
  1328         currentItem = iListBox->CurrentItemIndex();
       
  1329     }
       
  1330 #else
       
  1331     currentItem = iListBox->CurrentItemIndex();
       
  1332 #endif // RD_JAVA_S60_RELEASE_9_2
       
  1333 
       
  1334     // Calculate current listbox item rect
       
  1335     TRect lbitemRect = TRect(
       
  1336                            iListBox->View()->ItemPos(currentItem),
       
  1337                            iListBox->View()->ItemSize(currentItem));
       
  1338 
       
  1339     // CG item rect is also needed
       
  1340     TRect cgitemRect = iItem->Rect();
       
  1341 
       
  1342     // Amount to be scrolled
       
  1343     TInt nScroll = 0;
       
  1344 
       
  1345     // If the current item is even partly outside the form, should
       
  1346     // scroll. Scroll amount is either the selected item border to
       
  1347     // middle of form rect, or the rest of the CG visible, whichever is
       
  1348     // smaller.
       
  1349     if (lbitemRect.iBr.iY > formRect.iBr.iY)
       
  1350     {
       
  1351         // Items bottom is below the form bottom - need to scroll up (-)
       
  1352         nScroll = Min((lbitemRect.iTl.iY - (formRect.Height() / 2)),
       
  1353                       ((cgitemRect.iBr.iY - formRect.iBr.iY) + 1));
       
  1354         // Scroll up is negative
       
  1355         nScroll = -nScroll;
       
  1356     }
       
  1357     else if (lbitemRect.iTl.iY < formRect.iTl.iY)
       
  1358     {
       
  1359         // Items top is above the form top - need to scroll down (+)
       
  1360         nScroll = Min((((formRect.Height() / 2) - lbitemRect.iBr.iY) + 1),
       
  1361                       (formRect.iTl.iY - cgitemRect.iTl.iY));
       
  1362     }
       
  1363     else
       
  1364     {
       
  1365         // There should be no need to scroll
       
  1366         return;
       
  1367     }
       
  1368 
       
  1369     // Report a scrolling request
       
  1370     ReportEventL(
       
  1371         MMIDChoiceGroupControlObserver::EScrollRequest,
       
  1372         (TAny*) nScroll);
       
  1373 }
       
  1374 
       
  1375 
       
  1376 void CMIDChoiceGroupControl::RestoreFocus()
       
  1377 {
       
  1378     // The sub-item focus restore is done by scrolling the form
       
  1379     // Exceptions can be ignored, because failing of RequestScrollIfNeededL
       
  1380     // may cause only a cosmetic visual problems
       
  1381     TRAP_IGNORE(RequestScrollIfNeededL());
       
  1382 }
       
  1383 
       
  1384 
       
  1385 // Pops up the popup choice (creates a listbox, gives it to the
       
  1386 // popup for content, gives the popup in turn as parent to the
       
  1387 // listbox construction, sets title, creates scrollbars and
       
  1388 // pop goes the weasel
       
  1389 void CMIDChoiceGroupControl::DoPopupL()
       
  1390 {
       
  1391     //in case skin or resolution has changed
       
  1392     iModel->ReConstructSelectionIconsL();
       
  1393     iModel->UpdateIconArrayL();
       
  1394 
       
  1395     // In order for the listbox to have popup as parent, it
       
  1396     // needs to be allocated and constructed separately
       
  1397     CMIDChoiceGroupListBox* pListBox = AllocateListBoxL();
       
  1398     CleanupStack::PushL(pListBox);
       
  1399 
       
  1400 #ifdef RD_JAVA_S60_RELEASE_9_2
       
  1401     // Create the popup with the listbox as popup content
       
  1402     CMIDChoiceGroupPopupList* pPop = CMIDChoiceGroupPopupList::NewL(
       
  1403                                          pListBox,
       
  1404                                          R_MIDP_SOFTKEYS_CANCEL,
       
  1405                                          AknPopupLayouts::EMenuUnknownColumnWindow);
       
  1406 #else
       
  1407 
       
  1408     // Create the popup with the listbox as popup content
       
  1409     CMIDChoiceGroupPopupList* pPop = CMIDChoiceGroupPopupList::NewL(
       
  1410                                          pListBox,
       
  1411                                          R_MIDP_SOFTKEYS_OK_BACK,
       
  1412                                          AknPopupLayouts::EMenuUnknownColumnWindow);
       
  1413 #endif // RD_JAVA_S60_RELEASE_9_2
       
  1414     CleanupStack::PushL(pPop);
       
  1415 
       
  1416     // Now actually construct the listbox with the popup as parent
       
  1417     ConstructListBoxL(pListBox, pPop);
       
  1418 
       
  1419     // We need some internal vertical scroll stuff in popup - set it up
       
  1420     pListBox->CreateScrollBarFrameL(ETrue);
       
  1421     pListBox->ScrollBarFrame()->SetScrollBarVisibilityL(
       
  1422         CEikScrollBarFrame::EOff,
       
  1423         CEikScrollBarFrame::EAuto);
       
  1424     // Drawing of scrollbar background is disabled - avoid improper
       
  1425     // drawing in landscape mode and appearance is consistent
       
  1426     // with native side
       
  1427     pListBox->ScrollBarFrame()->DrawBackground(EFalse, EFalse);
       
  1428 
       
  1429     // Set the popup title to be the same as the choicegroup label
       
  1430     pPop->SetTitleL(*(iItem->LabelControl()->Text()));
       
  1431 
       
  1432 #ifdef RD_JAVA_S60_RELEASE_9_2
       
  1433     // Show highlight in pop-up ChoiceGroup.
       
  1434     pListBox->DisableSingleClick(ETrue);
       
  1435 #endif // RD_JAVA_S60_RELEASE_9_2
       
  1436 
       
  1437     // set the current item to the one we currently have selected
       
  1438     if (iModel->SelectedElement() >= 0)
       
  1439     {
       
  1440         pListBox->SetCurrentItemIndex(iModel->SelectedElement());
       
  1441     }
       
  1442 
       
  1443     iPopupList = pPop;
       
  1444 
       
  1445 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  1446     //When popup list is opening, do the feedback
       
  1447     if (CAknTransitionUtils::TransitionsEnabled(
       
  1448                 AknTransEffect::EComponentTransitionsOff))
       
  1449     {
       
  1450         iFeedback->InstantFeedback(ETouchFeedbackIncreasingPopUp);
       
  1451     }
       
  1452     else
       
  1453     {
       
  1454         iFeedback->InstantFeedback(ETouchFeedbackPopUp);
       
  1455     }
       
  1456 #endif //RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  1457 
       
  1458     TInt popOK = pPop->ExecuteLD();
       
  1459     iPopupList = NULL;
       
  1460 
       
  1461     CleanupStack::Pop(pPop);
       
  1462 
       
  1463     // Examine result
       
  1464     if (popOK)
       
  1465     {
       
  1466         // Retrieve the selection, and set in model
       
  1467         TInt nSelected = pListBox->CurrentItemIndex();
       
  1468         if (nSelected != iModel->SelectedElement())
       
  1469         {
       
  1470             SelectElementL(nSelected, ETrue, ETrue);
       
  1471         }
       
  1472     }
       
  1473 #ifdef RD_JAVA_ADVANCED_TACTILE_FEEDBACK
       
  1474     else
       
  1475     {
       
  1476         //Popup list was closed without any selection:
       
  1477         //-user canceled it
       
  1478         //-user tapped outside of choice list dialog
       
  1479         //Do the closing feedback for these two cases
       
  1480         if (CAknTransitionUtils::TransitionsEnabled(
       
  1481                     AknTransEffect::EComponentTransitionsOff))
       
  1482         {
       
  1483             iFeedback->InstantFeedback(ETouchFeedbackDecreasingPopUp);
       
  1484         }
       
  1485         else
       
  1486         {
       
  1487             iFeedback->InstantFeedback(ETouchFeedbackPopUp);
       
  1488         }
       
  1489     }
       
  1490 #endif //RD_RD_ADVANCED_TACTILE_FEEDBACK
       
  1491 
       
  1492     // The icon column may need to be added or removed,
       
  1493     // SizeChanged does the relayout
       
  1494     SizeChanged();
       
  1495 
       
  1496     // Cleanup
       
  1497     CleanupStack::Pop(pListBox);
       
  1498     DeleteListBox(pListBox);
       
  1499 
       
  1500     iItem->DrawDeferred();
       
  1501 }
       
  1502 
       
  1503 
       
  1504 // Creates the choice listbox
       
  1505 CMIDChoiceGroupListBox* CMIDChoiceGroupControl::CreateListBoxL(
       
  1506     const CCoeControl* aParent)
       
  1507 {
       
  1508     // Allocate
       
  1509     CMIDChoiceGroupListBox* pListBox = AllocateListBoxL();
       
  1510     CleanupStack::PushL(pListBox);
       
  1511 
       
  1512     // Construct
       
  1513     ConstructListBoxL(pListBox, aParent);
       
  1514     CleanupStack::Pop(pListBox);
       
  1515 
       
  1516     return pListBox;
       
  1517 }
       
  1518 
       
  1519 
       
  1520 // Allocates the choice listbox.
       
  1521 CMIDChoiceGroupListBox* CMIDChoiceGroupControl::AllocateListBoxL()
       
  1522 {
       
  1523     return (new(ELeave) CMIDChoiceGroupListBox(this));
       
  1524 }
       
  1525 
       
  1526 
       
  1527 // Constructs the choice listbox with proper flags and parent
       
  1528 void CMIDChoiceGroupControl::ConstructListBoxL(
       
  1529     CMIDChoiceGroupListBox* aListBox,
       
  1530     const CCoeControl* aParent)
       
  1531 {
       
  1532     TInt flags(CEikListBox::ELeftDownInViewRect |
       
  1533                CEikListBox::EPaintedSelection |
       
  1534                CEikListBox::EKeepModel);
       
  1535 #ifdef RD_JAVA_S60_RELEASE_9_2
       
  1536     flags |= CEikListBox::ENoExtendedSelection;
       
  1537 #endif // RD_JAVA_S60_RELEASE_9_2
       
  1538 
       
  1539     // Construct with the model passed in (do not allow the listbox
       
  1540     // to create its own model)
       
  1541     aListBox->ConstructL(aParent, flags, iModel);
       
  1542 
       
  1543     // Grab the column data
       
  1544     CColumnListBoxData* columnData = aListBox->ItemDrawer()->ColumnData();
       
  1545 
       
  1546     // Set up columns
       
  1547     SetupColumnsL(columnData);
       
  1548 
       
  1549     // Set icon array
       
  1550     // NOTE that the listbox (columndata) does not own the
       
  1551     // icon array. Some things are needed in deletion to make
       
  1552     // sure that the array is not deleted with the listbox
       
  1553     columnData->SetIconArray(iModel->IconArray());
       
  1554 }
       
  1555 
       
  1556 
       
  1557 // Deletes the choice listbox (taking care not to destroy the icon array)
       
  1558 void CMIDChoiceGroupControl::DeleteListBox(CMIDChoiceGroupListBox* aListBox)
       
  1559 {
       
  1560     // NOTE that the iconarray in the listbox data needs to be
       
  1561     // set to NULL, otherwise the array contents will be deleted, which
       
  1562     // is not good, since it is actually the model that owns the icons
       
  1563     if (aListBox)
       
  1564     {
       
  1565         CColumnListBoxData* columnData = aListBox->ItemDrawer()->ColumnData();
       
  1566         columnData->SetIconArray(NULL);
       
  1567 
       
  1568         delete aListBox;
       
  1569     }
       
  1570 }
       
  1571 
       
  1572 /**
       
  1573 * Functions sets and layouts column data (part of list box used for choicegroup):
       
  1574 * Column 0 (ERadioButtonOrCheckBoxColumn) is used for radiobuton/checkbox icons
       
  1575 * Column 1 (EUserDefinedImagesColumn) is used for user defined images
       
  1576 * Column 2 (ETextColumn) is used for text
       
  1577 * Each colum has specific layout.
       
  1578 *
       
  1579 * @param aColumnData pointer to CColumnListBoxData
       
  1580 */
       
  1581 void CMIDChoiceGroupControl::SetupColumnsL(CColumnListBoxData* aColumnData)
       
  1582 {
       
  1583     ASSERT(aColumnData);
       
  1584 
       
  1585     if (iModel->HasIcons())
       
  1586     { //ChoiceGroup has user defined images
       
  1587         TAknTextLineLayout textlayout;
       
  1588         TAknWindowLineLayout graphiclayout;
       
  1589 
       
  1590         if (iType != MMIDChoiceGroup::EPopup)
       
  1591         { //ChoiceGroup
       
  1592             //Normal ChoiceGroup must have radiobuton/checkbox icons
       
  1593             //if MULTIPLE or EXCLUSIVE type is set.
       
  1594             //We set and layout 0. column for those icons.
       
  1595             aColumnData->SetGraphicSubCellL(ERadioButtonOrCheckBoxColumn,
       
  1596                                             AknLayoutScalable_Avkon::
       
  1597                                             list_single_2graphic_pane_g2_cp4().LayoutLine());
       
  1598             //layout for text
       
  1599             textlayout = AknLayoutScalable_Avkon::
       
  1600                          list_single_2graphic_pane_t1_cp4().LayoutLine();
       
  1601             //layout for user defined image
       
  1602             graphiclayout = AknLayoutScalable_Avkon::
       
  1603                             list_single_2graphic_pane_g1_cp4().LayoutLine();
       
  1604         }
       
  1605         else
       
  1606         { //Popup ChoiceGroup - must not have radiobuton/checkbox icons,
       
  1607             // so that 0. column is not layouted.
       
  1608             //text layout
       
  1609             textlayout = AknLayoutScalable_Avkon::
       
  1610                          list_single_graphic_pane_t1_cp2(0).LayoutLine();
       
  1611             //layout for user defined image
       
  1612             graphiclayout = AknLayoutScalable_Avkon::
       
  1613                             list_single_graphic_pane_g1_cp2(0).LayoutLine();
       
  1614         }
       
  1615         //set and layout remaining columns
       
  1616         aColumnData->SetTextSubCellL(ETextColumn, textlayout);
       
  1617         aColumnData->SetGraphicSubCellL(EUserDefinedImagesColumn,
       
  1618                                         graphiclayout);
       
  1619     }
       
  1620     else
       
  1621     { //ChoiceGroup doesn't have user defined images
       
  1622         if (iType != MMIDChoiceGroup::EPopup)
       
  1623         { //ChoiceGroup
       
  1624             //Normal ChoiceGroup must have radiobuton/checkbox icons
       
  1625             //if MULTIPLE or EXCLUSIVE type is set.
       
  1626             //We set and layout 0. column for those icons.
       
  1627             aColumnData->SetGraphicSubCellL(ERadioButtonOrCheckBoxColumn,
       
  1628                                             AknLayoutScalable_Avkon::
       
  1629                                             list_single_midp_graphic_pane_g4_cp().LayoutLine());
       
  1630             // Set and layout text column.
       
  1631             aColumnData->SetTextSubCellL(ETextColumn,
       
  1632                                          AknLayoutScalable_Avkon::
       
  1633                                          list_single_midp_graphic_pane_t1_cp().LayoutLine());
       
  1634         }
       
  1635         else
       
  1636         { //Popup ChoiceGroup - must not have radiobuton/checkbox icons,
       
  1637             // so that 0. column is not layouted.
       
  1638             // Set and layout text column.
       
  1639             aColumnData->SetTextSubCellL(ETextColumn,
       
  1640                                          AknLayoutScalable_Avkon::
       
  1641                                          list_single_pane_t1_cp2(0).LayoutLine());
       
  1642         }
       
  1643         // Hide the 1. graphic column when there are no user defined images
       
  1644         TAknWindowLineLayout layout =
       
  1645             AknLayoutScalable_Avkon::
       
  1646             list_single_2graphic_pane_g1_cp4().LayoutLine();
       
  1647         layout.iW = 0;  // zero width
       
  1648         aColumnData->SetGraphicSubCellL(EUserDefinedImagesColumn, layout);
       
  1649     }
       
  1650 }
       
  1651 
       
  1652 // Calculate the rect to assign to the listbox.
       
  1653 TRect CMIDChoiceGroupControl::ListBoxRect(const TRect& aRect) const
       
  1654 {
       
  1655     TRect rect(aRect);
       
  1656 
       
  1657     if (iListBox)
       
  1658     {
       
  1659         TAknLayoutRect layoutRect;
       
  1660         layoutRect.LayoutRect(rect, AknLayoutScalable_Avkon::
       
  1661                               form2_midp_field_choice_group_pane().LayoutLine());
       
  1662         rect = layoutRect.Rect();
       
  1663     }
       
  1664 
       
  1665     return rect;
       
  1666 }
       
  1667 
       
  1668 
       
  1669 // Sets selection state of element at <aIndex>
       
  1670 // This a private method. There is also a public method
       
  1671 // CMIDChoiceGroupControl::SelectElementL(TInt aIndex, TBool aSelected)
       
  1672 // which calls this one.
       
  1673 void CMIDChoiceGroupControl::SelectElementL(TInt aIndex, TBool aSelected, TBool aPostEvent)
       
  1674 {
       
  1675     ASSERT(iModel);
       
  1676     iModel->SelectElementL(aIndex, aSelected);
       
  1677     iItem->UpdateCommands();
       
  1678 
       
  1679     if (aPostEvent)
       
  1680     {
       
  1681         iItem->PostItemStateChangedEventL();
       
  1682     }
       
  1683 }
       
  1684 
       
  1685 
       
  1686 void CMIDChoiceGroupControl::UpdateMargins()
       
  1687 {
       
  1688     TAknLayoutRect layoutRect;
       
  1689     // use the screen as a parent only the margins are calculated
       
  1690     TRect screenRect(iEikonEnv->ScreenDevice()->SizeInPixels());
       
  1691     layoutRect.LayoutRect(screenRect, AknLayoutScalable_Avkon::
       
  1692                           form2_midp_field_choice_group_pane().LayoutLine());
       
  1693 
       
  1694     TRect contentRect = layoutRect.Rect();
       
  1695 
       
  1696     iContentMargins.iTop    = contentRect.iTl.iY;
       
  1697     iContentMargins.iBottom = screenRect.iBr.iY - contentRect.iBr.iY;
       
  1698     iContentMargins.iLeft   = contentRect.iTl.iX;
       
  1699     iContentMargins.iRight  = screenRect.iBr.iX - contentRect.iBr.iX;
       
  1700 }
       
  1701 
       
  1702 void CMIDChoiceGroupControl::UpdatePopupListAppearanceL(TChoiceGroupModelEvent aEvent)
       
  1703 {
       
  1704     if (!iPopupList)
       
  1705     {
       
  1706         return;
       
  1707     }
       
  1708 
       
  1709     // resize is done by default
       
  1710     TBool bResize = ETrue;
       
  1711 
       
  1712     // Act upon the event, resize and redraw the popup list as necessary
       
  1713     // EUpdateEnded and EUpdateStarted events are not possible in this
       
  1714     // function as they occur only when choice group is constructed
       
  1715     switch (aEvent)
       
  1716     {
       
  1717     case EElementAdded:
       
  1718         iPopupList->ListBox()->HandleItemAdditionL();
       
  1719         break;
       
  1720     case EElementDeleted:
       
  1721         iPopupList->ListBox()->HandleItemRemovalL();
       
  1722 
       
  1723         // Popup list loses focus if the highlighted is in the last element and
       
  1724         // an element is removed. Set focus to last element in this case.
       
  1725         if (iPopupList->ListBox()->View()->CurrentItemIndex() == KErrNotFound &&
       
  1726                 iModel->NumberOfItems() > 0)
       
  1727         {
       
  1728             iPopupList->ListBox()->View()->SetCurrentItemIndex(iModel->NumberOfItems() - 1);
       
  1729         }
       
  1730         break;
       
  1731     case EElementModified:
       
  1732         // after the LAF changes the icon column is dynamic in popup list, so resize
       
  1733         // may be needed after image has been added to or removed from element
       
  1734         break;
       
  1735     case EElementSelected:
       
  1736         // Just a redraw will do
       
  1737         bResize = EFalse;
       
  1738         break;
       
  1739     default:
       
  1740         bResize = EFalse;
       
  1741         break;
       
  1742     }
       
  1743 
       
  1744     if (bResize)
       
  1745     {
       
  1746         // cast is safe as CMIDChoiceGroupListBox is inherited from CAknColumnListBox
       
  1747         SetupColumnsL(static_cast<CEikColumnListBox*>(
       
  1748                           iPopupList->ListBox())->ItemDrawer()->ColumnData());
       
  1749         iPopupList->ResizeList();
       
  1750     }
       
  1751 
       
  1752     iPopupList->DrawDeferred();
       
  1753 }
       
  1754 
       
  1755 void CMIDChoiceGroupControl::ShowInfoPopup()
       
  1756 {
       
  1757     if (!iListBox || !IsVisible())
       
  1758     {
       
  1759         return;
       
  1760     }
       
  1761 
       
  1762     TInt index = iListBox->View()->CurrentItemIndex();
       
  1763     if (index >= 0)
       
  1764     {
       
  1765         CMIDForm* form = iItem->Form();
       
  1766         if (form)
       
  1767         {
       
  1768             form->GetPopupNoteController()->HidePopup();
       
  1769 
       
  1770             if (static_cast<CEikColumnListBox*>(iListBox)->ItemDrawer()->ColumnData()->
       
  1771                     CurrentItemTextWasClipped())
       
  1772             {
       
  1773                 CMIDChoiceGroupElement* pElement = iModel->ElementAt(index);
       
  1774                 if (pElement)
       
  1775                 {
       
  1776                     TRect mainPane;
       
  1777                     AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, mainPane);
       
  1778 
       
  1779                     // HighLight rect returns the rect in propotion to whole screen,
       
  1780                     // move it in propotion to the main pane to check if its visible.
       
  1781                     TRect rect = iListBox->HighlightRect();
       
  1782                     TRect temp = rect;
       
  1783                     temp.Move(0, -mainPane.iTl.iY);
       
  1784                     if (form->RectPartiallyVisible(temp))
       
  1785                     {
       
  1786                         TRAP_IGNORE(form->GetPopupNoteController()->ShowPopupL(pElement->Text(),
       
  1787                                     rect));
       
  1788                     }
       
  1789                 }
       
  1790             }
       
  1791             else
       
  1792             {
       
  1793                 DEBUG("CMIDChoiceGroupControl::ShowInfoPopup(): text not clipped");
       
  1794             }
       
  1795         }
       
  1796     }
       
  1797 }
       
  1798 
       
  1799 #ifdef RD_SCALABLE_UI_V2
       
  1800 void CMIDChoiceGroupControl::TimedScroll(CMIDForm::TDirection aDirection)
       
  1801 {
       
  1802     ASSERT(iListBox);
       
  1803 
       
  1804     TRect itemRect = iItem->Rect();
       
  1805     TInt formHeight = iItem->FormRect().Height();
       
  1806 
       
  1807     // There must be something to scroll
       
  1808     if ((aDirection == CMIDForm::EDown && itemRect.iBr.iY <= formHeight) ||
       
  1809             (aDirection == CMIDForm::EUp   && itemRect.iTl.iY >= 0))
       
  1810     {
       
  1811         return;
       
  1812     }
       
  1813 
       
  1814     iPointerDragHasStarted = ETrue;
       
  1815 
       
  1816     TInt scroll = 0;
       
  1817     TInt elementHeight = iListBox->ItemHeight();
       
  1818     TInt index = FirstInvisibleElement(aDirection);
       
  1819 
       
  1820     // If valid index was found, adjust scroll so that the element at index will be fully visible.
       
  1821     // Otherwise scroll height of one element or to the bottom/top of the item.
       
  1822     if (aDirection == CMIDForm::EDown)
       
  1823     {
       
  1824         if (index != KErrNotFound)
       
  1825         {
       
  1826             scroll = -(iListBox->View()->ItemPos(index).iY + elementHeight - formHeight);
       
  1827         }
       
  1828         else
       
  1829         {
       
  1830             scroll = Max(-elementHeight, -(itemRect.iBr.iY - formHeight));
       
  1831         }
       
  1832     }
       
  1833     else if (aDirection == CMIDForm::EUp)
       
  1834     {
       
  1835         if (index != KErrNotFound)
       
  1836         {
       
  1837             scroll = -iListBox->View()->ItemPos(index).iY;
       
  1838         }
       
  1839         else
       
  1840         {
       
  1841             scroll = Min(elementHeight, -itemRect.iTl.iY);
       
  1842         }
       
  1843     }
       
  1844 
       
  1845     if (index != KErrNotFound)
       
  1846     {
       
  1847         iListBox->View()->SetCurrentItemIndex(index);
       
  1848     }
       
  1849 
       
  1850     TRAP_IGNORE(ReportEventL(MMIDChoiceGroupControlObserver::EScrollRequest, (TAny*)scroll));
       
  1851 }
       
  1852 
       
  1853 TInt CMIDChoiceGroupControl::FirstInvisibleElement(CMIDForm::TDirection aScrollDirection) const
       
  1854 {
       
  1855     TInt index = KErrNotFound;
       
  1856     TInt formHeight = iItem->FormRect().Height();
       
  1857 
       
  1858     // First find which element is currently right in the top or bottom edge of the form
       
  1859     TInt yPos = (aScrollDirection == CMIDForm::EDown) ? formHeight : 0;
       
  1860 
       
  1861     TBool found = iListBox->View()->XYPosToItemIndex(
       
  1862                       TPoint(iListBox->Rect().Center().iX, yPos), index);
       
  1863 
       
  1864     // Check if more than half of the element at index is already visible, move to next item or
       
  1865     // if already in the last/first element, return KErrNotFound
       
  1866     if (found && aScrollDirection == CMIDForm::EDown)
       
  1867     {
       
  1868         if (formHeight - iListBox->View()->ItemPos(index).iY > (iListBox->ItemHeight() / 2))
       
  1869         {
       
  1870             index = (index < (iModel->NumberOfItems() - 1)) ? index + 1 : KErrNotFound;
       
  1871         }
       
  1872     }
       
  1873     else if (found && aScrollDirection == CMIDForm::EUp)
       
  1874     {
       
  1875         if (-iListBox->View()->ItemPos(index).iY < (iListBox->ItemHeight() / 2))
       
  1876         {
       
  1877             index = (index > 0) ? index - 1 : KErrNotFound;
       
  1878         }
       
  1879     }
       
  1880 
       
  1881     return index;
       
  1882 }
       
  1883 
       
  1884 #endif
       
  1885 
       
  1886 #ifdef RD_JAVA_S60_RELEASE_9_2
       
  1887 CMIDForm* CMIDChoiceGroupControl::Form() const
       
  1888 {
       
  1889     return iItem->Form();
       
  1890 }
       
  1891 #endif // RD_JAVA_S60_RELEASE_9_2