|
|
|
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.
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.
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.
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
}
};
}
};
}
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.
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.
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.
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
}
};
}
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).
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.
width_type
TQikListBoxColumnSizeType behaviors explanation:
EQikListBoxColWidthFromContentType
The column will be as wide as the content width is calculated to be.
Be careful when the content type is text and the text might be user-supplied data, since a very long
user-supplied string might make the column use the entire available width, giving no free width to columns using EQikListBoxColWidthGrab
width_type.
EQikListBoxColWidthGrab
This type will make the column grab a portion of the free remaining width.
Free remaining width is the width available when fixed size columns, columns using width_type
EQikListBoxColWidthFromContentType or EQikListBoxColWidthPixels, have been laid out.
When using EQikListBoxColWidthGrab, width_value defines the width ratio between EQikListBoxColWidthGrab columns.
EQikListBoxColWidthPixels
Will make a column as wide in pixels as width_value defines.
EQikListBoxColWidthFromChildTree
This type is only applicable when the column is a parent to row elements. Will make the column as wide as the widest child row. No width limitations are imposed on the rows, instead a bottom-to-top calculation is made.
height_type
TQikListBoxRowSizeType behaviors explanation:
EQikListBoxRowHeightFromContentType
The row will be as high as the content's height is calculated to be. In case of a row aware layout this means snapping the height to a multiple of the system row height as well.
EQikListBoxRowHeightGrab
This type makes the row grab a portion of the available height, making it very usable in layouts to be used in Grid Views.
EQikListBoxRowHeightPixels
Will make a row as high in pixels as height_value defines. Overriden in a row aware layout.
EQikListBoxRowHeightFromChildTree
Only applicable when the row is parent to columns. This will make the row as high as the highest child column. No height limitations are imposed on the columns, instead a bottom-to-top calculation is made.
height_type
TQikListBoxLayoutSizeType behaviors explanation:
EQikListBoxLayoutHeightFill
Works together with the height the List Box View in use reports as its Cell Size height, in the sense that the layout will be set to be as high as this value.
EQikListBoxLayoutHeightPixels
Forces a layout to be as high in pixels as height_value defines. Could be applicable in custom built views, but should not be used in List box built in views.
EQikListBoxLayoutHeightFromColumns
Makes the layout as high as its columns are calculated to be. Should always be used in a list box using row view.
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.
left_edge_to_content
The gap between the List Box View's left edge to the left-most column.
right_edge_to_content
The minimum gap between the List Box View's right edge to the right-most column.
column_gap
The gap between adjacent columns.
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.
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;
}
};
}
};
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.
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;
}
};
}
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.
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;
}
};
}
};
}