XML-Based Component File

## Tutorial: Vertical Label Component - XML Details

The tutorial consists of two versions of the VerticalLabel component. VerticalLabel1 is the bare minimum needed to make a functioning component. VerticalLabel2 uses JavaScript to display the component in the UI Designer when designing your user interface.

The following information explains what is relevant to the tutorial. Refer to the XML component schema documentation for all the details.

### Component Definition

The root element for defining a custom component begins with the <componentDefinition> element as shown in the VerticalLabel1.component and VerticalLabel2.component files. It contains the necessary name space attributes, making the component schema namespace the default.

### Component

The component element defines the majority of the component properties, attributes, source mapping and souce generation declarations. The following snippet is from the example .component files:

    <component friendlyName="%friendlyName"
            qualifiedName="com.example.uiq.VerticalLabel1"
            baseComponent="com.nokia.carbide.uiq.ControlCollectionItemBase"
            category="Custom Controls" version="1.0"
            instanceNameRoot="vlabel">
            <symbian
              sdkName="com.uiq" minSDKVersion="3.0"
              className="CVerticalLabel"/>

Strings prefixed with % are localized strings that are automatically looked up in the accompanying properties files, such as VerticalLabel1.properties.

Note that this component derives from ControlCollectionItemBase, which is a component included with Carbide.c++. It provides some of the source code generation, as well as allowing it to behave like the other UIQ controls in the UI designer in that they are used in a design's different layout configurations as references in the control collection.

### Symbian Element

The <symbian> element specifies that this component is compatible with all SDKs from 3.0 forward and the class name in the VerticalLabel.cpp file used to draw the component at run time is CVerticalLabel.

    <symbian sdkName="com.uiq" minSDKVersion="3.0"  className="CVerticalLabel"/>

The sdkName property identifies the Symbian OS variant with which the component is compatible. Currently the only recognized SDK name for UIQ is "com.uiq".

TIP Enter devices at a command prompt (C:\>devices) to display a list of installed and properly configured SDKs.

### Designer Images

In the VerticalLabel1 example, the <designerImages> element uses one image. This is the static layout image visible in the UI design. This is used in place of writing rendering script in a JavaScript file. You will only see a static graphic in the UI designer and its sizing by the current layout manager will not be defined by the component. Since icon images have also been omitted, default images are displayed in the palette and in the outline view. For example:

    <designerImages layoutImageFile="layoutImage.png"/>

In the VerticalLabel2 example, the <designerImages> element uses custom icon images (.png files) to represent the component in the palette and outline views. The static layout image file can be removed since JavaScript rendering code has been added to display the component in the UI design. For example:

    <designerImages smallIconFile="VerticalLabel_sm.png"
     largeIconFile="VerticalLabel.png"/>

#### Image Support

Images are validated and rendered on a per-component basis. Each component may have different restrictions or guidelines for the type or size of images that appear. Images appearing in forms and lists will be automatically scaled by the platform. This requires a reference to another interface the component system understands (IImagePropertyRenderingInfo); and can be declared as shown in the following code fragment.

    <implementations>
     <implementation>
      <interface id="com.nokia.sdt.datamodel.adapter.IImagePropertyRenderingInfo"/>
      <script file="MyComponent.js" prototype="MyComponent"/>
     </implementation>
    </implementations>

### Attributes Element

The Attributes element allows you to declare miscellaneous characteristics about your component. For example, the following snippet is from the example Vertical Label .component files.

    <attributes>
     <attribute key="cpp-class-name">CVerticalLabel</attribute>
     <attribute key="rss-control-type-enum">EVerticalLabel</attribute>
    </attributes>

The cpp-class-name attribute is used by the source generation element (<sourceGen>) that is inherited from ControlCollectionItemBase. This allows you to specify the name of the C++ class to use in the generated source. The rss-control-type-enum attribute specifies the type identifier used in the QIK_CONTROL resource generated for the control in the control collection resource.

### Properties Element

Properties are the data values you can define for a component instance. The text property is the default text drawn by the vertical label component. Note that it is a localized string, so you may provide different values for each language added to the application. The lineWidth property determines the thickness of the border rectangle drawn around the component. A value of zero (0) indicates no border will be drawn. Note that default, minimum, and maximum values are specified. The default attribute is optional and provides an initial value. The optional minimum and maximum attributes provide range checking for integer properties.

    <properties>
     <property name="text" type="localizedString" default="label"/>
     <property name="lineWidth" type="integer" default="1" minValue="0" maxValue="5"/>
    </properties>

### Implementations Element

The <implementations> element is used in the VerticalLabel2.component example in order to render the component in the UI designer and provide its preferred size to be used by the layout manager. The <implementations> element informs the UI designer that the custom component has code. Implementations can be provided in either JavaScript or Java.

Each implementation declaration has a list of one or more interfaces it fulfills. In this case the IVisualAppearance interface is implemented. This allows us to render an image corresponding to the current property values and provide feedback on the appropriate sizing for the component. The <script> element informs the UI designer which file has the script and the name of the JavaScript prototype object to instantiate, as shown in the following snippet.

    <implementations>
       <implementation>
         <interface  id="com.nokia.sdt.datamodel.adapter.IVisualAppearance"/>
         <script file="VerticalLabel.js"  prototype="VerticalLabel"/>
       </implementation>
    </implementations>

#### JavaScript

The example JavaScript file (VerticalLabel.js) contains an empty function to instantiate the JavaScript prototype. Note that the JavaScript file needs to be located as a sibling to the component file that references it.

    function VerticalLabel() {
     }

The following code in the JavaScript file declares the draw method. It takes three parameters:

- instance – the current component instance used to retrieve property values and other state data.
- laf – the look and feel object. This has objects and values that vary with the SDK and screen configuration. See the XML documentation on ILookAndFeel for more information.
- graphics – the graphics used for drawing. This is a wrapper around an SWT GC object.

    VerticalLabel.prototype.draw  = function(instance, laf, graphics) {

The font object is obtained from the look and feel object. Since this is a simple example the font is hard-coded to a standard Symbian font.

    var font = laf.getFont("NormalFont");
     graphics.setFont(font);

The background color needs to be set since anti-aliased text with a transparent background is drawn. In the UI Designer, each component is rendered into a bitmap with 'transparent pixel' support. The bitmap does not have an alpha channel. Thus, if the background color is not set, the 'transparent pixel' would be blended with the antialiased text, resulting in an orange border.

    graphics.setBackground(laf.getColor("EEikColorControlBackground"));

Next a rectangular border and the text within the border is drawn. The bounds and position of the text are calculated accordingly.

     var properties = instance.properties;
     var lineWidth = properties.lineWidth;
     var halfLineWidth = lineWidth/2;
     var textBounds = new Rectangle(halfLineWidth, halfLineWidth,
     properties.size.width - halfLineWidth,
     properties.size.height - halfLineWidth);
     var x = lineWidth + 1;
     var y = properties.size.height - lineWidth - 1;

The rotated text is then drawn.

    graphics.drawRotatedString(properties.text, textBounds, x, y, -1.57, true);

If requested, the border is drawn.

    if (lineWidth > 0) {
     graphics.setLineWidth(lineWidth);
     x = y = halfLineWidth;

     graphics.drawRectangle(x, y,
     properties.size.width-lineWidth,
     properties.size.height-lineWidth);
     }

The getPreferredSize method is called by the layout manager to get the size of the component instance. If its text property is null, it will return an empty size, otherwise it will calculate the width of the text to use as its height, and return its parent's width as its width.

    VerticalLabel.prototype.getPreferredSize = function(instance, laf, wHint, hHint) {
    	var text = instance.properties.text;
    	if (text == null)
    		return new Point(0, 0);

    	var font = laf.getFont("NormalFont");
    	var extent = TextRendering.formattedStringExtent(font, text, new Point(1000, 1000), 0, 0);
    	var lineWidth = instance.properties.lineWidth;
    	var parentBounds = instance.parent.getLayoutBounds();

    	return new Point(parentBounds.width, extent.x + lineWidth + 1);
    }

### Source Mapping Element

The Vertical Label component uses an RSS include file (example_verticallabel.rh). This file defines a custom resource used to initialize the component. Since our component uses a localized string it is especially important to use a resource. The <sourceMapping> element contains information on how to convert from property values to RSS statements, and from RSS statements back to property values.

The <mapResource> element tells the RSS generator to create a resource of type EXAMPLE_VERTICAL_LABEL, and that the example_verticallabel.rh file is needed to create compilable source code. The RSS generator has flexible support for mapping properties to resources. Only simple conversions are needed, which can be done with the <mapSimpleMember> element. This has attributes that indicate a given property should be used to initialize a specific resource member. Refer to the "source mapping" XML schema documentation for details on all available mappings. Detailed documentation on the schema can be found in the plugins folder of your Carbide.c++ installation, for example, the default location at C:\Program Files\Nokia\Carbide.c++ v1.3\plugins\com.nokia.sdt.component.symbian_1.3.0.3. Also examine the UIQ components included with the UI designer for lots of examples; located at <Carbide installation path>/plugins/com.nokia.carbide.cpp.uiq.components/components.

    <sourceMapping>
     <mapResource struct="EXAMPLE_VERTICAL_LABEL" headers="example_verticallabel.rh">
     <mapSimpleMember property="text" member="txt"/>
     <mapSimpleMember property="lineWidth" member="line_size"/>
     </mapResource>
    </sourceMapping>

### Source Generation Element

The <sourceGen> element contains all the information needed to generate C++ code. Because this example is deriving from ControlCollectionItemBase, there is a lot of existing infrastructure to leverage. Source code generation is performed by executing JavaScript scripts. There is a layer above raw JavaScript that creates scripts by way of template expansion, like with PHP, JPS, ASP, etc. With templates you can define variables, or escape out to arbitrary script code. The following code snippet is from the Vertical Label .component files.

    <sourceGen>
    	<useTemplateGroup ids="makeVisible"/>
    	<templateGroup id="0" form="InstanceGen">
    	<expandMacro name="SetupControlInstanceVariable"  Type="${this.getCppClassName(instance)}"
    		InstanceMemberName="${instanceMemberName}" InstanceTitle="${instanceName$title}"
    		Headers="barsread.h eikenv.h"/>
    	</templateGroup>
    	<inline>
    if (Engine.formMatches(form, [""])) {
    	// create files if missing
    	Engine.createFromStockFile("inc", "VerticalLabel.h", "VerticalLabel.h");
    	Engine.createFromStockFile("src", "VerticalLabel.cpp", "VerticalLabel.cpp");
    }
    	</inline>
    	<template phase="MainUserIncludes"><![CDATA[
    #include "VerticalLabel.h"
    #include "example_verticallabel.hrh"
    ]]></template>
    	<template location="VIEWDIALOGBASE_HEADER_OWNED_SYSTEM_INCLUDES"><![CDATA[
    #include <QikControlProvider.h>
    ]]></template>
    	<templateGroup id="ControlFactory">
    	<template id="VerticalLabelControlFactory" phase="ClassPrivateOwnedMethods"><![CDATA[
    class TVerticalLabelControlFactory : public MQikControlFactory
    	{
    public:
    	CCoeControl* CreateByTypeL(
    		TInt aType,
    		TInt& aDefaultFlags )
    	{
    	if ( aType == EVerticalLabel )
    		{
    		aDefaultFlags = EQikCtrlFlagIsNonFocusing;
    		return new(ELeave) CVerticalLabel;
    		}
    	return NULL;
    	}
    	CCoeControl* ConstructCustomControlL(
    		TInt aUniqueHandle,
    		TInt aType,
    		TInt aResourceId,
    		TInt aItemFlags,
    		const CCoeControl& aParent )
    	{
    	return NULL;
    	}
    	};
    TVerticalLabelControlFactory iVerticalLabelControlFactory;
    ]]></template>
    	<template id="InstallControlFactory" phase="PreConstructFromResourceL"><![CDATA[
    // Install this factory in the control providers list
    ControlProvider()->AddControlFactoryL( iVerticalLabelControlFactory );
    ]]></template>
    	<template id="RemoveControlFactory" phase="Destroy"><![CDATA[
    // Remove this factory from the control providers list
    ControlProvider()->RemoveControlFactory( iVerticalLabelControlFactory );
    ]]></template>
    	</templateGroup>
    </sourceGen>

Since source code generation is very detailed and specific, deriving from a component does not automatically enable source code generation. The derived component must specify what to generate, either completely or by referencing existing templates. Templates defined in ControlCollectionItemBase can be reused.

The `makeVisible` template group does some standard initialization. Macros are groups of parametrized templates. The `SetupControlInstanceVariable` macro generates code to setup a member variable for the vertical label control's instance.

The <inline> element inserts JavaScript code. This example calls a predefined function to copy the stock versions of VerticalLabel.cpp and VerticalLabel.h that contain the runtime code implementing the vertical label control.

There is a <template> element in this snippet that is used to define a new template in order to insert the #include "VerticalLabel.h" and #include "example_verticallabel.hrh" statements for the required header files.

The final <templateGroup> element embodies a set of templates used to generate and install a custom control factory to translate the custom control type identifier, `EVerticalLabel` used in the control collection resource into a CVerticalLabel object.