Layout managers and building blocks
From UIQ Books
Contents |
Layout Managers and Building Blocks
Layout Managers
Layout managers were introduced in UIQ 3 to assist in the layout of controls. We have already used layout managers in our example applications. In ListView2 we specify the type and details for a row layout manager in the resource file:
RESOURCE QIK_CONTAINER_SETTINGS r_list_view_page1_control
{
layout_manager_type = EQikRowLayoutManager;
layout_manager = r_row_layout_manager_default;
controls =
{
QIK_CONTAINER_ITEM_CI_LI
{
unique_handle = EAppSpecificListViewListId1;
type = EQikCtListBox;
control = r_app_listview_listbox;
layout_data = r_row_layout_data_fill;
}
};
}
UIQ 3 defines four layout manager types:
enum TQikStockLayoutManagers
{
EQikGridLayoutManager,
EQikRowLayoutManager,
EQikFlowLayoutManager,
EQikColumnLayoutManager
};
Visually the layout managers present content like this:
Figure 1 Types of layout manager
The layout_manager field references a resource whose type depends on the layout_manager_type:
Layout_manager_type
| Properties |
|---|---|
EQikGridLayoutManager
| Places controls in a grid; each cell in the grid is the same size. |
EQikRowLayoutManager
| Places controls in a row, one control per row. |
EQikFlowLayoutManager
| Places controls end to end in rows, breaking the rows when a control cannot fit in the remaining space within a row. |
EQikColumnLayoutManager
| Positions controls on a single row, then aligns additional controls to create the appearance of columns. |
The LayoutManager1 example application shows a simple example of row and grid layout managers in use.
The example application has two pages:
RESOURCE QIK_CONTAINER_SETTINGS r_page1_control
{
layout_manager_type = EQikGridLayoutManager;
layout_manager = r_grid_layout_manager;
controls =
{
.. list of controls
};
}
RESOURCE QIK_CONTAINER_SETTINGS r_page2_control
{
layout_manager_type = EQikRowLayoutManager;
layout_manager = r_row_layout_manager;
controls =
{
.. list of controls
};
}
The grid layout references a resource:
RESOURCE QIK_GRID_LAYOUT_MANAGER r_grid_layout_manager
{
// This app has decided to have 3 columns.
columns = 3;
default_layout_data = QIK_GRID_LAYOUT_DATA
{
horizontal_alignment = EQikLayoutHAlignCenter;
};
}
While the row layout references:
RESOURCE QIK_ROW_LAYOUT_MANAGER r_row_layout_manager
{
default_layout_data = QIK_ROW_LAYOUT_DATA
{
// Align items to centre of the display region.
horizontal_alignment = EQikLayoutHAlignCenter;
// 8 pixels to left, item not on display edge.
left_margin= 8;
};
}
The layout of the entire application is handled by the resource definitions; there is no application-specific software required.
Figure 2 LayoutManager1 page one (grid manager) and page two (row manager)
Most applications do not need to use layout managers directly; instead they use building blocks that tend to hide the usage of layout mangers.
Building Blocks
To date we have concentrated on list boxes. While they provide a wealth of functionality, there are a number of other standard controls that applications may wish to use to capture input or display content.
In the same way that you might construct a house with components such as walls, windows and doors, you can construct an application view from a set of software components. These components need to be flexible enough to produce the desired results but rigid enough to still fit together. In a UIQ 3 application, these software components are called building blocks.
Building blocks are designed to aid the creation and display of views that retain consistency across the range of UIQ 3 phones. Building blocks are in many ways like compound controls, however, they also add significant functionality, which we will discuss.
Building blocks differ from standard compound controls in that they have attributes such as margins, alignment and size. They also integrate closely with the UIQ 3 layout managers such that much of the work associated with presenting controls on different mobile phones is handled automatically by the framework. Layout managers were introduced in UIQ 3 to assist in the layout of controls. Prior to UIQ 3, an application would present a variety of controls to the user and manage the layout of those controls in a rather ad hoc, application-specific manner. You can find more on layout managers in the UIQ 3 SDK.
The following diagram shows you how a view may be constructed using building blocks (it may, alternatively, be constructed using controls directly):
Figure 3 Constructing a view using building blocks
Note that:
- the view is made up building blocks
- each building block contains a number of slots
- each slot can hold one control.
You may place any control you like within a slot but you need to ensure the application presents data sensibly. For example, placing an icon into a long thin slot or a date editor into a tall, narrow, multi-line slot would be inappropriate.
A large number of building blocks are supplied as standard but if they are insufficient for your application you can create your own, either using resources or programmatically.
The standard building blocks are defined by the following extract from the standard UIQ 3 control set, found in qikstockcontrols.hrh:
enum TQikStockControls
{
EQikCtOnelineBuildingBlock,
EQikCtCaptionedTwolineBuildingBlock,
EQikCtTwolineBuildingBlock,
EQikCtManylinesBuildingBlock,
EQikCtIconOnelineBuildingBlock,
EQikCtIconCaptionedTwolineBuildingBlock,
EQikCtIconTwolineBuildingBlock,
EQikCtOnelineIconBuildingBlock,
EQikCtIconOnelineIconBuildingBlock,
EQikCtIconTwolineIconBuildingBlock,
EQikCtMediumThumbnailDoubleOnelineBuildingBlock,
EQikCtLargeThumbnailThreelineBuildingBlock,
EQikCtCaptionedOnelineBuildingBlock,
EQikCtIconCaptionedOnelineBuildingBlock,
EQikCtTwolineIconBuildingBlock,
EQikCtIconIconOnelineBuildingBlock,
EQikCtHalflineHalflineBuildingBlock,
EQikCtCaptionedHalflineBuildingBlock,
};
The following diagram shows you each building block in more detail. A building block can take one or two controls. These are placed in ItemSlot1 and, where available, ItemSlot2. Some building blocks also have one or two slots for icons:
Figure 4 Key to IconSlots
EQikCtOnelineBuildingBlock
| EQikCtIconTwolineIconBuildingBlock
| |
EQikCtCaptionedTwolineBuildingBlock
| EQikCtMediumThumbnailDoubleOnelineBuildingBlock
| |
EQikCtTwolineBuildingBlock
| EQikCtLargeThumbnailThreelineBuildingBlock
| |
EQikCtManylinesBuildingBlock
| EQikCtCaptionedOnelineBuildingBlock
| |
EQikCtIconOnelineBuildingBlock
| EQikCtIconCaptionedOnelineBuildingBlock
| |
EQikCtIconCaptionedTwolineBuildingBlock
| EQikCtTwolineIconBuildingBlock
| |
EQikCtIconTwolineBuildingBlock
| EQikCtIconIconOnelineBuildingBlock
| |
EQikCtOnelineIconBuildingBlock
| EQikCtHalflineHalflineBuildingBlock
| |
EQikCtIconOnelineIconBuildingBlock
| EQikCtCaptionedHalflineBuildingBlock
|
Figure 5 System building blocks
BuildingBlocks1 Example Application
In the BuildingBlocks1 application, we will construct a view that has three controls, each of which is a building block. Almost the entire application is defined by its resources. The key resource to understand is as follows:
RESOURCE QIK_CONTAINER_SETTINGS r_page_control
{
controls =
{
QIK_CONTAINER_ITEM_CD_LI
{
type = EQikCtOnelineBuildingBlock;
control = QIK_SYSTEM_BUILDING_BLOCK
{
flags = EQikBuildingBlockDividerBelow;
content =
{
QIK_SLOT_CONTENT
{
slot_id = EQikItemSlot1;
caption = "One line building block.";
}
};
};
},
QIK_CONTAINER_ITEM_CD_LI
{
type = EQikCtTwolineBuildingBlock;
control = QIK_SYSTEM_BUILDING_BLOCK
{
content =
{
QIK_SLOT_CONTENT_INDIRECT
{
slot_id = EQikItemSlot1;
type = EEikCtLabel;
itemflags = EQikCtrlFlagIsFocusing;
control= r_indirect_two_line_building_block;
}
};
};
},
QIK_CONTAINER_ITEM_CD_LI
{
type = EQikCtManylinesBuildingBlock;
control = QIK_SYSTEM_BUILDING_BLOCK
{
content =
{
QIK_SLOT_CONTENT_DIRECT
{
slot_id = EQikItemSlot1;
type = EEikCtLabel;
itemflags = EQikCtrlFlagIsFocusing;
control = LABEL
{
standard_font = EEikLabelFontAnnotation;
txt = "Many line building blocks wrap text
across as many lines as is required
to display the text.";
};
}
};
};
}
};
}
You can easily see each control from the QIK_CONTAINER_ITEM_CD_LI elements in the code. The control data is defined inline and the layout information is defined by reference. In this example the control data is defined by a QIK_SYSTEM_BUILDING_BLOCK. There is no additional layout information; that field is omitted.
The application looks like this:
Figure 6 BuildingBlocks1 application
Each of the QIK_CONTAINER_ITEM_CD_LI comprises a different type of building block. This example uses the following building blocks:
EQikCtOnelineBuildingBlock
| |
EQikCtTwolineBuildingBlock
| |
EQikCtManylinesBuildingBlock
|
|
Each building block is described by a QIK_SYSTEM_BUILDING_BLOCK structure:
STRUCT QIK_SYSTEM_BUILDING_BLOCK
{
BYTE version = 2;
LONG flags = 0;
LTEXT default_caption = "";
STRUCT content[];
}
The values that can be assigned to the flags field are:
-
EQikBuildingBlockDividerBelow. This causes a dividing line to be displayed below a building block. Our example displays a dividing line between the first and subsequent building blocks. -
EQikBuildingBlockMirror. This flag indicates that the building block slots should be mirrored, that is, instead of running left-to-right they run right-to-left. For example, for a building block having an icon on the left and text on the right, the icon would be displayed to the right and the text to the left. -
EQikBuildingBlockNoMirroring.When applications are run on mobile phones that present content in a right-to-left order, compared to typical European left-to-right order, this flag indicates whether the building block should obey the system mirroring requirements. -
EQikBuildingBlockDebugMode. When set, the building block will draw a black outline around itself. This makes it easier to see if your controls are laid out correctly when developing your application.
The content of each building block is described by one of three possible resource structures:
STRUCT QIK_SLOT_CONTENT
{
BYTE struct_type = 0;
LONG slot_id = -1;
LONG unique_handle = -1;
LTEXT caption = "";
}
STRUCT QIK_SLOT_CONTENT_INDIRECT
{
BYTE struct_type = 1;
LONG slot_id = -1;
LONG unique_handle = -1;
LONG itemflags = 0;
LONG type = -1;
LLINK control = 0;
}
STRUCT QIK_SLOT_CONTENT_DIRECT
{
BYTE struct_type = 2;
LONG slot_id = -1;
LONG unique_handle = -1;
LONG itemflags = 0;
LONG type = -1;
STRUCT control;
}
Which of the three structures you choose depends on what information you have and which feature set you wish to use. We use one of each type in BuildingBlocks1 to give you an example of all three.
struct_type
This defines which structure type is being used. It should be left as is.
slot_id
This field informs the software with which slot the resource description should be associated. For our first example, the system building blocks only have a single slot identified by EQikItemSlot1, defined in qikon.hrh. When you use the system building blocks that are provided with UIQ 3, the number and type of slots, and how they are referenced, is predefined.
unique_handle
A control has a unique value, or handle, associated with it. If the application is using a collection of controls, as opposed to defining the controls inline, this value is used to determine which QIK_CONTROL from the collection is to be used. The value only needs to be unique within a view but in practice, its value is taken from your application-specific enum lists and is often unique within your application.
The unique_handle is also used if you need to reference the control from your application, for example, to set up its initial value or collect the user data.
caption
This field is only defined in the QIK_SLOT_CONTENT and is a shorthand way of defining text content to be associated with the slot. If no caption is defined, the unique_handle field should reference a control from a control collection.
itemFlags
This contains a set of flags from the following list:
-
EQikCtrlFlagIsFocusing. The control can take focus. Controls that take focus usually do so to indicate that the user can change their content. In our example we have used the flag on a text only item, which is somewhat unusual. Focus is often indicated with a highlight, the highlight normally moves between those controls that can take focus. -
EQikCtrlFlagIsNonFocusing. The control does not take focus. In general controls that don’t take focus cannot have their content changed. A highlight will not normally move to items with this flag set. -
EQikCtrlFlagIsEditInPlace. For some controls such as a text editor, a pop-out type control is typically used to perform content editing. This flag indicates that the inline control will perform that task instead. -
EQikCtrlFlagIsNonEditInPlace. For some controls the actual control is normally used to perform content editing. This flag indicates a pop-out type control should be used instead.
You should take care when using the edit in place and non-edit in place flags. In particular you should ensure that a user is able to navigate around controls that are presented to them, irrespective of whether they are using a soft key or touchscreen type mobile phone.
type
This field indicates the control type from the set of stock controls the control field will reference, and is used to indicate how the control field should be interpreted. The type values for stock controls are contained in the TEikStockControls and TQikStockControls enum lists.
control
This contains either a reference to or the actual resource associated with the control indicated by the type field. In our example both the type fields contain EEikCtLabel. This control needs to describe a resource of type LABEL. For a QIK_SLOT_CONTENT_INDIRECT it is a reference to a resource of that type. For a QIK_SLOT_CONTENT_DIRECT it is the LABEL resource itself.
BuildingBlocks2 Example Application
For reference, we have created a second example application, BuildingBlocks2. We will not discuss it further here since it simply extends the previous example to illustrate a multi-page application that demonstrates the use of each of the standard building blocks listed by the TQikStockControls enum.
As in BuildingBlocks1, the controls are restricted to simple icons and text to minimize the complexity and help focus on the usage of each of the standard building block types. This is a good example to help you investigate the suitability of each of the building blocks for your particular application. Here is a screen shot of BuildingBlocks2:
Figure 7 BuildingBlocks2 application
BuildingBlocks3 Example Application
The two previous examples have demonstrated how to define and use, at a basic level, the standard building blocks in UIQ 3. While the ability to display icons and/or text is important there are a number of other controls that are equally useful in real world applications. You may recall from the earlier description of building blocks that you can place any control within a slot. This example shows how you can go about placing a wide variety of system controls within building block slots to construct highly functional applications with minimal effort.
Figure 8 BuildingBlocks3 application
The screen shot above shows three choice lists: a check box, a slider and a button control.
Controls are not only used to display information but also to capture user input. To achieve this, an application needs to interact with the controls, for example, to set them to a specific value when first viewed, or to collect information from them when it is entered by a user.
Page one presents three choice lists. The first fully defines the entries within the resource:
QIK_SLOT_CONTENT_DIRECT
{
slot_id = EQikItemSlot1;
type = EEikCtChoiceList;
itemflags = EQikCtrlFlagIsFocusing;
control = CHOICELIST
{
array_id = r_page1_choicelist_array;
};
}
RESOURCE ARRAY r_page1_choicelist_array
{
items=
{
LBUF {txt="Choice 1";},
LBUF {txt="Choice 2";},
LBUF {txt="Choice 3";}
};
}
The second and third require the application-specific software to set up the list box items.
The following resource fragment shows the declaration of an empty choice list. It also shows how the example application obtains a reference to the underlying control, in this case a CEikChoiceList, by using the same value used by the unique_handle field. You should note the importance of the unique_handle field:
QIK_SLOT_CONTENT_DIRECT
{
slot_id = EQikItemSlot2;
type = EEikCtChoiceList;
itemflags = EQikCtrlFlagIsFocusing;
unique_handle = EAppChoiceList1;
control = CHOICELIST
{
};
}
The code fragment below shows how to reference the choice list object created by the UIQ 3 framework:
// Create and initialize a choice list. iAppChoiceList=new(ELeave)CChoiceListArray; // Tell list box control about choice list. CEikChoiceList* cl = LocateControlByUniqueHandle<CEikChoiceList>(EAppChoiceList1); cl->SetArrayL(iAppChoiceList);
You may notice the use of a templated entity LocateControlByUniqueHandle. When controls are created by interpreting the resource information or, more precisely, the type field of the QIK_SLOT_CONTENT, a control of the required type is created. You may recall that all controls derive from the CCoeControl base class. When the framework stores the created object handles, it does so as a set of CCoeControl objects. When specific controls need to be manipulated, it is often the case that you need to convert back from the stored CCoeControl type into the real object type. This is what LocateControlByUniqueHandle<>() is used for.
The following table brings together the control types, their resource structures and the equivalent C++ object.
| Control type | Resource type | C++ object type |
|---|---|---|
EEikCtCommandButton
| CMBUT
| CEikCommandButton
|
EEikCtEdwin
| EDWIN
| CEikEdwin
|
EEikCtRichTextEditor
| RTXTED
| CEikRichTextEditor
|
EEikCtSecretEd
| SECRETED
| CEikSecretEditor
|
EEikCtCheckBox
| CHECKBOX
| CEikCheckBox
|
EEikCtChoiceList
| CHOICELIST
| CEikChoiceList
|
EEikCtOptionButton
| OPBUT
| CEikOptionButton
|
EEikCtHorOptionButList
| HOROPBUT
| CEikHorOptionButtonList
|
EEikCtListBox
| LISTBOX
| CEikListBox
|
EEikCtImage
| IMAGE
| CEikImage
|
EEikCtLabel
| LABEL
| CEikLabel
|
EEikCtComboBox
| COMBOBOX
| CEikComboBox
|
EEikCtProgInfo
| PROGRESSINFO
| CEikProgressInfo
|
EEikCtGlobalTextEditor
| GTXTED
| CEikGlobalTextEditor
|
EEikCtClock
| CLOCK
| CEikClock
|
EEikCtCalendar
| CALENDAR
| CEikCalendar
|
EEikCtTextButton
| TXTBUT
| CEikTextButton
|
EEikCtBitmapButton
| BMPBUT
| CEikBitmapButton
|
EEikCtTwoPictureCommandButton
| PICMBUT
| CEikTwoPictureCommandButton
|
EEikCtLabeledCheckBox
| LABELEDCHECKBOX
| CEikLabeledCheckBox
|
EQikCtVertOptionButtonList
| QIK_VERTOPBUT
| CQikVertOptionButtonList
|
EQikCtSoundSelector
| QIK_SOUND_SELECTOR
| CQikSoundSelector
|
EQikCtTimeEditor
| QIK_TIME_EDITOR
| CQikTimeEditor
|
EQikCtDateEditor
| QIK_DATE_EDITOR
| CQikDateEditor
|
EQikCtTimeAndDateEditor
| QIK_TIME_AND_DATE_EDITOR
| CQikTimeAndDateEditor
|
EQikCtDurationEditor
| QIK_DURATION_EDITOR
| CQikDurationEditor
|
EQikCtColorSelector
| QIK_COLOR_SEL
| CQikColorSelector
|
EQikCtSlider
| QIK_SLIDER
| CQikSlider
|
EQikCtNumberEditor
| QIK_NUMBER_EDITOR
| CQikNumberEditor
|
EQikCtFloatingPointEditor
| QIK_FLOATING_POINT_EDITOR
| CQikFloatingPointEditor
|
EQikCtIpEditor
| QIK_IP_EDITOR
| CQikIpEditor
|
The following code fragment taken from the example application ViewConstructL() method demonstrates how we set controls to contain default values:
// Locate the check box and ensure it is set. CEikCheckBox* cb = LocateControlByUniqueHandle<CEikCheckBox>(EAppCheckbox1); cb->SetState(CEikButtonBase::ESet); // Locate the slider and set a default value. CQikSlider* sl = LocateControlByUniqueHandle<CQikSlider>(EAppSlider1); sl->SetValue(21); // Locate the edwins and set a default value. _LIT(KSomeText,”Some text”); TBuf<16> text(KSomeText); CEikEdwin* edwin = LocateControlByUniqueHandle<CEikEdwin>(EAppEdwin1); edwin->SetTextL(&text); _LIT(KOtherText,”Other text”); text=KOtherText; edwin=LocateControlByUniqueHandle<CEikEdwin>(EAppEdwin2); edwin->SetTextL(&text); // Locate the number editor and set a default value. CQikNumberEditor* numEd = LocateControlByUniqueHandle<CQikNumberEditor>(EAppEdwin4); numEd->SetValueL(21); // Locate the floating point editor and set a default value. CQikFloatingPointEditor* fltEd = LocateControlByUniqueHandle<CQikFloatingPointEditor>(EAppEdwin5); fltEd->SetValueL(21.21); // Locate and set the IP editor to a default value. CQikIpEditor* ipEd = LocateControlByUniqueHandle<CQikIpEditor>(EAppEdwin6); _LIT(K10203040,” 10.20.30.40”); ipEd->SetIpAddress(K10203040); // Locate and set the time & date editor to a default value. CQikTimeAndDateEditor* dtEd = LocateControlByUniqueHandle<CQikTimeAndDateEditor>(EAppDateTime3); TTime time; time.HomeTime(); // Default value is now. dtEd->SetTimeL(time); // Locate and set the duration editor to a default value. CQikDurationEditor* durEd = LocateControlByUniqueHandle<CQikDurationEditor>(EAppDateTime4); durEd->SetDurationL(1200); // 1200 secs = 1200/60 mins = 20 mins.
Edit in Place and Control Stand-ins
When we place controls on a page, it is important to ensure that the user can still navigate around using the standard mechanism provided by the mobile phone, especially in Softkey Style UI configuration. For example, if a phone contains a four-way navigation key, a user would expect to be able to move through pages using left and right keys and move vertically though the list of controls with the up and down keys.
Some controls, such as a choice list, require use of the Up and Down keys to enable the user to choose an item. Other controls, such as a text editor, require the use of Left and Right keys to move a cursor around the text. It is very important that controls do not consume the navigation keys. If this happens, the user is unlikely to be able to navigate around the application.
To support these conflicting requirements, controls tend not to be edit in place. To select a choice list item or change the text within an editor you need to pop out the control.
Figure 9 Choice list stand-in and control
This is how the framework operates; even though you have specified that you wish to have an EEikCtChoiceList or EEikCtEdwin control, a replacement or stand-in control is created and is displayed in its place. It is only when a user chooses to change the content that a control of the correct type is displayed. The user interacts with the control, which can now consume any navigation keys, until the user completes the operation. The stand-in and real control co-operate such that any changes are displayed correctly when the operation completes.
Figure 10 Text editor stand-in and control
| Pro tip:
You should use care when distinguishing between the PC keyboard arrow keys and the four-way navigation keys displayed on the emulator skin. When testing applications on the emulator you should always click on the four-way navigation key images to determine what will happen on a real mobile phone. |
Code
Code for this chapter
LayoutManagersAndBuildingBlocks_code.zip



















