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.VerticalLabel1"
            baseComponent="com.nokia.sdt.series60.CCoeControlBase"
            category="Controls" version="1.0"
            instanceNameRoot="vlabel">
            <symbian
              sdkName="com.nokia.series60" minSDKVersion="2.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 CCoeControlBase, which is a component included with Carbide.c++. It provides much of the default behavior, including needed source code generation.

### Symbian Element

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

    <symbian sdkName="com.nokia.series60" minSDKVersion="2.0"  className="CVerticalLabel"/>

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

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. Since icon images have also been omitted, a default image is displayed in the palette and no image is visible 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="is-ccoecontrol-content">true</attribute>
    </attributes>

The cpp-class-name attribute is used by the source generation element (<sourceGen>) that is inherited from CCoeControlBase. This allows you to specify the name of the C++ class to use in the generated source. The is-ccoecontrol-content attribute specifies that this component is compatible with the CCoeControl container. This attribute is understood by the S60 CCoeControl container component because of the specifics of how its containment query script is implemented.

NOTE This attribute has to be defined as "true" for the component to be placed in the UI Designer palette.

### 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 design. 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 S60 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 to calculate the initial size of the component instance. The wHint and hHint parameters will be greater than zero when the user has dragged out a rectangle to specify the initial component size. That should be respected, unless that size is inappropriate for your component. The example script respects the requested size and specifies defaults, if necessary.

    VerticalLabel.prototype.getPreferredSize = function(instance, laf, wHint, hHint) {
     var width = wHint > 0? wHint : 20;
     var height = hHint > 0? hHint : 100;
     return new Point(width, height);
     }

### 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 S60 components included with the UI designer for lots of examples; located at <Carbide installation path>/plugins/com.nokia.sdt.series60.componentlibrary/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 CCoeControlBase and generating code for an existing container (CCoeControl), 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 forms="Container">

      <useTemplateGroup ids="CLASS_CONTRIBS" />
      <useTemplate ids="INIT_FROM_CONTAINER" />
      <useTemplateGroup ids="CONTAINER_CHILD_CONTRIBS" />
      <useTemplate ids="LAYOUT_CONTROLS" />
      <inline>
        if (Engine.formMatches(form, [""])) {
         // create files if missing
         Engine.createFromStockFile("inc", "VerticalLabel.h", "VerticalLabel.h");
         Engine.createFromStockFile("src", "VerticalLabel.cpp", "VerticalLabel.cpp");
        }
        this.getCppSystemIncludes(contribs, ["barsread.h", "stringloader.h", "eikenv.h"]);
      </inline>
      <useTemplateGroup ids="GenerateCommonControlEvents GenerateStateChangedEvent"/>
      <useTemplateGroup ids="GenerateRequestingFocusEvent GenerateRequestingExitEvent"/>
      <useTemplateGroup ids="GenerateRequestingCancelEvent GenerateInteractionRefusedEvent"/>
      <useTemplateGroup ids="GeneratePrepareFocusTransitionEvent"/>

      <template location="MAIN_USER_INCLUDES"><![CDATA[#include "VerticalLabel.h"]]>
      </template>
    </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 CCoeControlBase can be reused.

A template group is a set of templates referenced by a single name. The CLASS_CONTRIBS group is the common boilerplate for defining a member variable in the class; initializing the member and deallocating the member.

The INIT_FROM_CONTAINER template emits the standard Symbian code for allocating the component within a CCoeControl container. This includes allocating the object, reading the state from a resource, and managing the cleanup stack.

The LAYOUT_CONTROLS template generates source to size and position the component according to the properties set in the UI designer.

The <inline> element inserts JavaScript code. This example calls a predefined function to emit the header files needed to use this component.

The additional <useTemplateGroup> elements (after the inline element) references existing templates in order to support events. Since the VerticalLabel example is a subclass of CCoeControl you want to support all the events in a CCoeControl container. Since the example inherits from CCoeControlBase, the appropriate event declarations and templates have already been inherited.

The final <template> element in this snippet is used to define a new template in order to insert the #include "VerticalLabel.h" statement for the class header file.