List boxes

From UIQ Books

Jump to: navigation, search

Contents

UIQ 3 List boxes

UIQ 3 applications frequently use a list-detail model. This means that when the application starts, data is presented in a list view. The user selects an item from the list and opens a detail view to see and do more. Agenda, Contacts and Jotter use this method of presentation.

Previous versions of UIQ supported list boxes but the old controls have been replaced by a new highly flexible, highly functional list box class CQikListBox.

This new class fulfils a core UIQ 3 design goal of allowing applications to use a single control, while the control adapts itself to be appropriate for the type of phone it is being displayed on. For example, on a Pen Style phone the list box has a wide pen-operated scrollbar; on a Softkey Style phone scrolling uses the Up and Down keys but retains a narrow scrollbar to provide visual feedback.

Scrollbars in Softkey Style Scrollbars in Softkey Style Touch

Figure 1 Scrollbars in Softkey Style and Softkey Style Touch

This chapter presents the functionality of list boxes through two example applications. The first example presents a simple traditional list box type application. The second explores the wide variety of functionality that can be included within a UIQ 3 list box control.

As part of the first example application we step through the framework code that each application needs to provide. The general structure of the framework code is common across most UIQ 3 applications and we will not repeat it in later examples.

ListView1 Application

This application presents a list box control containing a fixed number of entries. The list box is presented in a single view. Key, pointer and redraw events are all delivered to the application although this is not obvious since these are all handled automatically by the framework. The application supports the six primary view configurations available within the emulator. As you switch between configurations, so the list box is updated to display correctly within those configurations.

ListView1 application

Figure 2 ListView1 application

The application is made up from the following files:

Listview1.mmp The Symbian makefile for the application.
Listview1_reg.rss The application registration file. The meaning and use of registration files is discussed fully in the Chapter Building an Application. For the purpose of the examples in this chapter you can ignore these files.
ListView1_loc.rss The localization information required by the application registration file. As with registration files these are described fully in the Chapter Building an Application.
ListView1.rss Is the application resource file. UIQ 3 applications are resource intensive so you should be able to read and understand the structure and content of resource files.
ListView1.hrh The application shared resource and source code header file.
ListView1.h Contains the public object definitions. For the example applications these contain minimal information.
ListView1.cpp Contains the entire example application source code.

The application contains two objects of interest:

CAppSpecificListView The application-specific list view. This subclasses the CQikViewBase class hence ultimately the CCoeControl class. It presents the view as a list box as opposed to any other type of control.
CAppSpecificUi The application user interface object. This subclasses CQikAppUi and includes the application entry point. Amongst other tasks CQikAppUi creates the control environment for you.

In a graphical application, code execution effectively starts at the ConstructL() method of the application specific UI object. Our application contains the following code:

void CAppSpecificUi::ConstructL()
  {
  CQikAppUi::ConstructL();
 
  // Create and set up an engine.
  iEngine=new(ELeave)CAppEngine(EQikCmdZoomLevel2);
  TBuf<KMaxListItemText>bb;
  const TInt KListView1Items=7;
  for (TInt i=0;i<KListView1Items;i++)
    {
    iEikonEnv->ReadResourceL(bb,R_STR_LIST_CONTENT_1+i);
    iEngine->SetListItem(bb);
    }
 
  // Create and set up the single view.
  CAppSpecificListView* q = new(ELeave)CAppSpecificListView(*this,iEngine);
  CleanupStack::PushL(q);
  q->ConstructL();
  AddViewL(*q);
  CleanupStack::Pop(q);
  }

The call to CQikAppUi::ConstructL() is very important as it is responsible for setting up various parts of the control environment such as creating the control stack.

The first application-specific task is creating and initializing an engine object. The second is creating and initializing the single view. Of all the above lines of code the AddViewL() function is one to focus on, the rest should be self explanatory.

AddViewL()

This method takes ownership of the passed object, registers it with the view server and adds it to the control stack. Unlike previous versions of UIQ, the CAppSpecificUi object is no longer required to track or delete the view object; the framework now performs that task on your behalf.

For a view to be registered with the view server it needs to implement the MCoeView interface. A primary task of our view is to implement that interface.

As we explained in the previous chapter, the control stack is a priority ordered list of controls that are interested in receiving key events from the window server. Our view has been registered as such a control and will therefore be delivered key presses if no other higher priority control consumes them.

Code execution reaches the end of the ConstructL() method and returns to the framework. A short period of time later the ViewConstructL() method of our view will be called.

The CAppSpecificListView object

This object implements a view on the application data. As part of implementing the MCoeView interface, all views need to be uniquely identified which is achieved using a TVwsViewId object. A TVwsViewId object comprises two UIDs, the first must be your application UID and the second is a value which is unique within your application.

A TVwsViewId is defined as:

  const TUid KAppSpecificUid={0xEDEAD001};
  const TUid KUidListView={0x00000001};
  #define KViewIdListView TVwsViewId(KAppSpecificUid,KUidListView)

It is returned by the ViewId() method:

TVwsViewId CAppSpecificListView::ViewId() const
  {
  return(KViewIdListView);
  }

To reiterate, the first UID needs to be your application UID, as opposed to any other globally unique ID you may have been allocated. This is how the view server identifies the application that contains the view and subsequently how you can display views belonging to other applications.

After the ViewId() method, ViewConstructL() is called:

void CAppSpecificListView::ViewConstructL()
  {
  ViewConstructFromResourceL(R_LIST_VIEW_CONFIGURATIONS); 
  CQikViewBase::SetZoomFactorL(CQikAppUi::ZoomFactorL(iEngine->ListViewZoomState(),*iEikonEnv));  
  LocateControlByUniqueHandle<CQikListBox>(EListViewListId)->SetListBoxObserver(this);
 
  // Add a view title.
  TBuf<64>bb;
  iEikonEnv->ReadResourceL(bb,R_STR_LIST_TITLE);
  ViewContext()->AddTextL(1,bb);
  }

UIQ 3 substantially expands the view functionality so that applications can support a wide variety of phones within a single executable. A single phone may support multiple UI configurations, such as portrait and landscape or Softkey Style and Pen Style. Such configurations may vary such that functionality available in one configuration cannot reasonably be performed in another or the way in which certain functionality is presented has to change to ensure optimal usage. The UIQ 3 Calculator application is such a case:

Calculator application in Softkey Style Calculator application in Pen Style

Figure 3 Calculator application in Softkey Style and Pen Style

UIQ 3 deals with these configuration issues via extensive use of resource files. The first line of our ViewConstructL() method passes the resource ID of the view configuration information specific to our view.

The remainder of the method sets our default zoom size, specifies that the view wants to hear about list box events and sets the text displayed below the application name.

The framework code has performed a substantial number of tasks on our behalf. For example, it has read and interpreted the configuration resource, created the controls that resource has defined, laid them out and presented a type safe mechanism by which we can access the controls.

To complete the implementation of the MCoeView interface we need to provide the ViewActivatedL() and ViewDeactivated() methods.

void CAppSpecificListView::ViewActivatedL(
  const TVwsViewId& aPrevViewId,
  const TUid aCustomMessageId,
  const TDesC8& aCustomMessage)
  {
  AddItemsL();
  }
      
void CAppSpecificListView::ViewDeactivated()
  {
  CQikListBox* listbox= LocateControlByUniqueHandle<CQikListBox>(EAppSpecificListViewListId);
  listbox->RemoveAllItemsL();
  }

The ViewActivatedL() method of a view is called when the view server determines a particular view should become the foreground view. If completed without error, the ViewDeactivated() of the previous view will be called.

In our example we have chosen to generate the content of the list box when the view is activated, freeing any resources when the view is deactivated. In a resource constrained environment it is good practice to allocate resources only as and when they are needed and to free them up when not required. It should be noted however that there is often a trade off between the time taken to build any data structure, how much memory it uses and how appropriate such actions are for your specific application.

You can exercise the ViewActivatedL() and ViewDeactivated() code by switching back and forth between ListView1 and the application launcher.

View Configuration Resources

Most resource structures used by a view are defined in qikon.rh. If you are unsure about how resource files are structured and used it is strongly recommended you review the resource files information in the UIQ 3 SDK or read Chapter 13 of the Symbian OS C++ for Mobile Phones, Volume 3 book.

When our view is constructed, we call the ViewConstructFromResourceL() method passing it a resource ID R_LIST_VIEW_CONFIGURATIONS. This resource is defined in ListView1.rss as:

RESOURCE QIK_VIEW_CONFIGURATIONS r_list_view_configurations
  {
  configurations =
    {
    QIK_VIEW_CONFIGURATION
      {
      ui_config_mode = KQikPenStyleTouchPortrait;
      command_list = r_list_view_pen_style_commands;
      view = r_list_view_pen_style_view;
      },
    QIK_VIEW_CONFIGURATION
      {
      ui_config_mode = KQikPenStyleTouchLandscape;
      command_list = r_list_view_pen_style_commands;
      view = r_list_view_pen_style_view;
      },
    QIK_VIEW_CONFIGURATION
      {
      ui_config_mode = KQikSoftkeyStylePortrait;
      command_list = r_list_view_key_style_commands;
      view = r_list_view_key_style_view;
      },
    QIK_VIEW_CONFIGURATION
      {
      ui_config_mode = KQikSoftkeyStyleSmallPortrait;
      command_list = r_list_view_key_style_commands;
      view = r_list_view_key_style_view;
      },
    QIK_VIEW_CONFIGURATION
      {
      ui_config_mode = KQikSoftkeyStyleSmallLandscape;
      command_list = r_list_view_key_style_commands;
      view = r_list_view_key_style_view;
      },
    QIK_VIEW_CONFIGURATION
      {
      ui_config_mode = KQikSoftkeyStyleTouchPortrait;
      command_list = r_list_view_key_style_commands;
      view = r_list_view_key_style_view;
      }
    };
  }

The r_list_view_configurations comprises a set of six QIK_VIEW_CONFIGURATION structures, one for each of the configurations supported by our application. UI configurations are described in the Chapter UIQ 3 Basics.

The framework code looks at the set of view configurations and compares with the phone's current UI configuration to choose the most appropriate entry. For example, if a phone has a portrait oriented touch screen and is in Pen Style UI configuration, the KQikPenStyleTouchPortrait entry is chosen. If the UI configuration changes, for example, if the flip is closed on a Sony Ericsson P990i, the framework code will choose the entry for KQikSoftkeyStyleSmallPortrait.

Once the framework has chosen an entry it will read the list of views and commands associated with that entry to configure dynamically the application. We have determined the example application can use a single command list and view for both of the Pen Style configurations. Similarly, a single command list and view can be used for all four of the Softkey Style configurations. In more sophisticated applications you may choose to have separate commands and/or views for each of the configurations.

The full list of configurations as defined in Qikon.hrh is:

  KQikSoftkeyStylePortrait
  KQikSoftkeyStyleLandscape
  KQikSoftkeyStyleLandscape180
  KQikSoftkeyStyleSmallPortrait
  KQikSoftkeyStyleSmallLandscape
  KQikSoftkeyStyleSmallLandscape180
  KQikSoftkeyStyleTouchPortrait
  KQikSoftkeyStyleTouchLandscape
  KQikSoftkeyStyleTouchLandscape180
  KQikPenStyleTouchPortrait
  KQikPenStyleTouchLandscape
  KQikPenStyleTouchLandscape180

There are a number of factors that you need to consider when determining what configurations an application should support. We have chosen to support six UI configurations in our example applications. At the time of writing, if your application supports these six, you will support all the commercially available UIQ 3 devices. As an absolute minimum you should support the default configurations of the UIQ 3 phones that you wish to support.

If the phone is in a UI configuration that is not explicitly listed in your QIK_VIEW_CONFIGURATIONS, then the framework will select the QIK_VIEW_CONFIGURATION that it considers to best match the phone's configuration. Your application will run, however, in some instances view layout and command handling may not be optimal.

Pro tip:

Your application may choose not to support certain view configurations, hence classes of phones, for technical or commercial reasons. The UIQ 3 framework does not require you support a specific number of configurations. However, you need to understand the consequences of only supporting certain configurations and running in ‘best match’ mode, particularly if you choose not to support a configuration used on commercially available phones.

In our example application we have identified two different views, one for Pen Style configurations and one for Softkey Style configurations, r_list_view_pen_style_view and r_list_view_key_style_view respectively. The resource referenced by the view field is expected to be of type QIK_VIEW.

At this point it is worth recalling that the UIQ 3 resource definitions are required to support a wide range of application usages. Specific applications will only use a subset of the fields defined within a particular resource. The first example of this is the QIK_VIEW resource, defined as:

STRUCT QIK_VIEW
  {
  BYTE version = 2;
  LLINK view_mode = 0;
  LLINK command_list = 0;
  LLINK qiktoolbar = 0;
  LLINK pages = 0;
  }

If you look at the r_list_view_pen_style_view or r_list_view_key_style_view resources as duplicated below you will see we only use the pages field.

RESOURCE QIK_VIEW r_list_view_pen_style_view
  {
  pages = r_list_view_pen_style_pages;
  }

In general an application view is made up of a number of pages of information. In its simplest form the number of pages is one. The r_list_view_pen_style_pages link is expected to reference a resource of type QIK_VIEW_PAGES.

RESOURCE QIK_VIEW_PAGES r_list_view_pen_style_pages
  {
  pages =
    {
    QIK_VIEW_PAGE
      {
      page_id = EAppSpecificListViewPageId;
      page_content = r_list_view_page_control;
      }
    };
  }

Since our application only has a single page of controls we only need a single QIK_VIEW_PAGE structure.

Applications often need to reference controls created from resources within the application code. To achieve this, controls are allocated some type of unique ID; in the case of a QIK_VIEW_PAGE it is the page_id. For this application the page_id is set to EAppSpecificListViewPageId, an application-specific value defined in ListView1.hrh.

A page needs to contain some content. In UIQ 3 a page will usually contain a set of controls within a containing control. The r_list_view_page_control references a resource of type QIK_CONTAINER_SETTINGS which defines the container and controls within that container.

RESOURCE QIK_CONTAINER_SETTINGS r_list_view_page_control
  {
  layout_manager_type = EQikRowLayoutManager;
  layout_manager = r_row_layout_manager_default;
  controls =
    {
    QIK_CONTAINER_ITEM_CI_LI
      {
      unique_handle = EAppSpecificListViewListId;
      type = EQikCtListBox;
      control = r_app_listview_listbox;
      layout_data = r_row_layout_data_fill;
      }
    };
  }

The UIQ 3 application framework provides a set of sophisticated controls called layout managers that will, within certain bounds, lay out controls automatically for you irrespective of the current configuration. We discuss this in detail in the Chapter Layout Managers and Building Blocks. For now, all you need to know is that our list box will be laid out in rows using EQikRowLayoutManager with default parameters.

Row layout manager

Figure 4 Row layout manager

RESOURCE QIK_ROW_LAYOUT_MANAGER r_row_layout_manager_default
  {
  default_layout_data = QIK_ROW_LAYOUT_DATA {};
  }

Within the container we have a set of controls, each defined by a QIK_CONTAINER_ITEM or derivative such as:

  QIK_CONTAINER_ITEM_CI_LI
  QIK_CONTAINER_ITEM_CD_LI
  QIK_CONTAINER_ITEM_LD
  QIK_CONTAINER_ITEM_CI_LD
  QIK_CONTAINER_ITEM_CD_LD
  QIK_CONTAINER_ITEM_NESTED_CONTAINER
  QIK_CONTAINER_ITEM_NESTED_CONTAINER_CI_LI

For the inquisitive amongst you, the way the resource reading code knows how to differentiate between the above structures is to query the first byte or the struct_type field. You may note from resource definitions this field varies from 0 to 7 dependent on which of the above resources is used.

Each of the QIK_CONTAINER_ITEM resource definitions has a different set of fields to complete depending on exactly what you are attempting to achieve and some individual preferences about how to achieve the desired results. So how do we go about determining which variant is applicable to our application?

A container item requires two fundamental pieces of information: a description of the control to put in the container and some associated layout information. Resources can be defined to either expect a reference to another resource or contain that resource directly. A reference to another resource is said to be indirect.

In general the QIK_CONTAINER_ITEM resource definitions follow a naming convention:

  • C = control information
  • L = layout information
  • D = directly define
  • I = indirectly defined, via a reference to another resource.

Thus a QIK_CONTAINER_ITEM_CD_LI resource contains the ­Control defined Directly within the structure, while the Layout information is defined Indirectly.

Our application has chosen to reference both the control and layout information using a resource name. Therefore our example application uses a QIK_CONTAINER_ITEM_CI_LI structure.

Had we made other choices, we could have used the following code to achieve the same result:

  QIK_CONTAINER_ITEM_CI_LD
    {
    unique_handle = EAppSpecificListViewListId;
    type = EQikCtListBox;
    control = r_app_listview_listbox;
    layout_data = QIK_ROW_LAYOUT_DATA
      {
      vertical_alignment = EQikLayoutVAlignFill;
      vertical_excess_grab_weight = 1;
      };
    }

Actually there are two ways in which controls can be referenced indirectly within a resource file: via resource name or by a unique ID. Controls referenced by their unique ID need to exist within a QIK_CONTROL_COLLECTION. For simplicity, the first example does not use a QIK_CONTROL_COLLECTION.

Apart from enabling the usage of a QIK_CONTROL_COLLECTION the unique_handle field allows us to uniquely identify a control within our application. As with the page_id earlier the EAppSpecificListViewListId is defined in ListView1.hrh. The layout_data field in our QIK_CONTAINER_ITEM_CI_LI specifies how the row layout manager needs to handle some layout attributes. In this example, with a single list box control, little information is required. Finally, we get to define what type of control is to be created, in this instance an EQikCtListBox, then the reference to the list box configuration information.

RESOURCE QIK_LISTBOX r_app_listview_listbox
  {
  view = r_app_listbox_view_default;
  layouts = { r_app_normal_layout_pair };
  }
 
RESOURCE QIK_LISTBOX_ROW_VIEW r_app_listbox_view_default
  {
  }
 
RESOURCE QIK_LISTBOX_LAYOUT_PAIR r_app_normal_layout_pair
  {
  standard_normal_layout = EQikListBoxLine;
  }

The primary field of interest above is the standard_normal_layout field.

List boxes come in a variety of styles depending on what information you are attempting to present, and how you want to present it. For Listbox1 we have chosen the simplest type of list box, EQikListBoxLine, where each line contains a single text item.

List box type EQikListBoxLine

Figure 5 List box type EQikListBoxLine

Wow, all that just to display a list box? Well yes, however you have a UI control that supports multiple phone configurations. You can observe this by switching the emulator in to different view configurations, which you can do in a number of ways:

  • set the configuration using UiqEnv -ui at the command prompt (see the Chapter Testing, debugging and deploying)
  • use the UiConfigTest application in the application launcher
  • switch through configurations using Ctrl+Alt+Shift+U.

We now have a starting point from which we can extend the functionality. For example we might change the type of list box, add more pages and use more controls in our application.

The next example builds on this simple list box example to demonstrate usage of all the standard list box types and how to start customizing list boxes.

ListView2 application

This application extends the ListView1 example application to show:

  • support for multi-page applications
  • support for all list box types
  • an alternative approach to creating and initializing list boxes.

ListView2 example application

Figure 6 ListView2 example application

Unlike many platforms, a significant proportion of a UIQ 3 application user interface can be defined in resource files. The software that interprets the resource information is provided within the application framework code. If there is a problem with interpreting any resource, your application will typically panic. One of the difficulties with UIQ 3 is being able to debug why the panic occurred and which resource caused the problem.

This application presents at least one implementation of every type of standard list box as listed earlier. It also shows how to construct a custom list box should you need something more than UIQ 3 provides as standard.

Pro tip:

Due to the difficulty in debugging the framework resource interpretation code, it is often easier to take a known working example, get that to work within your application then change the code and resources to suit your specific application. This application provides the working examples; in particular, showing how to set up each of the list box types to display content.

Structurally the application is identical to the ListView1 example. The primary difference is that the application view subclasses CQikMultiPageViewBase instead of CQikViewBase since this application wants to display more than one page to the user. The two pieces of code are shown below:

class CAppSpecificListView : public CQikMultiPageViewBase
  {
  };
class CAppSpecificListView : public CQikViewBase
  {
  };

Since we have multiple pages of content multiple QIK_VIEW_PAGE entries are defined in the r_list_view_pages resource, one of each page. We actually have twelve pages but only the first three are shown here.

RESOURCE QIK_VIEW_PAGES r_list_view_pages
  {
  pages =
    {
    QIK_VIEW_PAGE
      {
      page_id = EAppSpecificListViewPageId1;
      tab_bmpid = EMbmListview2Tab1;
      tab_bmpmaskid = EMbmListview2Tab1mask;
      page_content = r_list_view_page1_control;
      },
    QIK_VIEW_PAGE
      {
      page_id = EAppSpecificListViewPageId2;
      tab_bmpid = EMbmListview2Tab2;
      tab_bmpmaskid = EMbmListview2Tab2mask;
      page_content = r_list_view_page2_control;
      },
    QIK_VIEW_PAGE
      {
      page_id = EAppSpecificListViewPageId3;
      tab_caption = "Tab3";
      page_content = r_list_view_page3_control;
      },
 
    // Remaining pages repeat the above info.
    };
  }

Pages are presented as a tabbed list across view context area of the title bar. These tabs can contain icons or text. In our code fragment two tabs contain icons, the third contains some text.

Page tabs

Figure 7 Page tabs

Each page displays a different type of list box. The first displays a list box similar to ListView1, demonstrating how little needs to change to incorporate that entity within a more complex application. The list box content creation code is modified slightly to demonstrate the usage of separators.

// Add a captioned separator.
lbData=model.NewDataLC(MQikListBoxModel::EDataSeparator);
iEikonEnv->ReadResourceL(bb,R_STR_LIST_SEPARATOR_1);
lbData->AddTextL(bb,MQikListBoxData::EDefaultSlot);
CleanupStack::PopAndDestroy(lbData);
// Adding a plain separator.
lbData=model.NewDataLC(MQikListBoxModel::EDataSeparator);
CleanupStack::PopAndDestroy(lbData);

The second page displays a text only list box. The example has added some left and right margins to illustrate potential usage of QIK_LISTBOX_ROW_VIEW fields.

RESOURCE QIK_LISTBOX_ROW_VIEW r_app_listview_listbox2_view
  {
  left_margin=8;                       // Add 8 pixel margins.
  right_margin=8;
  }

We also introduce the usage of two layouts within the same list box; the first layout is used for regular entries, the second for the highlighted entry.

RESOURCE QIK_LISTBOX_LAYOUT_PAIR r_app_listbox2_layout_pair
  {
  standard_normal_layout = EQikListBoxLine;
  standard_highlight_layout = EQikListBoxTwoLines;
  }

List box with highlight

List box with highlight

Figure 8 List box with highlight can have a different layout

Here, the row containing the highlight is displayed using two lines of content. This facilitates the display of additional content about the highlighted entry without significantly reducing the number of items that are visible within a screen full of information.

Pages three to ten present examples of the other standard list box types. The application code demonstrates how you go about setting up the icons and text fields displayed by each of the different list boxes. The following table shows all list box styles and in which tab you will find each in ListView2. (For example, 1 means Tab 1; 2H means the highlighted row in Tab 2) We have populated all text and icons in the top row; in other rows we show that you can leave text or icons blank.

List box Style Tab Name and Contents
EQikListBoxLine 1 EQikListBoxLine

Text1

EQikListBoxTwoLines 2H EQikListBoxTwoLines

Text1

Text2

EQikListBoxIconLine 3 EQikListBoxIconLine

Icon and text

EQikListBoxLineIcon 2 EQikListBoxLineIcon

Text1, Icon1

EQikListBoxIconLineIcon 4 EQikListBoxIconLineIcon

Icon1, Text1, Icon2

EQikListBoxIconIconLine 4H EQikListBoxIconIconLine

Icon1, Icon2, Text

EQikListBoxLineIconIcon 5 EQikListBoxLineIconIcon

Text, Icon1, Icon2

EQikListBoxIconLineIconIcon 5H EQikListBoxIconLineIconIcon

Icon, text, icon, icon

EQikListBoxIconHalfLineHalfLine 6 EQikListBoxIconHalfLineHalfLine

Icon, Text1, Text2

EQikListBoxIconHalfLineHalfLineLine 6H EQikListBoxIconHalfLineHalfLineLine

Icon, Text1, Text2

Text 3

EQikListBoxIconTwoLines 7 EQikListBoxIconTwoLines

Icon, Text1

Text2

EQikListBoxIconIconTwoLines 7H EQikListBoxIconIconTwoLines

Icon1, Icon2, Text1

Text2

EQikListBoxMediumIconTwoLines 3H EQikListBoxMediumIconTwoLines

MediumIcon1, Text1

Text2

EQikListBoxMediumThumbTwoLines 8 EQikListBoxMediumThumbTwoLines

Thumbnail1, Text1

Text2

EQikListBoxCheckLineSwappingLine 9 EQikListBoxCheckLineSwappingLine

Checkbox, Text1

Line with swappable content

EQikListBoxCheckLineIconLine 10 EQikListBoxCheckLineIconLine

Checkbox, Text1

Icon, Text2

Figure 9 Types of list box layout

Pages eleven and twelve present examples of custom created list boxes; these are discussed later.

Creating and Initializing List Boxes

Compared to ListView1, this example creates and initializes the list boxes within the ViewConstructL() method instead of the ViewActivatedL() method. This clearly requires more resources to be used when our view is not displayed, that is, when the view is ViewDeactivated() but some applications need to maintain contextual information when you switch between views. For example, if you display the details of a list item then switch back to the list, it is desirable that the list box highlights the item for which you displayed the details. If you remove all items from the list box when the view is ViewDeactivated() and re-construct the list box when the view is ViewActivatedL(), as we did in ListView1, you need to supply an external mechanism to track the originally selected item. This example shows that the list box can perform that task if required.

void CAppSpecificListView::ViewConstructL()
  {
  ViewConstructFromResourceL(R_LIST_VIEW_CONFIGURATIONS); 
  CQikViewBase::SetZoomFactorL(CQikAppUi::ZoomFactorL(iEngine->ListViewZoomState(),*iEikonEnv));
 
  AddItemsToList1L();
  AddItemsToList2L();
  AddItemsToList3L();
  AddItemsToList4L();
  AddItemsToList5L();
  AddItemsToList6L();
  AddItemsToList7L();
  AddItemsToList8L();
  AddItemsToList9L();
  AddItemsToList10L();
  AddItemsToList11L();
  AddItemsToList12L();
  }
 
void CAppSpecificListView::ViewDeactivated()
  {
 
  // No code required.
  }
 
void CAppSpecificListView::ViewActivatedL(
  const TVwsViewId& aPrevViewId,
  const TUid aCustomMessageId,
  const TDesC8& aCustomMessage)
  {
 
  // No code required.
  }

By setting up the list boxes in the ViewConstructL() method, the list boxes are constructed once during the lifetime of the application. Consequently, it is quite reasonable to move the text resource, loading directly into the list box creation code, compared to an engine supplying the text. This is particularly true of the UIQ 3 platform since the list boxes own a copy of the content.

Pro tip:

In general it is desirable to push functionality into an engine, even if that functionality is associated with displaying content, hence ListView1 preferring to store and supply the list view content from an engine object. The ListView1 and ListView2 examples merely demonstrate various choices need to be made appropriate to your application requirements.

ItemIds

Entries added to a list box for display are usually derived from a data structure maintained elsewhere within an application. In that respect our example applications are somewhat unusual. Since items within a list box can be re-ordered; for example, if the list box is sorted, any one-to-one correspondence between list box entries and alternate data structure may not be permanently maintained. By allowing the list box entries to be assigned an ID, in this case a 32-bit number; a link between the two structures can be maintained. It is up to the individual application to generate these unique IDs. While sounding difficult, this can be as simple as assigning the index value used when creating the list box entries, as demonstrated by the following code:

void CAppSpecificListView::AddItemsToList2L()
  {
  CQikListBox* listbox = LocateControlByUniqueHandle<CQikListBox>(EAppSpecificListViewListId2);
  MQikListBoxModel& model(listbox->Model());
  model.ModelBeginUpdateLC();
  TBuf<KMaxListItemText>bb;
  for (TInt i=0;i<KListView2Items;i++)
    {
    MQikListBoxData* lbData = model.NewDataL(MQikListBoxModel::EDataNormal);
    CleanupClosePushL(*lbData);
    iEikonEnv->ReadResourceL(bb,R_STR_LIST_CONTENT_1+i);
    lbData->AddTextL(bb,EQikListBoxSlotText1);
    iEikonEnv->ReadResourceL(bb,R_STR_LIST_DETAILS_1+i);
    lbData->AddTextL(bb,EQikListBoxSlotText2);
    lbData->SetItemId(i);
    CleanupStack::PopAndDestroy(lbData);
    }
  model.ModelEndUpdateL();
  }
Pro tip:

If you plan to have add and delete type functionality then the simple scheme mentioned above is unlikely to be adequate. In this case you will usually have to generate and store a unique ID in your engine code so you can translate between items being displayed on screen and the corresponding engine entries.

Slots

We use a set of standard enums to specify the content that is displayed in a list box, rather than dealing with any list box specific structure. The full list is defined by TListBoxStdLayoutSlots. The ListView1 example only displays a single line of text placed in EQikListBoxSlotText1. In ListView2, the list boxes on the second and third pages display up to two lines of text. Irrespective of whether the list box displays icons or not the text is assigned to EQikListBoxSlotText1 and EQikListBoxSlotText2. The text in slot two is only displayed when the second text line is visible.

EQikListBoxMediumIconTwoLines

Figure 10 EQikListBoxMediumIconTwoLines

On the third page the small icon is placed in the EQikListBoxSlotLeftSmallIcon1 while the larger icon is placed in the EQikListBoxSlotLeftMediumIcon1. The list box determines which content to display at runtime.

The following code, simplified slightly from the actual example code, shows text and icons being added to various slots within a list box.

void CAppSpecificListView::AddItemsToList3L()
  {
  CQikListBox* listbox = LocateControlByUniqueHandle<CQikListBox>(EAppSpecificListViewListId3);
  MQikListBoxModel& model(listbox->Model());
  model.ModelBeginUpdateLC();
  TBuf<KMaxListItemText>bb;
  for (TInt i=0;i<KListView2Items;i++)
    {
    MQikListBoxData* lbData = model.NewDataL(MQikListBoxModel::EDataNormal);
    CleanupClosePushL(*lbData);
 
    // Add text to slots.
    iEikonEnv->ReadResourceL(bb,R_STR_LIST_CONTENT_1+i);
    lbData->AddTextL(bb,EQikListBoxSlotText1);
    iEikonEnv->ReadResourceL(bb,R_STR_LIST_DETAILS_1+i);
    lbData->AddTextL(bb,EQikListBoxSlotText2);
 
    // Add small icons to slots.
    CQikContent* icon = CQikContent::NewL(NULL, KMbmFile, EMbmListview2Icon0, EMbmListview2Icon0mask);
    CleanupStack::PushL(icon);
    lbData->AddIconL(icon,EQikListBoxSlotLeftSmallIcon1);
    CleanupStack::Pop(icon);
 
    // Add medium icons to slots.
    icon = CQikContent::NewL(NULL, KMbmFile, EMbmListview2Largeicon0, EMbmListview2Largeicon0mask);
    CleanupStack::PushL(icon);
    lbData->AddIconL(icon,  EQikListBoxSlotLeftMediumIcon1);
    CleanupStack::Pop(icon);     // lbData taken ownership.
    CleanupStack::PopAndDestroy(lbData);
    }
  model.ModelEndUpdateL();
  }

Slots are defined by the creator of the resource structure describing a particular list box. For the pre-defined list box types, you only need to know which data is associated with which slot and where that is displayed. The example application provides that information. If you create custom list boxes, as described later, you become the resource creator. You therefore decide what slots are defined and where they are displayed.

Each slot may have multiple elements associated with it. By default the first element added to a slot will be displayed. Usually, you would assign multiple elements to a slot if you need to display different content depending on the internal state of your application. As an alternative, it is possible to construct a list box where the user can switch between the different elements, a so called content swapping list box. Examples of such list boxes are presented by r_list_view_page9_control and r_list_view_page12_control, the latter being a custom list box.

Content-swapping list box EQikListBoxCheckLineSwappingLine

Figure 11 Content-swapping list box EQikListBoxCheckLineSwappingLine

The code to add items to page nine is:

void CAppSpecificListView::AddItemsToList9L()
  {
  CQikListBox* listbox=LocateControlByUniqueHandle<CQikListBox>(EAppSpecificListViewListId9);
  MQikListBoxModel& model(listbox->Model());
  model.ModelBeginUpdateLC();
  TBuf<KMaxListItemText>bb;
  for (TInt i=0;i<KListView2Items;i++)
    {
    MQikListBoxData* lbData = model.NewDataL(MQikListBoxModel::EDataNormal);
    CleanupClosePushL(*lbData);
 
    // This listbox has two lines of data.
    iEikonEnv->ReadResourceL(bb,R_STR_LIST_CONTENT_1+i);
    lbData->AddTextL(bb,EQikListBoxSlotText1);
 
    // We swap between items in the second line.
    iEikonEnv->ReadResourceL(bb,R_STR_LIST_ALT_TEXT_1+i);
    lbData->AddTextL(bb,EQikListBoxSlotText2);
    iEikonEnv->ReadResourceL(bb,R_STR_LIST_DETAILS_1+i);
    lbData->AddTextL(bb,EQikListBoxSlotText2);
    CleanupStack::PopAndDestroy(lbData);
    }
  model.ModelEndUpdateL();
  }

You should be able to see two items being added to EQikListBoxSlotText2. The following screen shot shows how the content would be presented to the user.

Content-swapping list box in a view

Figure 12 Content-swapping list box in a view

Since EQikListBoxSlotText2 allows content swapping, the user can change the display between the content associated with the slot.

TabActivatedL(TInt aTabId)

Often there is a requirement to know when the user navigates between the pages presented by an application. The TabActivatedL() method is called when the current page is changed; the parameter indicates the page that is made active.

void CAppSpecificListView::TabActivatedL(TInt aTabId)
  {
 
  // Display info message saying which tab is activated.
  TBuf<128>bb;
  if (aTabId==EAppSpecificListViewPageId1)
    iEikonEnv->Format128(bb,R_STR_TAB_ACTIVATED_INFO,1);
  else if (aTabId==EAppSpecificListViewPageId2)
    iEikonEnv->Format128(bb,R_STR_TAB_ACTIVATED_INFO,2);
  else if (aTabId==EAppSpecificListViewPageId3)
     iEikonEnv->Format128(bb,R_STR_TAB_ACTIVATED_INFO,3);
  else
              ……
 
  if (bb.Length())
    iEikonEnv->InfoMsg(bb);
 
  // Let base class perform its work.
  CQikMultiPageViewBase::TabActivatedL(aTabId);
  }

Custom List Boxes

In tabs eleven and twelve, ListView2 introduces the ability to define custom list boxes. At the simplest level you can choose between numerous combinations of standard_normal_layout and standard_highlight_layout to produce various effects. The list boxes displayed on pages eleven and twelve of our example demonstrates how to construct highly customized list boxes.

Anatomy of a List Box

From a high level perspective a list box starts with a single column of content. The column can then be broken into one or more rows of content. Each of those rows can be further broken down into columns. This process can continue to form an arbitrary depth tree like structure but in practice it is unlikely to go more than a few levels deep.

If you consider the EQikListBoxIconLine list box, at the highest level there is a single column of content, the list box. Each element in the column comprises a single row, the rows in the list box. The single row contains two columns, one for the icon and the other for the text component. The icon and text components complete the tree so no further items are required.

Dividing by row and column to create EQikListBoxIconLine

Figure 13 Dividing by row and column to create EQikListBoxIconLine

In contrast, EQikListBoxCheckLineSwappingLine has two rows, each broken in to a different number of columns:

Dividing by row and column to create EQikListBoxCheckLineSwappingLine

Figure 14 Dividing by row and column to create EQikListBoxCheckLineSwappingLine

Grid List Box

A grid list box is created using a custom layout. While there is a slightly different interpretation to the above for grid like list boxes, the general principles are the same.

A grid list box starts with a single column containing the content. In the case of the grid, the column is interpreted as an individual grid cell. The column can be broken down into a set of rows. If required, each row can be further broken into columns, and so on.

Dividing up a grid list box

Figure 15 Dividing up a grid list box

Page eleven of ListView2 displays a grid list box. Each cell in the grid consists of an icon displayed above some text. Mapping that onto the previous description you should see that we have a single column or grid cell. Each element in that column comprises two rows. No further sub-division is required to display our content so we have reached the end of the hierarchy.

Our grid is described by the following resource code:

RESOURCE QIK_LISTBOX_LAYOUT r_app_list11_custom_layout
  {
  flags = 0;
  columns =
    {
    QIK_LISTBOX_COLUMN
      {
      type = QIK_LISTBOX_PARENT_TYPE;
      width_type = EQikListBoxColWidthGrab;
      slot_id = EQikListBoxSlotParent1;
      rows =
        {
        QIK_LISTBOX_ROW
          {
          type = QIK_LISTBOX_ICON_TYPE
            {
                size=EQikListBoxSizeMediumIcon;
            };
          height_type=EQikListBoxRowHeightGrab;
          height_value=1;
          slot_id=EQikListBoxSlotLeftMediumIcon1;
          },
        QIK_LISTBOX_ROW
          {
          type = QIK_LISTBOX_TEXT_TYPE
            {
            alignment=EQikListBoxTextAlignCenter;
            font_size=EQikListBoxFontSmall;
            };
          height_type =
           EQikListBoxRowHeightFromContentType;
          height_value=1;
          slot_id=EQikListBoxSlotText1;
          }
        };
      }
    };
  }

You should be able to identify the two rows; one containing the icon and one containing the text. The two rows belong to a parent or containing column element. You should be able to see where the slot IDs are being defined. When you come to populate your list box the slot ID values you have assigned the individual components will be used to set the content.

In order for the list box to correctly display as a grid there is one other important field to configure: the flags. By default list boxes are said to be row aware. We need to disable this for grids. This is achieved by setting the flags to zero.

Content Swapping List Box

A second example of custom list box design is displayed on page twelve of the ListView2 example. The list box is a single column. Each element in the column is a single row. The single row has four columns, the left and right arrows, an icon and some text.

Content-swapping list box

Figure 16 Content-swapping list box

The resource defining the content swapping list box is:

RESOURCE QIK_LISTBOX_LAYOUT r_app_list12_custom_layout
  {
  columns =
    {
    QIK_LISTBOX_COLUMN
      {
      type = QIK_LISTBOX_PARENT_TYPE;
      slot_id = EQikListBoxSlotParent1;          
      rows =
        {
        QIK_LISTBOX_ROW
          {
          type = QIK_LISTBOX_PARENT_TYPE;
          slot_id = EQikListBoxSlotParent2;  
          columns=
                       {
                       QIK_LISTBOX_COLUMN
              {
              type = QIK_LISTBOX_LEFT_ARROW_TYPE
                           {
                           slots_to_swap =
                             {
                             EQikListBoxSlotLeftSmallIcon1,
                              EQikListBoxSlotText1
                             };
                           };
              width_type =
               EQikListBoxColWidthFromContentType;
              slot_id = EQikListBoxSlotLeftArrow1;
              },
                       QIK_LISTBOX_COLUMN
              {
              type = QIK_LISTBOX_ICON_TYPE
                {
                           size=EQikListBoxSizeSmallIcon;
                           };
                         width_type =
               EQikListBoxColWidthFromContentType;
               slot_id = EQikListBoxSlotLeftSmallIcon1;
              },
            QIK_LISTBOX_COLUMN
              {
              type = QIK_LISTBOX_TEXT_TYPE;
              width_type = EQikListBoxColWidthGrab;
              width_value = 1;
              slot_id = EQikListBoxSlotText1;
              },
            QIK_LISTBOX_COLUMN
              {
              type = QIK_LISTBOX_RIGHT_ARROW_TYPE
                {
                slots_to_swap =
                             {
                   EQikListBoxSlotLeftSmallIcon1,
                    EQikListBoxSlotText1
                      };                              
                };
              width_type=
               EQikListBoxColWidthFromContentType;
                         slot_id = EQikListBoxSlotRightArrow1;
              }
            };                   
          }  
        };
      }
    };
  }

This example demonstrates the ability for a single row to swap between multiple pieces of information. When data is added to the list box, up to two icons and two pieces of text are added to each slot. By default the first item added to a slot is displayed, that is, the content at index 0 of the slot. Tapping the left or right arrows changes the current slot index, causing alternative content to be displayed.

Content-swapping in ListView2

Content-swapping in ListView2

Figure 17 Content-swapping in ListView2 page twelve

The Contacts application makes good use of the content-swapping capability of EQikListBoxCheckLineSwappingLine:

Content-swapping in Contacts list view

Content-swapping in Contacts list view

Content-swapping in Contacts list view

Figure 18 Content-swapping in Contacts list view

The user can select the required telephone number directly in the list view and then dial it.

When constructing grid list boxes or list boxes containing items that can be swapped it is important to understand what happens to left and right arrow keys, particularly in the context of multi-page views.

In pen-enabled configurations, the user can freely decide whether to tap a page tab and select a page, or the arrow tab in a content swapping list box to select alternative content.

In softkey only configurations, the left and right keys are used for both actions. Where the content swapping list box has focus, it will consume the arrow key command and change the content. The user will not be able to change page. We therefore recommended that content swapping list boxes should not be part of a multi-page design in commercial applications.

Code

Code for this chapter

ListBoxes_code.zip
Personal tools
code download