|
|
|||
This guide explains the UIQ control Custom Building Blocks (CQikGenericBuildingBlock). A building block is a compound control used to layout the controls in a view. A view can consist
of multiple building blocks. Each building block has a defined layout and a certain number of slots where controls
or captions can be inserted.
UIQ provides a set of System Building Blocks that can be used by application developers. See the How To guide for System Building Blocks.
If none of the System Building Blocks fits the purpose of the application developer, it is possible to create Custom Building Blocks. This should, however, only be a last resort when no System Building Block fits the purpose.
For each column in a Custom Building Block, there are a number of settings available:
Slot ID, which must be unique within the building block,
Excess space grab weight, which determines how excess space is distributed when the columns have reached their minimum size,
Horizontal and vertical alignment,
Horizontal margins,
Vertical margins, which are disregarded when placed in row-based views,
Maximum number of slots, which determines how many copies of a slot are allowed,
Auto wrapping, which only affects controls that are MQikRowAwareControl, informs the control if it should automatically wrap if it does not fit horizontally,
Number of visible lines, which only affects controls that are MQikRowAwareControl, informs the control how many lines of text to show before it truncates,
Control internal alignment, which only affects controls that are MEikAlignedControl, informs the control how to align its content within its given extent,
Fixed width and/or height, the number of rows in row-based views, determines if the building block should use the control's own MinimumSize(), or a fixed value,
The following functionality can be used by the application developer:
Set the caption in any of the slots,
Set the control in any of the slots,
Accessing the controls and captions,
Set how the building block handles mirroring, that is, force no mirroring, force mirroring or follow the application language,
Set if a divider is shown below the building block,
Set if the control can gain focus or not.
Default control configuration.
By default, the following configuration applies to a Custom Building Block:
Follows the mirroring of the application language,
Has no divider,
The control cannot gain focus.
By default, the following configuration applies to the caption labels:
Normal system font is used,
Text emphasis is not used,
Text underlining is not used,
Text strikethrough is not used.
Default configuration for a specific control depends on the control itself.
See the API documentation for Custom Building Blocks (CQikGenericBuildingBlock).
Before using Custom Building Blocks, see if there is a System Building Block that could be used instead. See the How To guide for System Building Blocks for an overview of System Building Blocks.
See even the API documentation for System Building Blocks (CQikBuildingBlock).
Custom Building Blocks inherits from System Building Blocks, CQikBuildingBlock, which inherits from CCoeControl.
This section explains how the control is constructed, used and destroyed. Source code examples are used and explained to illustrate how Custom Building Blocks are used.
For Custom Building Blocks use the following #include directive:
#include <QikGenericBuildingBlock.h>
Use the following LIBRARY directive in the project's mmp-file:
LIBRARY qikctl.lib
Use the following identifier when specifying Custom Building Blocks in resource data files.
The ID is defined in QikStockControls.hrh, and used by the framework when constructing the Custom Building Block from resource data:
EQikCtGenericBuildingBlock
The resource to use is defined by the QIK_GENERIC_BUILDING_BLOCK
structs, defined in Qikon.rh. The structs look like this:
STRUCT QIK_GENERIC_BUILDING_BLOCK
{
BYTE version = 2; //don't change
LONG flags = 0;
LTEXT default_caption = "";
LONG group_id = -1;
STRUCT columns[]; //QIK_GENERIC_BUILDING_BLOCK_COLUMN
STRUCT content[]; //QIK_SLOT_CONTENT
}
STRUCT QIK_GENERIC_BUILDING_BLOCK_COLUMN
{
LONG slot_id = -1;
STRUCT rows[]; //QIK_GENERIC_BUILDING_BLOCK_ROW
BYTE grabweight = 0;
BYTE horizontal_alignment = EQikLayoutHAlignInherit; //TQikLayoutHorizontalAlignment
BYTE vertical_alignment = EQikLayoutVAlignInherit; //TQikLayoutVerticalAlignment
BYTE left_margin = 0;
BYTE right_margin = 0;
BYTE top_margin = 0;
BYTE bottom_margin = 0;
BYTE max_num = 1; //this feature might be removed in the future
BYTE auto_wrapping = 1;
BYTE number_of_visible_lines = 0;
BYTE control_internal_alignment = EQikAlignHLeftVCenter; //TQikBuildingBlockControlInternalAlignment
BYTE fixed_width = -1;
BYTE fixed_height = -1;
}
STRUCT QIK_GENERIC_BUILDING_BLOCK_ROW
{
LONG slot_id = -1;
BYTE allow_columns_to_break_row = 0;
STRUCT columns[]; //QIK_GENERIC_BUILDING_BLOCK_COLUMN
BYTE grabweight = 0;
BYTE horizontal_alignment = EQikLayoutHAlignInherit; //TQikLayoutHorizontalAlignment
BYTE vertical_alignment = EQikLayoutVAlignInherit; //TQikLayoutVerticalAlignment
BYTE left_margin = 0;
BYTE right_margin = 0;
BYTE top_margin = 0;
BYTE bottom_margin = 0;
BYTE max_num = 1; //this feature might be removed in the future
BYTE auto_wrapping = 1;
BYTE number_of_visible_lines = 0;
BYTE control_internal_alignment = EQikAlignHLeftVCenter; //TQikBuildingBlockControlInternalAlignment
BYTE fixed_width = -1;
BYTE fixed_height = -1;
}
STRUCT QIK_SLOT_CONTENT
{
BYTE struct_type = 0; //do not change
LONG slot_id = -1;
LONG unique_handle = -1;
LTEXT caption = "";
}
STRUCT QIK_SLOT_CONTENT_DIRECT
{
BYTE struct_type = 2; //do not change
LONG slot_id = -1;
LONG unique_handle = -1;
LONG type = -1;
LONG itemflags = 0;
STRUCT control;
}
STRUCT QIK_SLOT_CONTENT_INDIRECT
{
BYTE struct_type = 1; //do not change
LONG slot_id = -1;
LONG unique_handle = -1;
LONG type = -1;
LONG itemflags = 0;
LLINK control = -1;
}
The values given in the struct definition are default values. The QIK_GENERIC_BUILDING_BLOCK
struct contains the following:
version is always 2 and cannot be changed,
flags is used to customize the control and the available flags are defined in qikon.hrh and listed below,
default_caption is the default caption of the System Building Block,
group_id is the ID of the group,
columns is a struct of type QIK_GENERIC_BUILDING_BLOCK_COLUMN
content is a struct of type QIK_SLOT_CONTENT, QIK_SLOT_CONTENT_DIRECT or QIK_SLOT_CONTENT_INDIRECT.
The QIK_GENERIC_BUILDING_BLOCK_COLUMN
struct contains the following:
slot_id is the ID of the slot,
rows is a struct of type QIK_GENERIC_BUILDING_BLOCK_ROW.
grabweight, which is used to determine how extra space is divided between the columns, is relative, which means, for example, that two controls that have a grab weight of three and six, one gets a third, and the other two thirds of the extra space,
horizontal_alignment is the horizontal alignment of the building block column as specified by TQikLayoutHorizontalAlignment,
vertical_alignment is the vertical alignment of the building block column as specified by TQikLayoutVerticalAlignment,
left_margin is the left margin of the building block column,
right_margin is the right margin of the building block column,
top_margin is the top margin of the building block column,
bottom_margin is the bottom margin of the building block column,
max_num is the maximum number of slots,
auto_wrapping turns on auto wrapping when set to 1 and turns it off when set to 0,
number_of_visible_lines, the number of visible lines in the building block column, is unlimited when set to 0,
control_internal_alignment,
sets the internal alignment of a control which is an MEikAlignedControl,
to guide the control where to position its contents. The alignment is specified by values defined in the type
TQikBuildingBlockControlInternalAlignment,
fixed_width supports the logical size, in pixels, of layout managers,
fixed_height supports the logical size, in pixels, of layout managers.
The QIK_GENERIC_BUILDING_BLOCK_ROW
struct contains the following:
slot_id is the ID of the slot,
allow_columns_to_break_row, when set to 1, allows columns to break the row,
columns is a struct of type QIK_GENERIC_BUILDING_BLOCK_COLUMN,
grabweight, which is used to determine how extra space is divided between the columns, is relative, which means, for example, that two controls that have a grab weight of three and six, one gets a third, and the other two thirds of the extra space,
horizontal_alignment is the horizontal alignment of the building block column as specified by TQikLayoutHorizontalAlignment,
vertical_alignment is the vertical alignment of the building block column as specified by TQikLayoutVerticalAlignment,
left_margin is the left margin of the building block column,
right_margin is the right margin of the building block column,
top_margin is the top margin of the building block column,
bottom_margin is the bottom margin of the building block column,
max_num is the maximum number of slots,
auto_wrapping turns on auto wrapping when set to 1 and turns it off when set to 0,
number_of_visible_lines, the number of visible lines in the building block column, is unlimited when set to 0,
control_internal_alignment,
sets the internal alignment of a control which is an MEikAlignedControl,
to guide the control where to position its contents. The alignment is specified by values defined in the type
TQikBuildingBlockControlInternalAlignment,
fixed_width supports the logical size, in pixels, of layout managers,
fixed_height supports the logical size, in pixels, of layout managers.
The QIK_SLOT_CONTENT
struct represents the content of a slot in a building block. It is referenced by QIK_GENERIC_BUILDING_BLOCK. Use this struct when the content of the slot is a caption, or the control is included in the QIK_CONTROL_COLLECTION, or the control factory only needs the unique handle to create the control. The struct contains the following:
struct_type is the type of the struct can not be changed. Must always be 0.
slot_id - the ID of the slot. Depends on the building block that is used, but is usually a value from TQikBuildingBlockSlots, defined in Qikon.hrh. The slot_id is mandatory.
unique_handle - the ID of the control is unique within the view. Is used to reference a specific QIK_CONTROL in the control collection, or to tell a control factory which control to create. Unique_handle is mandatory if no caption is specified.
caption - the caption of the slot, mandatory if no control is specified.
The QIK_SLOT_CONTENT_DIRECT
struct represents the content of a slot in a building block. Is referenced by QIK_GENERIC_BUILDING_BLOCK. Use this struct when you do not want to use a QIK_CONTROL_COLLECTION, and you want to reference the resource struct of the control through a link, or you want to create the control using resources. The struct contains the following:
struct_type, the type of the struct, is always 2 and cannot be changed,
slot_id, the ID of the slot, is mandatory and depends on which building block is used, but values are usually taken from TQikBuildingBlockSlots as defined in Qikon.hrh,
unique_handle, the ID of the control, is optional, is unique within the view and is used to set the control's UniqueHandle() and send it to the control factories,
type, the control type, such as the items in TQikStockControls as defined in QikStockControls.hrh, is mandatory,
itemflags, the optional flags from TQikCtrlItemFlags as defined in Qikon.hrh, control the creation of the control,
control, which is mandatory, is the resource struct that is read by the control's ConstructFromResourceL(), such as QIK_SLIDER for EQikCtSlider.
The QIK_SLOT_CONTENT_INDIRECT
struct represents the content of a slot in a building block. It is referenced by QIK_GENERIC_BUILDING_BLOCK. Use this struct when you do not want to use a QIK_CONTROL_COLLECTION, and you want to reference the resource struct of the control through a link, or you do not want to create the control using resources. The struct contains the following:
struct_type, the type of the struct, is always 1 and cannot be changed,
slot_id, the ID of the slot, is mandatory and depends on which building block is used, but values are usually taken from TQikBuildingBlockSlots as defined in Qikon.hrh,
unique_handle, the ID of the control, is optional, is unique within the view and is used to set the control's UniqueHandle() and send it to the control factories,
type, the control type, such as the items in TQikStockControls as defined in QikStockControls.hrh, is mandatory for controls created entirely from resource files, otherwise it depends on the control factories,
itemflags, the optional flags from TQikCtrlItemFlags as defined in Qikon.hrh, controls the creation of the control,
control, which is mandatory for controls created entirely from resource files, otherwise it depends on the control factories, is the resource struct that is read by the control's ConstructFromResourceL(), such as QIK_SLIDER for EQikCtSlider.
The Custom Building Blocks can have the following flags:
|
A common way to construct controls is to specify them in the resource files and then let the framework construct them from there. Specifying the controls in resource files is the preferred way of constructing controls since it allows for easier modifications compared to creating them entirely from source code.
This section covers different ways of constructing Custom Building Blocks.
There are two approaches to creating a Custom Building Block. You can either use CQikGenericBuildingBlock or subclass CQikBuildingBlock. If you subclass CQikBuildingBlock, you are on your own. If you want to use CQikGenericBuildingBlock, this is how you do it.
The example below describes how to construct a Custom Building Block, containing a Label control, using the view framework.
The reason the example seems to be rather complex is because it demonstrates how to construct a complete view containing a Scrollable Container and a Layout Manager. It also encapsulates a Label control in a Custom Building Block. The view supports both pen and softkey styles; support of both styles in a view is optional.
1) Declare an enumeration for the Custom Building Block and for the Label control to be used in the view in a *.hrh file. Hrh files are files to be included both in resource files (*.rss) and C++ files:
/* Declare the controls' ID in a *.hrh file for use both in resource and cpp */
enum TMyViewControls
{
EMyViewScrollableContainer,
EMyViewGenericBuildingBlock,
EMyViewLabel,
EMyViewIcon,
EMyViewNumberOfControls
};
2) Declare the controls to be used in the view in your resource (*.rss) file:
/* Declare the set of the Custom Building Block to be used in the view */
RESOURCE QIK_CONTROL_COLLECTION r_my_view_controls
{
items =
{
QIK_CONTROL
{
unique_handle = EMyViewScrollableContainer;
type = EQikCtScrollableContainer;
control = r_my_scroll_pane;
},
QIK_CONTROL
{
unique_handle = EMyViewLabel;
type = EEikCtLabel;
control = r_my_label;
},
QIK_CONTROL
{
unique_handle = EMyViewIcon;
type = EEikCtImage;
control = r_my_icon;
},
QIK_CONTROL
{
unique_handle = EMyViewGenericBuildingBlock;
type = EQikCtGenericBuildingBlock;
control = r_my_generic_building_block;
}
};
}
3) Define the view and its contents in your resource file:
/* The view */
RESOURCE QIK_VIEW r_my_view
{
pages = r_my_viewpages;
}
/* The view page */
RESOURCE QIK_VIEW_PAGES r_my_viewpages
{
pages =
{
QIK_VIEW_PAGE
{
container_unique_handle = EMyViewScrollableContainer;
page_content = r_my_view_container_details;
}
};
}
4) Define the resource for the Scrollable Container used in the view:
/* The scrollable container used in the view */
RESOURCE QIK_SCROLLABLE_CONTAINER r_my_scroll_pane
{
}
5) Declare the contents and properties for the Scrollable Container used in the view:
/* Contents of the Scrollable Container used in the view */
RESOURCE QIK_SCROLLABLE_CONTAINER_SETTINGS r_my_view_container_details
{
controls =
{
QIK_CONTAINER_ITEM
{
unique_handle = EMyViewGenericBuildingBlock;
}
};
}
6) Define the controls resource structs used in the view:
/* The Label used in the Building Block*/
RESOURCE LABEL r_my_label
{
flags=EUnderlining;
horiz_alignment=EEikLabelAlignVTop;
}
/* The Icon used in the Building Block*/
#define KImageFile "z:\\sys\\bin\\MyApp.mbm"
RESOURCE IMAGE r_my_icon
{
bmpfile = KImageFile;
bmpid = 11;
bmpmask = 12;
}
7) Define the settings for the Custom Building Block containing the control:
/* Settings for the Custom Building Block containing the Label control */
RESOURCE QIK_GENERIC_BUILDING_BLOCK r_my_generic_building_block
{
columns =
{
QIK_GENERIC_BUILDING_BLOCK_COLUMN
{
slot_id = EQikIconSlot1;
vertical_alignment = EQikLayoutVAlignTop;
control_internal_alignment = EQikAlignHCenterVCenter;
fixed_width = 1;
fixed_height = 1;
left_margin = 6;
right_margin = 3; //this right margin plus the next column’s left margin equals left_margin
top_margin = 1;
bottom_margin = 1;
},
QIK_GENERIC_BUILDING_BLOCK_COLUMN
{
slot_id = EQikSlotContainer1;
grabweight = 1;
rows =
{
QIK_GENERIC_BUILDING_BLOCK_ROW
{
slot_id = EQikItemSlot1;
horizontal_alignment = EQikLayoutHAlignFill;
number_of_visible_lines = 1;
left_margin = 3;
right_margin = 6;
top_margin = 1;
bottom_margin = 1;
},
QIK_GENERIC_BUILDING_BLOCK_ROW
{
slot_id = EQikItemSlot2;
horizontal_alignment = EQikLayoutHAlignFill;
number_of_visible_lines = 2;
left_margin = 3;
right_margin = 6;
top_margin = 1;
bottom_margin = 1;
}
};
}
};
content =
{
QIK_SLOT_CONTENT
{
slot_id = EQikIconSlot1;
unique_handle = EMyViewIcon;
},
QIK_SLOT_CONTENT
{
slot_id = EQikItemSlot1;
caption = "Caption";
},
QIK_SLOT_CONTENT
{
slot_id = EQikItemSlot2;
unique_handle = EMyViewLabel;
}
};
}
8) The configurations of the view:
RESOURCE QIK_VIEW_CONFIGURATIONS r_singlepageview_configurations
{
configurations=
{
QIK_VIEW_CONFIGURATION
{
ui_config_mode = KQikSoftkeyStylePortrait;
view = r_view_softkey_style_multi;
command_list = r_commands_task_menu;
},
QIK_VIEW_CONFIGURATION
{
ui_config_mode = KQikPenStyleTouchPortrait;
view = r_view_softkey_style_multi;
command_list = r_commands_task_menu;
}
};
}
9) The view framework constructs the view described in this example with this code:
void CMySinglePageView::ViewConstructL()
{
ViewConstructFromResourceL( R_SINGLEPAGEVIEW_CONFIGURATIONS, R_MY_VIEW_CONTROLS);
}
10) The result should look something like this:
The example below describes how to construct a Custom Building Block from resource with your own C++ code.
The reason the example seems to be rather complex is because it demonstrates how to construct a complete view containing a Scrollable Container and a Layout Manager. It also encapsulates a Label and an Icon control in a Custom Building Block.
This example uses the resource structs from the previous example.
The following code creates the Custom Building Block:
#include <QikGenericBuildingBlock.h>
#include <QikRowLayoutManager.h>
#include <QikGridLayoutManager.h>
#include <QikBuildingBlock.h>
void CMySinglePageView::ViewConstructL()
{
// Give a layout manager to the view
CQikGridLayoutManager* gl = CQikGridLayoutManager::NewLC();
SetLayoutManagerL(gl);
CleanupStack::Pop(gl);
// Create a container and give it to the view
ControlProvider()->ControlInfos().AddFromResourceL(R_MY_VIEW_CONTROLS);
CCoeControl* ctrl = ControlProvider()->ControlConstructIfNeededL(EMyViewScrollableContainer, *this);
ASSERT(ctrl);
CQikContainerBase* container;
ctrl->MopGetObjectNoChaining(container);
ASSERT(container);
Controls().AppendLC(container);
CleanupStack::Pop(ctrl);
// Create a layout manager to be used inside the container
CQikRowLayoutManager* rowlayout = CQikRowLayoutManager::NewLC();
container->SetLayoutManagerL(rowlayout);
CleanupStack::Pop(rowlayout);
// Create the Custom Building Block and add it to the container
CQikGenericBuildingBlock* block = new(ELeave) CQikGenericBuildingBlock;
container->AddControlLC(block, EMyViewGenericBuildingBlock);
TResourceReader blockReader;
iCoeEnv->CreateResourceReaderLC(blockReader, R_MY_GENERIC_BUILDING_BLOCK);
block->ConstructFromResourceL(blockReader, *ControlProvider());
block->SetUniqueHandle(EMyViewGenericBuildingBlock);
CleanupStack::PopAndDestroy(); //reader
CleanupStack::Pop(block);
}
What the code does
1) Initializes the Command Manager with an empty Command List. The controls placed in the view add their commands to the Command List when they receive focus.
2) Creates a Layout Manager for the view. The Grid Layout Manager fills the view with its only control in this example, the Scrollable Container.
3) Loads the control collection
R_MY_VIEW_CONTROLS into the Control Provider. Then the Control Provider is
asked to create the Scrollable Container.
4) Uses the MopGetObjectNoChaining function
to determine whether the control that was created really is a class of the type
CQikContainerBase before it is added to the view.
5) Creates a Layout Manager to control the layout inside the container. Adds the Layout Manager to the container.
6) Constructs the Custom Building Block, containing a Label control and an Icon control, from the resource R_MY_BUILDING_BLOCK.
Adds the Building Block to the container.
Use AddControlLC to add controls to a Scrollable Container.
Add the controls as soon as they are created. Do not push them onto the
Cleanup Stack before they are added. Do not pop them from the Cleanup Stack
until they are fully constructed. A TCleanupItem created in AddControlLC makes sure that
the control is both cleaned up and removed from the Components Array if a leave
occurs before the control is fully constructed.
Not applicable.
Not applicable.
This section covers the most common functions used for interacting with the control.
When constructing the control with resource data, no reference to the control is available in the view class.
When constructing the control with code, the preferred way might be to not save a reference to the control.
In both these cases, the LocateControlByUniqueHandle function
is used to get a pointer to the control by supplying the control's unique handle. When constructing the view and the control
from code, you must explicitly set this unique handle by calling the method SetUniqueHandle.
See the code examples below.
Note that the function will return NULL if the control could not be
found. Always check the pointer before using it!
// Set the unique handle
block->SetUniqueHandle(EViewGenericBuildingBlock);
// Get a pointer to the Building Block control
CQikGenericBuildingBlock* block = LocateControlByUniqueHandle<CQikGenericBuildingBlock>(EViewGenericBuildingBlock);
In order to be notified when a Custom Building Block changes state, you
must add an observer to the Custom Building Block. An observer is an object of the type
MCoeControlObserver. The observer receives a function call to its function
HandleControlEventL(CCoeControl* aControl, TCoeEvent aEventType) when the Custom Building Block changes state.
The view base class, CQikViewBase, implements the
MCoeControlObserver. The HandleControlEventL function must be overloaded in the
view class because the view inherits from CQikViewBase.
The following source code example shows how to add an object as an observer and how to receive events from the Custom Building Block:
void CMySinglePageView::ViewConstructL()
{
// Construction code
…
// Adding this object as an observer
block->SetObserver(this);
}
void CMySinglePageView::HandleControlEventL(CCoeControl* aControl, TCoeEvent aEventType)
{
// Call base class to handle focus management
CQikViewBase::HandleControlEventL(aControl, aEventType);
CQikGenericBuildingBlock* block = LocateControlByUniqueHandle<CQikGenericBuildingBlock>(EViewGenericBuildingBlock);
if(aControl == block)
{
switch(aEventType)
{
case EEventStateChanged:
// The internal state of the Custom Building Block was changed,
// for example, due to another item being selected.
break;
case EEventRequestExit:
break;
case EEventRequestCancel:
break;
case EEventRequestFocus:
// The control received a pointer down event
break;
case EEventPrepareFocusTransition:
// A focus change is about to appear
break;
case EEventInteractionRefused:
// The control is dimmed and received a
// pointer down event.
break;
default:
break;
}
}
}
The reason for calling the base class's HandleControlEventL function is
that the view base class CQikViewBase handles focus management between controls in the view.
If the control's observer is not a class which derives from CQikViewBase, focus management must be resolved by the observer itself. If a control requests
focus and does not get it from the observer, it will generate a panic in some cases if the observer does not leave.
For more details on the TCoeEvent
type, see class MCoeControlObserver in the API documentation.
Destroying the control is just a matter of invoking operator delete on the Custom Building Blocks object.
If you want to create a custom building block you could subclass CQikBuildingBlock, System Building Blocks, or use CQikGenericBuildingBlock, Custom Building Block. Creating a custom building block should, however, only be a last resort when there is no System Building Block that fits the purpose.
This is an explanation of some of the expressions used in this guide.
|