UIQ Technology
 Developer Library

UIQ 3 SDK

UIQ developer portal

FEEDBACK 

[Index] [Spacer] [Previous] [Next]



UIQ Controls - List Box - Custom Layouts


1. Introduction

The List Box Introductionary Guide introduces the List Box control and explains the basics of getting a List Box (CQikListBox) up and running. The List Box Features Guide explains many of the List Box features. This guide shows how to create custom List Box Layouts using Resource files. It is possible, but not recommended, to create Custom Layouts using C++ code as well.

The List Box is an extensive control providing a great deal of functionality through various classes. Data items are created in the List Box Model and information is updated, removed and added to these data items. The view takes each currently visible data item, and the Layout associated with it, and creates a view item that visually represents the data item. These view items are arranged and presented on screen by the view.

The List Box comes with a set of pre-created Layouts, called Standard Layouts. These Layouts provide some common ways to display data in an item, without each application developer having to create them over and over again. When there is no Standard Layout that fits an application's needs, custom Layouts can be created.


1.1 Further Reference

Before reading this guide, read List Box Introductionary Guide and List Box Features Guide.

See the API documentation for List Box (CQikListBox).

See the List Box Standard Layouts Listing.

[Top]


2. Defining Custom Layouts

Custom Layouts are created by using the Layout struct (QIK_LISTBOX_LAYOUT):

STRUCT QIK_LISTBOX_LAYOUT
    {
    BYTE version =                                      1;
    LONG flags =                                            EQikListBoxDefault;
    BYTE multiple_selection_area_orientation =  EQikListBoxDefault;
    LONG multiple_selection_area_slot =             EQikListBoxDefault;
    BYTE left_edge_to_content =                         EQikListBoxDefault;
    BYTE right_edge_to_content =                        EQikListBoxDefault;
    BYTE column_gap =                                   EQikListBoxDefault;
    BYTE height_type =                                  EQikListBoxDefault;
    WORD height_value =                                     EQikListBoxDefault;
    STRUCT columns[];
    }

Most properties have a default value of EQikListBoxDefault, which will make the List Box load default values for those properties when created.


2.1 Columns and Rows

The very core of the layout struct is the columns[] element, which makes up the structure of the layout. The layout is built up by columns and rows, using the QIK_LISTBOX_COLUMN and QIK_LISTBOX_ROW structs.

CQikListBoxColumn and CQikListBoxRow are derived from CQikListBoxLayoutElement, and are therefore often referred to as elements, or layout elements.

A column can contain either rows or content. A row can contain either columns or content. An element containing other elements is called a parent element, and is not allowed to directly contain content.

In the following code column #2 is parent to row #1 and row #2. Column #1, row #1 and row #2 are elements that would contain content:

RESOURCE QIK_LISTBOX_LAYOUT r_my_layout
    {
    // layout properties not explicitly changed
    // would be loaded with default values
    columns =
        {
        QIK_LISTBOX_COLUMN // column #1
            {
            // column properties
            },
        QIK_LISTBOX_COLUMN      // column #2
            {
            // column properties (no content allowed)
            rows =
                {
                QIK_LISTBOX_ROW // row #1
                    {
                    // row properties
                    },  
                QIK_LISTBOX_ROW // row #2
                    {
                    // row properties
                    }   
                };
            }
        };
    }


2.2 Content Type

Every element needs to define its content type. The content type denotes what kind of data the element can display, or in the case of a parent, that it is a parent element. Each content type has it own struct defining the content type's properties and features.

The different content types available are QIK_LISTBOX_PARENT_TYPE, QIK_LISTBOX_TEXT_TYPE, QIK_LISTBOX_ICON_TYPE and QIK_LISTBOX_THUMBNAIL_TYPE.

Extending r_my_layout with content types:

RESOURCE QIK_LISTBOX_LAYOUT r_my_layout
    {
    // layout properties not explicitly changed
    // would be loaded with default values
    columns =
        {
        QIK_LISTBOX_COLUMN // column #1
            {
            type =
                QIK_LISTBOX_ICON_TYPE
                    {
                    // icon type properties
                    };
            // other column properties
            },
        QIK_LISTBOX_COLUMN      // column #2
            {
            type = QIK_LISTBOX_PARENT_TYPE;
            // other column properties
            rows =
                {
                QIK_LISTBOX_ROW // row #1
                    {
                    type =
                        QIK_LISTBOX_TEXT_TYPE
                            {
                            // text type properties
                            };                  
                    // other row properties
                    },  
                QIK_LISTBOX_ROW // row #2
                    {
                    type =
                        QIK_LISTBOX_TEXT_TYPE
                            {
                            // text type properties
                            };                  
                    // other row properties
                    }   
                };
            }
        };
    }

The layout now consists of a column containing an icon, followed by a column that is split into two rows each containing text.


2.3 Slot ID

Slot IDs are used for mapping data to a position in a layout where the data will appear. Each column and row must be assigned a slot ID. All slot IDs must be zero or higher and be unique within each layout. Slot IDs are preferably specified as an enumeration to make it easier to reference them in code. It is recommended to use the slot IDs defined in TListBoxStdLayoutSlots to make mixing of custom and standard layouts as easy as possible.

Adding slot IDs to each element in r_my_layout:

RESOURCE QIK_LISTBOX_LAYOUT r_my_layout
    {
    // layout properties not explicitly changed
    // would be loaded with default values
    columns =
        {
        QIK_LISTBOX_COLUMN // column #1
            {
            type =
                QIK_LISTBOX_ICON_TYPE
                    {
                    // icon type properties
                    };
            slot_id = EQikListBoxSlotLeftSmallIcon1;
            // other column properties
            },
        QIK_LISTBOX_COLUMN      // column #2
            {
            type = QIK_LISTBOX_PARENT_TYPE;
            slot_id = EQikListBoxSlotParent1;           
            // other column properties
            rows =
                {
                QIK_LISTBOX_ROW // row #1
                    {
                    type =
                        QIK_LISTBOX_TEXT_TYPE
                            {
                            // text type properties
                            };
                    slot_id = EQikListBoxSlotText1;                 
                    // other row properties
                    },  
                QIK_LISTBOX_ROW // row #2
                    {
                    type =
                        QIK_LISTBOX_TEXT_TYPE
                            {
                            // text type properties
                            };
                    slot_id = EQikListBoxSlotText2;                 
                    // other row properties
                    }   
                };
            }
        };
    }

Adding some data, that would be displayed in the rows:

CMyClass::AddSomeDataL(const TDesC& aText, const TDesC& aOtherText)
    {
    MQikListBoxModel& model(iMyListBox->Model());
    model.ModelBeginUpdateLC();
        
    // Add text to EQikListBoxSlotText1 and EQikListBoxSlotText2
    MQikListBoxData* data = model.NewItemLC(MQikListBoxModel::EDataNormal);
    data->AddTextL(aText, EQikListBoxSlotText1);
    data->AddTextL(aOtherText, EQikListBoxSlotText2);    
    CleanupStack::PopAndDestroy(data);

    model.ModelEndUpdateL();
    }

Slot IDs are not only used to map data to elements, but can also be used to get a pointer to a specific element. Such a pointer allows for changing an element's properties or the properties of element's contents. All elements, even parent elements, must be assigned a slot ID, and all slot IDs must be unique within the layout; duplicates are not allowed.


2.4 Content Type Sizing

The content of an element does not need to be of the exact same size as the element containing it. To size content of type icon or thumbnail it is possible to set a logical size to them. The logical sizes are defined in TQikListBoxContentTypeLogicalSize. The values that have something like "Small", "Medium" or "Large" in their names tend to be mapped directly to a fixed pixel size (EQikListBoxSizeSmallIcon could for example be mapped to 18*18 pixels), while the others denote some sort of behavior, for example, EQikListBoxSizeThumbnailFill will make the thumbnail scale to always fill its containing element.

Sizing an icon within a column:

// Column taken out of context, must in
// practice be a part of a layout resource
QIK_LISTBOX_COLUMN // column #1
    {
    type =
        QIK_LISTBOX_ICON_TYPE
            {
            size = EQikListBoxSizeSmallIcon;
            // other icon type properties
            };
    slot_id = EQikListBoxSlotLeftSmallIcon1;
    // other column properties
    }

Note that the column itself does not yet have a size defined. This code is only an example of how content can be sized.


2.5 Layout and Element Sizing

To present information well, sizing of the different elements in the layout, and in some cases the sizing of the layout itself, is important. The struct elements of interest are:

STRUCT QIK_LISTBOX_LAYOUT
    {
    BYTE height_type = EQikListBoxDefault;
    BYTE height_value = EQikListBoxDefault;
    // other properties
    }

STRUCT QIK_LISTBOX_COLUMN
    {
    BYTE width_type = EQikListBoxDefault;
    BYTE width_value = EQikListBoxDefault;
    // other properties
    }

STRUCT QIK_LISTBOX_ROW
    {
    BYTE height_type = EQikListBoxDefault;
    BYTE height_value = EQikListBoxDefault;
    // other properties 
    }

The width_type and height_type properties defines how, and from where, an element (and layout) will get its size. For some types the width_value or height_value is also applicable, for others it is disregarded. The size types available for layout, column and row are defined in TQikListBoxLayoutSizeType, TQikListBoxColumnSizeType, and TQikListBoxRowSizeType.

As seen in the structs, width can only be set on columns while height is set on rows, and the layout, only. All rows within a column will be set to have the full width of the column. All columns within a row are set to the same height, the height of the row.

All elements with content will calculate the width and height of that content. Some width_type and height_type types will make the element be of the same width or height as it has calculated its content to be, other types will make the element be of other size.

The width_type and height_type determines whether a top-to-bottom or bottom-to-top calculation will be used on an element (or the layout). A top-to-bottom calculation would mean that a parent element sets, or at least limits, the sizes of its child elements. In a bottom-to-top calculation the size of a parent element depends on the sizes of its child elements. On this matter the layout itself can be seen as a top level row, but with a special set of height types.

The layout's default height_type, EQikListBoxLayoutHeightFromColumns, imposes no height limit on its child columns. Instead, the child columns' sizes are calculated, and the layout's height will be set to the height of the highest column; all columns are then set to have the same height.

In the example below the layout uses the default height_type. The column is set to grab the entire free width, which will be as wide as the List Box View control allows it to be. Since the column has no height limitations forced upon it by the layout, the content type will be calculated and the height propagated upwards to the layout, which will be set to be of this height. If the icon's size is set to be EQikListBoxSizeSmallIcon, and that would map into 18*18 pixels, the end result will be an item that is 18 pixels in height and taking the full width of the control:

RESOURCE QIK_LISTBOX_LAYOUT r_layout
    {
    // use default values for all layout properties, so no need to
    // redefine them here.
    columns =
        {
        QIK_LISTBOX_COLUMN
            {
            type =
                QIK_LISTBOX_ICON_TYPE
                {
                size = EQikListBoxSizeSmallIcon;
                // other icon type properties
                };
            width_type = EQikListBoxColWidthGrab;
            width_value = 1;
            slot_id = EQikListBoxSlotLeftSmallIcon1;
            // other column properties          
            }
        };
    }


2.6 Row Awareness

Row awareness in a layout means that it will always take on a height that is a multiple of the system row height. Row awareness is a layout property, enabled by default. Row awareness works together with the logical content sizes to make sure that a List Box looks good across different phones. The system row height, content logical sizes, and font sizes may differ between phones but are designed to work together under row awareness.

Row awareness is a means to get Row Views to look good, but is not intended to be enabled in layouts to be used in Grid Views.

All layouts used in row views should be row aware to make applications look uniform.

In the previous example it was stated that if the icon's size was set to EQikListBoxSizeSmallIcon, hypothetically mapped to 18*18 pixels, 18 pixels was the height propagated upwards to the layout. This is not entirely true, since the layout in this example would have row awareness enabled by default. When row aware, an element will calculate the height of its content, then snap the height to the nearest higher multiple of the system row height before propagating the height upwards to the layout.

When row aware, some settings of the layout and rows might get overridden. If, for instance, setting a row's height_type to EQikListBoxRowHeightPixels and width_type to 20 in a row aware layout, that row would not be 20 pixels high, but in practice have a height that is the nearest higher multiple of the system row height (assuming the system row height is not 20 pixels).

[Top]


3. Element Sizing Types Explained

Further explanation can be found in the API documentation on the different behaviorsfor column, row and layout sizing. Be sure to read the enumeation documentation as well, TQikListBoxLayoutSizeType, TQikListBoxColumnSizeType and TQikListBoxRowSizeType.


3.1 Column width_type

TQikListBoxColumnSizeType behaviors explanation:


3.2 Row height_type

TQikListBoxRowSizeType behaviors explanation:


3.3 Layout height_type

TQikListBoxLayoutSizeType behaviors explanation:

[Top]


4. Layout Gaps

Three horizontal gaps are used in a List Box Layout. These gaps are used to space content. To make Row List Boxes look uniform, these gaps should not be changed in Row View Layouts but it is often necessary to change them in Grid View Layouts.

[Top]


5. Row View Layout Examples


5.1 Two Text Rows

The following example creates a two line layout, showing how to use a column to make two rows occupy the entire available width. This is actually the standard layout mapped to EQikListBoxTwoLines.

EQikListBoxTwoLines in use

EQikListBoxTwoLines in use

The properties of the layout itself are not changed, default values are used.

As stated before, the default height_type of the layout imposes no limitations on the column, instead a bottom-to-top calculation will be made. Since the column has no adjacent columns and width_type is EQikListBoxColWidthGrab, it will grab the entire width. The column's child rows will be set to be as wide as the column.

The rows are both set to use height_type EQikListBoxRowHeightFromContentType. In the case of text type rows this means the font height. Since the layout is row aware, the rows' heights will be set to the nearest multiple of the system row height. The column will be set to be as high as the sum of its child rows' heights. The layout will then be set to the height of its column. The end result is an item that is occupying the entire width, with two rows, each as high as the current system row height.

RESOURCE QIK_LISTBOX_LAYOUT r_layout_two_lines
    {
    columns=
        {
        QIK_LISTBOX_COLUMN
            {
            type=QIK_LISTBOX_PARENT_TYPE;
            width_type=EQikListBoxColWidthGrab;
            width_value=1;
            slot_id=EQikListBoxSlotParent1;
            rows=
                {
                QIK_LISTBOX_ROW
                    {
                    type=QIK_LISTBOX_TEXT_TYPE;
                    height_type=EQikListBoxRowHeightFromContentType;
                    slot_id=EQikListBoxSlotText1;
                    },
                QIK_LISTBOX_ROW
                    {
                    type=QIK_LISTBOX_TEXT_TYPE;
                    height_type=EQikListBoxRowHeightFromContentType;
                    slot_id=EQikListBoxSlotText2;
                    }
                };
            }
        };


5.2 Two Icons and a Text String

This example creates a layout that has the system row height, showing two icons followed by a short text string. This is actually the Standard Layout mapped to EQikListBoxIconIconLine.

EQikListBoxIconIconLine in use

EQikListBoxIconIconLine in use

The layout imposes no height limitations upon the columns, instead, the layout will be set to the height of the highest column. If, hypothetically, the system row height is 27 pixels, a small icon is 18*18 pixels, and the font height is 22 pixels, all columns will set to be 27 pixels high.

Both the first and second column will be as wide as a small icon is. The third column will grab the rest of the available width. Having at least one column that uses grab will make the layout adapt to changes in available pixels nicely.

RESOURCE QIK_LISTBOX_LAYOUT r_layout_icon_icon_line
    {
    columns=
        {
        QIK_LISTBOX_COLUMN
            {
            type=QIK_LISTBOX_ICON_TYPE{size=EQikListBoxSizeSmallIcon;};
            width_type=EQikListBoxColWidthFromContentType;
            slot_id=EQikListBoxSlotLeftSmallIcon1;
            },
        QIK_LISTBOX_COLUMN
            {
            type=QIK_LISTBOX_ICON_TYPE{size=EQikListBoxSizeSmallIcon;};
            width_type=EQikListBoxColWidthFromContentType;
            slot_id=EQikListBoxSlotLeftSmallIcon2;
            },
        QIK_LISTBOX_COLUMN
            {
            type=QIK_LISTBOX_TEXT_TYPE;
            width_type=EQikListBoxColWidthGrab;
            width_value=1;
            slot_id=EQikListBoxSlotText1;
            }
        };
    }

[Top]


6. Grid View Layout Examples


6.1 Thumbnail with Short Text

A Grid View is divided into cells by columns and rows. The number of cells can be changed at run time, by changing the number of columns or rows, which results in the cell size being changed as well. Due to this a dynamic layout, that automatically fills the entire cell, is often the preferable choice when using Grid View.

Grid View showing items using example la...

Grid View showing items using example layout

For starters, we disable row awareness of the layout by setting the flag's property to 0. This is done since a grid cell is so limited in both width and height that we do not want the extra empty space row awareness would inflict.

Next, the height type of the layout itself is changed from default to EQikListBoxLayoutHeightFill. This will make the layout and resulting item always use the entire height available to it; in a grid view this means the entire cell height.

The orientation and placement of the selector is changed, since leaving it on default, check mark in a column left of the content, would make the check mark occupy valuable space not usable by the content. The orientation sets the check mark to appear in the top left corner of the element defined to have the slot ID supplied. This means that the check mark will be drawn in front of the thumbnail image.

Edge to content gaps are set to 0 to not waste valuable width; changing these properties overrides the default behavior of getting the values from system settings.

Since we want the layout to dynamically size itself to both the available height, done by setting the height type of the layout, and width, the next step is to create a parent column that makes its child rows be as wide as the available width, grid cell width, this is done by using width_type EQikListBoxColWidthGrab. The parent column also has margins set all around it; without margins the thumbnail would fill the entire row hiding the drawn highlight beneath it.

The next step is to create two rows. The first one will have thumbnail content, showing the thumbnail as large as possible, while the second row will show a text (center aligned and small), under the thumbnail. The second row is set to use height_type EQikListBoxRowHeightFromContentType, making it as high as the font used. The first row is set to use height_type EQikListBoxRowHeightGrab, taking all the available height left when the second row has been sized.

This way, a dynamic layout has been made that always will occupy the entire Cell Size available - growing or shrinking as the size of the cell changes.

RESOURCE QIK_LISTBOX_LAYOUT r_grid_listbox_layout
    {
    flags = 0;
    height_type=EQikListBoxLayoutHeightFill;
    multiple_selection_area_orientation =   EQikListBoxMultipleSelectionSlotTopLeft;
    multiple_selection_area_slot = EQikListBoxSlotLargeThumbnail1;
    left_edge_to_content = 0;
    right_edge_to_content = 0;
    columns =
        {
        QIK_LISTBOX_COLUMN
            {
            type=QIK_LISTBOX_PARENT_TYPE;
            width_type=EQikListBoxColWidthGrab;
            width_value=1;
            top_margin = 2;
            bottom_margin = 2;
            left_margin = 2;
            right_margin = 2;
            slot_id=EQikListBoxSlotParent1;
            rows =
                {
                QIK_LISTBOX_ROW
                    {
                    type=QIK_LISTBOX_THUMBNAIL_TYPE {size=EQikListBoxSizeThumbnailFill;};
                    height_type=EQikListBoxRowHeightGrab;
                    height_value=1;
                    slot_id=EQikListBoxSlotLargeThumbnail1;
                    },
                QIK_LISTBOX_ROW
                    {
                    type=QIK_LISTBOX_TEXT_TYPE{alignment=EQikListBoxTextAlignCenter;font_size=EQikListBoxFontSmall;};
                    height_type=EQikListBoxRowHeightFromContentType;
                    height_value=1;
                    slot_id=EQikListBoxSlotText1;
                    }
                };
            }
        };
    }

Terms and conditions of use of the material