So far, a clone of the CCoeControl sourcegen has been generated. Now we want the runtime behavior to match the design time layout behavior. Currently, the CCoeControl component constructs a LayoutControls() method into which children provide hardcoded child->SetExtent() calls to place themselves at absolute coordinates. Now you will preprocess the contributions and toss away all contributions to this function and use your own.
First, break up the <inline> block to do work before this.finishSourceGen().<inline> this.initSourceGen(contribs, instance, form); this.getChildSourceGen(contribs, instance, form);
// delete all the existing layout code, since it reflects // the design state, not the runtime state Engine.removeContributionsForPhase(contribs, "LayoutControls"); </inline>
Inject our call to have the container lay out children.
<template phase="LayoutControls">
PackControls( ${instance.properties.padding}, ${(instance.properties.direction == "horizontal" ? "ETrue" : "EFalse")} );
</template>
<inline> this.finishSourceGen(contribs, instance, form); </inline>
A routine is used to delete contributions for the “LayoutControls” phase. Phases are converted to locations in finishSourceGen() and would have to be handled differently after that. Then, the <template> injects a call, showing again how properties for our container can be read inside the text using the ${…} escape syntax.
NOTE Complex expressions in ${...} escape sequences should be enclosed in parentheses, because the result is added to a string using the "+" operator.
Finally, account for the new method mentioned above, PackControls(). Define a method declaration into the class and provide the function body. The elements that provide this behavior should come after the <templateGroups> that define the header and main file, and precede the <inline> script code which gathers and finalizes child contributions.
You need to define the method containing this code:
<!-- add a method declaration --> <template location="CLASS_METHODS"> /* Pack the controls into equal-sized regions. */ void PackControls( TInt aPadding, TBool aIsHorizontal ); </template>
Then, define the body. This could be written directly to the MAIN_FILE as a template, but here we choose to make it into a location. By being a location, you can toggle the owned attribute to true and have the UI Designer rewrite the function each time it is saved. This may be useful either to test changes to the templates interactively or to inject new property values into the generated source. If not owned, the function will be written only once, and regenerated if deleted. The function must be placed inside its own location for the UI Designer to rewrite it; unless the whole file is deleted.
Define the function as a location, which can be owned, thus rewritten every time the design is saved. This is useful for testing, though not very efficient.
<defineLocation id="PACK_CONTROLS" baseLocation="MAIN_FILE" owned="false" location="function(${className}::PackControls(TInt, TBool))"> <template> /** Pack the controls into equal-sized vertical regions. */ void ${className}::PackControls( TInt aPadding, TBool aIsHorizontal ) { } </template> </defineLocation>
The <templates> inside <defineLocation> usually describe only the skeleton of the function, with the body defined elsewhere, but this is based on personal preference. Note that the location=”…” line must match the signature of the function declared inside, otherwise you will get strange errors about “C++ parser could not find location … “.
Following is the body of the function. Refer to the EqualContainer.component file for the full text.
<template location="PACK_CONTROLSL"><![CDATA[ TRect rect( Rect() ); TInt count = CountComponentControls(); … </template>
It is worth mentioning that the <![CDATA[ … ]]> block is used to allow free use of C++ syntax inside the block without worrying about escaping XML-sensitive characters. The text placed inside the location should be flush against the left-hand margin. The location itself defines the indentation.
NOTE For new components, it is advised to use macros to define functions. This will encapsulate the <defineLocation> and <template> elements as well as handling some of the gotchas mentioned here. See the reference for <expandMacro> and the CommonMacros.inc file in the com.nokia.series60.componentlibrary plugin for details and Macro information located here.