Symbian3/SDK/Source/GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1.dita
changeset 7 51a74ef9ed63
equal deleted inserted replaced
6:43e37759235e 7:51a74ef9ed63
       
     1 <?xml version="1.0" encoding="utf-8"?>
       
     2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
       
     3 <!-- This component and the accompanying materials are made available under the terms of the License 
       
     4 "Eclipse Public License v1.0" which accompanies this distribution, 
       
     5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
       
     6 <!-- Initial Contributors:
       
     7     Nokia Corporation - initial contribution.
       
     8 Contributors: 
       
     9 -->
       
    10 <!DOCTYPE concept
       
    11   PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
       
    12 <concept id="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1" xml:lang="en"><title>How
       
    13 to write controls</title><prolog><metadata><keywords/></metadata></prolog><conbody>
       
    14 <p>Cone itself does not provide any concrete controls. Uikon and the UI variant
       
    15 libraries provide a large number of 'stock' controls for application writers.
       
    16 Application writers often need to supplement the standard set of controls
       
    17 with application specific controls of their own. These may be completely new
       
    18 controls or, more often, compound controls which contain a number of standard
       
    19 controls. </p>
       
    20 <p>This section describes how to create controls and how to integrate them
       
    21 in to the control framework. It is divided into the following sections: </p>
       
    22 <p><xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1/GUID-341017B2-8CF9-5124-8D20-C75A8A51F0B7-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-13">Creating
       
    23 a control</xref>  </p>
       
    24 <p><xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1/GUID-3F0E8223-2218-5C95-AFBC-D66AD1DB12A7-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-14">Window
       
    25 owning or not?</xref>  </p>
       
    26 <p><xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1/GUID-795EBF51-AD26-513E-9A82-A99C629CE779-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-15">Creating
       
    27 a compound control</xref>  </p>
       
    28 <p><xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1/GUID-795EBF51-AD26-513E-9A82-A99C629CE779-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-15">Size,
       
    29 position and layout</xref>  </p>
       
    30 <p><xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1/GUID-351911EE-87C7-5D11-8434-BA7FD3741745-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-17">Drawing
       
    31 and refreshing</xref>  </p>
       
    32 <p> <xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1/GUID-FF7DB067-24AD-50C3-BF52-952F836609B0-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-18">Drawing
       
    33 backgrounds</xref>  </p>
       
    34 <p> <xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1/GUID-54C6A39A-CBD0-52E5-8CD0-76BE22247A54-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-19">Drawing
       
    35 text</xref>  </p>
       
    36 <p> <xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1/GUID-D1AED2A8-94AC-54BB-9CEB-C8C3643AFBBD-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-20">Drawing
       
    37 graphics</xref>  </p>
       
    38 <p><xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1/GUID-AC723EE4-1482-59C5-9F13-CAE119C7800D-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-21">Handling
       
    39 events</xref>  </p>
       
    40 <p><xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290-GENID-1-8-1-6-1-1-4-1-6-1-9-1/GUID-FE221E89-1817-5A73-8FBA-212FBC030766-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-22">Implementing
       
    41 the Object Provider (MOP) interface</xref>  </p>
       
    42 <section id="GUID-341017B2-8CF9-5124-8D20-C75A8A51F0B7-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-13"><title>Creating a
       
    43 control</title> <p>A control is a class which derives from <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref>.
       
    44 It should have a public constructor and, if any leaving function calls or
       
    45 memory allocations are required during construction, a <codeph>ConstructL()</codeph> function.
       
    46 The majority of re-useable and configurable controls have a <codeph>ConstructFromResourceL()</codeph> function
       
    47 which allows a specific instance of a control to be configured using an application's
       
    48 resource file. Obviously any memory allocated must be freed in the destructor.
       
    49 Before a control is drawn to the screen it must be activated. The <codeph>ActivateL()
       
    50 function</codeph> may be overriden to perform last-minute configuration (but
       
    51 must call the function in the base class). </p> <codeblock id="GUID-18D48E7E-9846-5CE0-BE1E-FAB723419B90-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-13-3" xml:space="preserve">
       
    52 Class CMyControl : public CCoeControl
       
    53     {
       
    54     public:
       
    55         CMyControl() ;
       
    56         void ConstructL(...) ;
       
    57         // from CCoeControl
       
    58         void ConsructFromResourceL( TResourceReader&amp; aReader ) ; 
       
    59     private:
       
    60         ~CMyControl() ;
       
    61 
       
    62     // additional functions to handle events 
       
    63     // additional functions to draw the control
       
    64     // additional functions to determine the size, layout and position the control
       
    65     }</codeblock> </section>
       
    66 <section id="GUID-3F0E8223-2218-5C95-AFBC-D66AD1DB12A7-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-14"><title>Window owning
       
    67 or not? </title> <p>The decision over whether to make a control window owning
       
    68 or not is usually straightforward. Each view requires a window, so the top-level
       
    69 control must be window-owning and a child of the AppUi. Below this a window
       
    70 owning control is normally only necessary where a sense of layering is required:
       
    71 for instance a pop-up window or a scrolling window. Dialogs and menus are
       
    72 window owning controls but these are normally implemented in the Uikon and
       
    73 UI variant libraries and do not require custom derivation from <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref>.
       
    74 Unnecessary window-owning controls should be avoided as they require more
       
    75 infrastructure, place greater demand on the Window Server and reduce performance. </p> <p>If
       
    76 a control must be window owning its window must either be created in the <codeph>ConstructL()</codeph> function
       
    77 or by the caller. The former is preferred. There are several overloads of
       
    78 the <codeph>CreateWindowL()</codeph> and <codeph>CreateBackedUpWindowL()</codeph> functions.
       
    79 Those which do not take a parent parameter create a top-level window which
       
    80 is a child of the root window. </p> <p>If a control is not window owning its <codeph>SetContainerWindowL()</codeph> function
       
    81 must be called when it is instantiated. </p> <p>If it can, the Framework will
       
    82 automatically set up the parent pointer when the window, or associated window
       
    83 relationship is established. If it cannot do this, because <codeph>CreateWindowL()</codeph> or <codeph>SetContainerWindowL()</codeph> did
       
    84 not provide a <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref>, the parent pointer (and MopParent)
       
    85 may be set expicitly using <codeph>SetParent()</codeph> and <codeph>SetMopParent()</codeph>. </p> </section>
       
    86 <section id="GUID-795EBF51-AD26-513E-9A82-A99C629CE779-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-15"><title>Creating a
       
    87 compound control</title> <p>Most applications UIs are built from compound
       
    88 controls. Many custom controls are built up from stock controls and are therefore
       
    89 also compound controls. When a compound control is constructed it constructs
       
    90 its components in its <codeph>ConstructL()</codeph> function. When it receives
       
    91 commands itself, such as <codeph>ActivateL()</codeph> and <codeph>DrawNow()</codeph> it
       
    92 passes them on to each of its components. In most cases the Framework does
       
    93 much of the donkey work as long as the compound control has been constructed
       
    94 correctly. </p> <p>There are now two methods of creating and managing lodger
       
    95 controls. The first method described is the one that should be used. </p> <codeblock id="GUID-F77661F7-6A68-58DB-B875-9D957A937617-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-15-4" xml:space="preserve">
       
    96 void MyControl::ConstructL( ... )
       
    97     {
       
    98     // initialise the component array. This must be called once (subsequent calls have no effect)
       
    99     InitComponentArrayL() ; 
       
   100 
       
   101     // construct each component control and add it to the component array.
       
   102     CComponent* myComponent = new (ELeave) CComponent ;
       
   103     Components().AppendLC( myComponent ) ; // or InsertLC or InsertAfterLC().  Places item on cleanup stack.
       
   104     myComponent-&gt;ConstructL() ;
       
   105     myComponent-&gt;SetThisAndThatL() ;
       
   106     CleanupStack::Pop( myComponent ) ;    
       
   107     }</codeblock> <p>The return value of the insert and append methods is
       
   108 a <xref href="GUID-2D8BFBA2-79AC-364D-875D-E863CD4A2FE1.dita#GUID-2D8BFBA2-79AC-364D-875D-E863CD4A2FE1/GUID-AD37D86C-F9FA-3514-BFD4-7139A0B8543F"><apiname>CCoeControlArray::TCursor</apiname></xref> object which works as an iterator.
       
   109 It will remain valid when other items are inserted or deleted, or even if
       
   110 the whole array is re-ordered. </p> <p>The insert and append methods leave
       
   111 the component on the Cleanup Stack using a dedicated Cleanup Item that protects
       
   112 the parent's array as well as the component itself. </p> <p>The insert and
       
   113 append methods allow each component to be given an ID. The ID must be unique
       
   114 only within the parent so typically a compound control will have an enum listing
       
   115 each of its children's IDs. <xref href="GUID-2D8BFBA2-79AC-364D-875D-E863CD4A2FE1.dita"><apiname>CCoeControlArray</apiname></xref> , accessed
       
   116 using <codeph>CCoeControl::Components()</codeph>, has a <codeph>ControlById()</codeph> method
       
   117 to retrieve components using their IDs. </p> <p>Components in the array are,
       
   118 by default, owned by the parent and will be deleted automatically when the
       
   119 parent is deleted. The default may be overridden using <codeph>CCoeControlArray::SetControlsOwnedExternally()</codeph>.
       
   120 The setting applies to all of the components. </p> <p>Controls may be removed
       
   121 from the array using one of the <codeph>Remove()</codeph> methods. These do
       
   122 not delete. </p> <codeblock id="GUID-9F9EC327-E7DE-59B8-838B-F5052E3750D3-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-15-10" xml:space="preserve">
       
   123 class CCoeControlArray
       
   124         ...
       
   125     public:
       
   126         IMPORT_C TInt Remove(const CCoeControl* aControl);
       
   127         IMPORT_C CCoeControl* Remove(TCursor aRemoveAt);
       
   128         IMPORT_C CCoeControl* RemoveById(TInt aControlId);
       
   129         ...
       
   130 </codeblock> <p>Using the component array as described is now the approved
       
   131 method of constructing and managing compound controls. In older versions of
       
   132 Symbian OS a specific method of handling components was not provided and developers
       
   133 were obliged to design their own. Bypassing the component array is still possible.
       
   134 It is necessary to allocate and store the components (typically as member
       
   135 data) and to implement the <codeph>CountComponentControls()</codeph> and <codeph>ComponentControl()</codeph> functions
       
   136 to return the number of components and a specified component to the framework.
       
   137 The new method offers significant advantages when controls are added and removed
       
   138 dynamically or are dependant on run-time data. The new method is also integrated
       
   139 with new layout managers. </p> </section>
       
   140 <section id="GUID-7E144310-9AF4-50F1-AD8A-9F9E05D554D1-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-16"><title>Size, position
       
   141 and layout</title> <p>There are several factors which contribute to a control's
       
   142 size and position. The control itself will require a certain size in order
       
   143 to display itself (and its data) correctly. The control's container will be
       
   144 responsible for positioning the control but is also likely to be responsible
       
   145 for positioning other controls - each of which will have its own requirements.
       
   146 Additionally there are the requirements of the UI's look and feel that must
       
   147 be complied with. </p> <p>Each control is responsible for implementing its
       
   148 own <codeph>Size()</codeph> function. </p> <p>Until Symbian OS version 9.1
       
   149 it was normal to write layout code for simple and compound controls in the <codeph>SizeChanged()</codeph> function.
       
   150 This is called by the framework, as one might expect, when a control's size
       
   151 (its 'extent') is changed. From 9.1, however, Symbian OS supports the use
       
   152 of the layout manager interface (<xref href="GUID-A622B8C7-60F4-38E8-B102-14883BCBA249.dita"><apiname>MCoeLayoutManager</apiname></xref>) and
       
   153 the <codeph>SizeChanged()</codeph> function is now implemented in the base
       
   154 class. (Note that if a control's position is changed, with no size change,
       
   155 using <codeph>CCoeControl::SetPosition()</codeph> its <codeph>PositionChanged()</codeph> function
       
   156 is called and that default implementation of <codeph>PositionChanged()</codeph> is
       
   157 empty). </p> <codeblock id="GUID-53A10820-550A-52C2-AE80-D556FD77E8FA-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-16-5" xml:space="preserve">
       
   158 class MCoeLayoutManager
       
   159         ...
       
   160     protected:
       
   161         IMPORT_C MCoeLayoutManager();
       
   162     
       
   163     public:
       
   164         virtual TBool CanAttach() const = 0;
       
   165         virtual void AttachL(CCoeControl&amp; aCompoundControl) = 0;
       
   166         virtual void Detach(CCoeControl&amp; aCompoundControl) = 0;
       
   167         virtual TSize CalcMinimumSize(const CCoeControl&amp; aCompoundControl) const = 0;
       
   168         virtual void PerformLayout() = 0;
       
   169         virtual TInt CalcTextBaselineOffset(const CCoeControl&amp; aCompoundControl, const TSize&amp; aSize) const = 0;
       
   170         virtual void SetTextBaselineSpacing(TInt aBaselineSpacing) = 0;
       
   171         virtual TInt TextBaselineSpacing() const = 0;
       
   172         virtual void HandleAddedControlL(const CCoeControl&amp; aCompoundControl, const CCoeControl&amp; aAddedControl) = 0;
       
   173         virtual void HandleRemovedControl(const CCoeControl&amp; aCompoundControl, const CCoeControl&amp; aRemovedControl) = 0;
       
   174         virtual TInt HandleControlReplaced(const CCoeControl&amp; aOldControl, const CCoeControl&amp; aNewControl) = 0;
       
   175         ...
       
   176 </codeblock> <p>A layout manager may be attached to a compound control. </p> <codeblock id="GUID-ACCD143C-8618-5606-B749-D7EFE5C83ACD-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-16-7" xml:space="preserve">
       
   177 class CCoeControl
       
   178         ...
       
   179     protected: 
       
   180         IMPORT_C MCoeLayoutManager* LayoutManager() const;
       
   181         IMPORT_C virtual void SetLayoutManagerL(MCoeLayoutManager* aLayoutManager);
       
   182 
       
   183     public:
       
   184         IMPORT_C virtual TBool RequestRelayout(const CCoeControl* aChildCtrl);
       
   185         ...</codeblock> <p>The default implementations of <codeph>MinimumSize()</codeph> and <codeph>SizeChanged()</codeph> now
       
   186 use the layout manager. </p> <codeblock id="GUID-88340A33-A58C-5856-AD47-C2E1637DD45F-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-16-9" xml:space="preserve">
       
   187 EXPORT_C TSize CCoeControl::MinimumSize()
       
   188     { 
       
   189     const MCoeLayoutManager* layoutManager = LayoutManager();
       
   190     if (layoutManager)
       
   191         return layoutManager-&gt;CalcMinimumSize(*this);
       
   192     else    
       
   193         return iSize;
       
   194     }
       
   195 
       
   196 EXPORT_C void CCoeControl::SizeChanged()
       
   197     {
       
   198     MCoeLayoutManager* layout = LayoutManager();
       
   199     if (layout)
       
   200         layout-&gt;PerformLayout();
       
   201 </codeblock> <p>The layout manager is responsible for the size and position
       
   202 of the component controls. In practice it's likely that the UI variant libraries
       
   203 will provide concrete layout managers. Application developers should use these
       
   204 as the basis for control-specific layout managers. </p> </section>
       
   205 <section id="GUID-351911EE-87C7-5D11-8434-BA7FD3741745-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-17"><title> Drawing and
       
   206 refreshing</title> <p>A fundamental requirement of most controls is that they
       
   207 are able to render themselves onto the screen. For most controls the drawing
       
   208 process involves outputting text, painting backgrounds (either plain or from
       
   209 a bitmap), drawing shapes (graphics objects) and drawing component controls. </p> <p>Screen
       
   210 drawing may be initiated by the application itself, following something within
       
   211 the application changing, or by the Window Server, due to something else in
       
   212 the system updating the screen while the application is visible. In both cases
       
   213 the control's <codeph>Draw()</codeph> function will be called automatically
       
   214 by the framework. For compound controls all of the components' <codeph>Draw()</codeph> functions
       
   215 will also be called - unless the component lies completely outside the area
       
   216 that requires redrawing. </p> <p>As a control writer you will probably have
       
   217 to implement a <codeph>Draw()</codeph> function. </p> <p>Here is the signature
       
   218 for <codeph>Draw()</codeph>: </p> <codeblock id="GUID-7A83E8B5-9673-5EBC-B628-674734A07E0F-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-17-6" xml:space="preserve">private:
       
   219     void Draw( const TRect&amp; aRect ) const ;</codeblock> <p>Note that it
       
   220 is private, takes a <codeph>const TRect&amp;</codeph> as a parameter, must
       
   221 not leave and is <codeph>const</codeph>. </p> <p>It should only be called
       
   222 by the framework. Application initiated redraws should be through calls to <codeph>DrawNow()</codeph>, <codeph>DrawDeferred()</codeph> or
       
   223 custom functions for drawing smaller elements. </p> <p>The <codeph>aRect</codeph> parameter
       
   224 is the part of the control that requires drawing (refreshing). </p> <p>The
       
   225 function is <codeph>const</codeph> and non-leaving because it is intended
       
   226 to support the decoupling of drawing actions from application state. </p> </section>
       
   227 <section id="GUID-FF7DB067-24AD-50C3-BF52-952F836609B0-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-18"><title>Drawing backgrounds</title> <p>A
       
   228 control's background is typically determined by the current colour scheme
       
   229 or skin. It may be a plain colour or a bitmap. It's also possible that a control
       
   230 is to appear non-rectangular or transparent in which case some of the background
       
   231 will be the control underneath. Prior to Symbian OS 9.1 controls were required
       
   232 to clear and update their whole area and creating these effects was rather
       
   233 complex. From 9.1 controls are drawn 'backmost first'. </p> <p>Background
       
   234 drawing should be done by a dedicated background drawer - i.e. an object which
       
   235 implements the <xref href="GUID-88936D48-B801-3D9C-8A9D-3498807937CE.dita"><apiname>MCoeControlBackground</apiname></xref> interface. A background
       
   236 can be attached to a <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref> using <codeph>SetBackground()</codeph> and
       
   237 is used for that control and all of its children. When a control is drawn
       
   238 the framework looks for the nearest background up the run-time hierarchy and
       
   239 calls <codeph>MCoeControlBackground::Draw()</codeph>. </p> <p>UI variant libraries
       
   240 typically provide backgrounds. They are not owned by the controls to which
       
   241 they are attached. </p> </section>
       
   242 <section id="GUID-54C6A39A-CBD0-52E5-8CD0-76BE22247A54-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-19"><title>Drawing text</title> <p>Text
       
   243 must be drawn with the correct color, font, size and direction. As with backgrounds,
       
   244 these are determined at runtime according to UI customizations. This is achieved
       
   245 by means of a Text Drawer. Note the use of the <xref href="GUID-2280260C-3A4F-3C1E-ADF2-3219ED7FE0DE.dita"><apiname>XCoeTextDrawer</apiname></xref> class.
       
   246 This is a smart pointer (note the use of the <codeph>-&gt;</codeph> operator
       
   247 to access <xref href="GUID-C8C7B785-B3CF-3488-AEB1-BE0A70F6C1F2.dita"><apiname>CCoeTextDrawerBase</apiname></xref> functions) which ensures that
       
   248 only one text drawer is allocated on the heap at a time. </p> <codeblock id="GUID-511A9CEE-F02C-5667-A334-3C61A2428F0F-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-19-3" xml:space="preserve">
       
   249 XCoeTextDrawer textDrawer( TextDrawer() );
       
   250 textDrawer-&gt;SetAlignment(iAlignment); 
       
   251 textDrawer-&gt;SetMargins(iMargin);
       
   252 textDrawer-&gt;SetLineGapInPixels(iGapBetweenLines);
       
   253 textDrawer.SetClipRect(aRect); // have to use . [dot] operator for SetClipRect() as not CCoeTextDrawerBase function.
       
   254 
       
   255 textDrawer.DrawText(gc, *iTextToDraw, Rect(), *Font());
       
   256 </codeblock> <p>Text drawers are typically provided by the UI variant library
       
   257 or skin manager. Controls within the run-time hierarchy can set the text drawer
       
   258 for their children by overriding <codeph>GetTextDrawer()</codeph>. </p> <p>Note
       
   259 that the text drawer expects text to be passed as a <xref href="GUID-07D86324-ED54-3FCD-B301-53B7A6E04AE3.dita"><apiname>TBidiText</apiname></xref> rather
       
   260 than a descriptor. Controls should store all display text in <xref href="GUID-07D86324-ED54-3FCD-B301-53B7A6E04AE3.dita"><apiname>TBidiText</apiname></xref> objects.
       
   261 Application writers should consider the implications of right-to-left layouts
       
   262 for languages such as Hebrew and Arabic. </p> <p>A control's <codeph>GetTextDrawer()</codeph> function
       
   263 might look something like this. It checks on the current state of the control
       
   264 (<codeph>IsDimmed()</codeph>) and passes the call on to a skin manager. </p> <codeblock id="GUID-155AD8EC-17DD-5155-BE20-23246A33695C-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-19-7" xml:space="preserve">
       
   265 EXPORT_C void CMyButtonControl::GetTextDrawer(CCoeTextDrawerBase*&amp; aTextDrawer, const CCoeControl* aDrawingControl, TInt /*aKey*/) const
       
   266     {
       
   267     const TInt textDrawerIndex = (IsDimmed() ? EButtonTextDimmed : EButtonText);
       
   268 
       
   269     SkinManager::GetTextDrawer(aTextDrawer, KSkinUidButton, textDrawerIndex, aDrawingControl);
       
   270     }
       
   271 </codeblock> <p>If the control is drawing text on its own graphics (and does
       
   272 not care about the text drawer of its parents) it can just create an <xref href="GUID-2280260C-3A4F-3C1E-ADF2-3219ED7FE0DE.dita"><apiname>XCoeTextDrawer</apiname></xref> object
       
   273 on the stack in its <codeph>Draw()</codeph> method and initiate it from the
       
   274 skin that it is currently using to draw its graphics, using the <codeph>CSkinPatch::TextDrawer()</codeph> method,
       
   275 like this: </p> <codeblock id="GUID-3DFDBF27-8744-5283-AC7B-EC512EEEBB7D-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-19-9" xml:space="preserve">
       
   276 const CSkinPatch&amp; skin = SkinManager::SkinPatch(KSomeSkinUid, KSomeSkinIndex, this);
       
   277 
       
   278 skin.DrawBitmap(gc, Rect(), aRect);
       
   279 XCoeTextDrawer textDrawer( skin.TextDrawer(KSomeSkinUid, ESomeSkinTextDimmed, this) );
       
   280 
       
   281 const CFont&amp; font = ScreenFont(TCoeFont::NormalFont);
       
   282 textDrawer.DrawText(gc, iText, rect, font);
       
   283 </codeblock> <p>The example above also illustrates how to retrieve the correct
       
   284 font. <xref href="GUID-2A12FE3B-47F2-3016-8161-A971CA506491.dita"><apiname>CFont</apiname></xref> objects must not be stored in control member
       
   285 data as they must change when the control's zoom state changes. Instead, a <xref href="GUID-463C1928-878D-3B06-ABFD-178BE1BAD776.dita"><apiname>TCoeFont</apiname></xref> that
       
   286 represents a font's size (logical or absolute in pixels) and style (plain,
       
   287 bold, italic, subscript, or superscript) should be used. </p> <codeblock id="GUID-864A57DB-BCDA-50B6-B876-9EF62CFB27C6-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-19-11" xml:space="preserve">
       
   288 class TCoeFont 
       
   289         ...
       
   290     public: 
       
   291         IMPORT_C TCoeFont(TLogicalSize aSize, TInt aStyle, TInt aFlags = ENoFlags); 
       
   292         IMPORT_C TCoeFont(TInt aHeightInPixels, TInt aStyle, TInt aFlags = ENoFlags); 
       
   293         IMPORT_C TCoeFont(const TCoeFont&amp; aFont);
       
   294         IMPORT_C TCoeFont();
       
   295         ...</codeblock> <p>By creating a <xref href="GUID-463C1928-878D-3B06-ABFD-178BE1BAD776.dita"><apiname>TCoeFont</apiname></xref> object
       
   296 describing the properties of the desired font, a <xref href="GUID-2A12FE3B-47F2-3016-8161-A971CA506491.dita"><apiname>CFont</apiname></xref> object
       
   297 reference (needed to actually draw the text) can be fetched from the <xref href="GUID-372CDE49-2148-3A21-8EA3-8D4656548C23.dita"><apiname>CCoeFontProvider</apiname></xref>.
       
   298 A font provider can be attached to any <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref> and
       
   299 will keep information about the typeface used by that control and all controls
       
   300 below. A default font provider is attached to the <xref href="GUID-12A9389D-363B-3F54-857F-89EE0EDCDF40.dita"><apiname>CCoeEnv</apiname></xref>. </p> <codeblock id="GUID-C46BEB52-33DB-564B-9A64-53763C7CD226-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-19-13" xml:space="preserve">
       
   301 class CCoeControl
       
   302         ...
       
   303     public:
       
   304         IMPORT_C const CCoeFontProvider&amp; FindFontProvider() const;
       
   305         IMPORT_C void SetFontProviderL(const CCoeFontProvider&amp; aFontProvider);
       
   306         ...
       
   307         </codeblock> <p>To get hold of the <xref href="GUID-2A12FE3B-47F2-3016-8161-A971CA506491.dita"><apiname>CFont</apiname></xref> object
       
   308 a <codeph>Draw()</codeph> method can be implemented like this: </p> <codeblock id="GUID-45292362-1E39-59B0-AC7F-14C98592F059-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-19-15" xml:space="preserve">
       
   309 void CMyControl::Draw(const TRect&amp; aRect)
       
   310     {
       
   311     const CCoeFontProvider&amp; fontProvider = FindFontProvider();
       
   312     const CFont&amp; font = fontProvider.Font(TCoeFont::LegendFont(), AccumulatedZoom());
       
   313 
       
   314     XCoeTextDrawer textDrawer( TextDrawer() );
       
   315     textDrawer-&gt;SetAlignment(EHCenterVCenter);
       
   316     textDrawer.DrawText(gc, iText, rect, font);
       
   317     }
       
   318 </codeblock> <p>For convenience there’s a <codeph>CCoeControl::ScreenFont()</codeph> method
       
   319 that locates the font provider and calls it with the control’s accumulated
       
   320 zoom: </p> <codeblock id="GUID-5974F900-84B7-5262-8428-88797911F94A-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-19-17" xml:space="preserve">
       
   321 class CCoeControl
       
   322         ...
       
   323     protected:
       
   324         IMPORT_C const CFont&amp; ScreenFont(const TCoeFont&amp; aFont) const;
       
   325         ...
       
   326 </codeblock> </section>
       
   327 <section id="GUID-D1AED2A8-94AC-54BB-9CEB-C8C3643AFBBD-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-20"><title>Drawing graphics</title><p>Controls
       
   328 draw graphics objects - lines, rectangles, shapes and bitmaps to a <keyword>graphics
       
   329 context</keyword>. The graphics context is provided by the Window Server and
       
   330 represents a group of settings appropriate for the physical device that is
       
   331 ultimately being drawn to. In most cases the device is a screen and a graphics
       
   332 context should be obtained using <codeph>CCoeControl::SystemGc()</codeph>. <codeph>CCoeControl::SystemGc()</codeph> gets
       
   333 the current graphics context from the run-time hierarchy. Controls in the
       
   334 hierarchy may override graphics context settings which will then be passed
       
   335 on to their children. <i>Controls should not get their graphics context directly
       
   336 from CCoeEnv as to do so would bypass the hierarchy</i>. </p> <codeblock id="GUID-DC2B7A84-BA93-5AE0-BABA-9CF6B156A54E-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-20-3" xml:space="preserve">
       
   337 void CMyControl::Draw( const TRect&amp; aRect )
       
   338     {
       
   339     CWindowGc&amp; gc = SystemGc() ; // get gc from run time hierarchy
       
   340     TRect rect = TRect( Size() ) ;
       
   341     if ( IsBlanked() )
       
   342         {
       
   343         // blank out the entire control
       
   344         gc.SetPenStyle( CGraphicsContext::ENullPen ) ;
       
   345         gc.SetBrushStyle( CGraphicsContext::ESolidBrush ) ;
       
   346         TRgb blankColor = BlankingColor() ;
       
   347         gc.SetBrushColor( blankColor ) ;
       
   348         gc.DrawRect( rect ) ;
       
   349         }
       
   350     else
       
   351         {
       
   352         // draw masked bitmap in the centre of the control 
       
   353         // The parent will draw the background 
       
   354         TInt id = BitMapId() ;
       
   355 
       
   356         TInt x = Size().iWidth - iBitmap[id]-&gt;SizeInPixels().iWidth ;
       
   357         TInt y = Size().iHeight - iBitmap[id]-&gt;SizeInPixels().iHeight ;
       
   358 
       
   359         TPoint pos = Rect().iTl ;
       
   360         pos.iX = pos.iX + ( x / 2 ) ;
       
   361         pos.iY = pos.iY + ( y / 2 ) ;
       
   362 
       
   363         gc.BitBltMasked( pos, iBitmap[id], rect, iMaskBitmap, ETrue ) ;
       
   364         }
       
   365     }</codeblock> <p>Before a graphics context can be used it must be activated.
       
   366 After use it must be deactivated. Activation and deactivation are done automatically
       
   367 by the framework in <codeph>DrawNow()</codeph>, <codeph>DrawDeferred()</codeph> and <codeph>HandleRedrawEvent()</codeph> but
       
   368 must be done explicitly for any other application initiated drawing by calling <codeph>ActivateGc()</codeph> and <codeph>DeactivateGc()</codeph>. </p> <p>Controls may implement partial drawing to speed up performance. The <codeph>Draw()</codeph> function
       
   369 may be split into sub functions: <codeph>DrawThis()</codeph>, <codeph>DrawThat()</codeph>, <codeph>DrawTheOther()</codeph>.
       
   370 Each of these requires a corresponding <codeph>DrawThisNow()</codeph> and/or <codeph>DrawThisDeferred()</codeph> function. </p> <codeblock id="GUID-EDC0D6F1-61BC-552F-B56D-C32148ADECA3-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-20-6" xml:space="preserve">
       
   371 CMyControl::Draw()
       
   372     {
       
   373     DrawThis() ;
       
   374     DrawThat() ;
       
   375     DrawTheOther() ;
       
   376     }</codeblock> <codeblock id="GUID-E026186D-7B55-5AB5-9391-8587E3510D6D-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-20-7" xml:space="preserve">
       
   377 CMyControl::DrawThisNow()
       
   378     {
       
   379     ActivateGc() ;
       
   380     DrawThis() ;
       
   381     DeactivateGc() ;
       
   382     }</codeblock> </section>
       
   383 <section id="GUID-AC723EE4-1482-59C5-9F13-CAE119C7800D-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-21"><title>Handling events </title> <p>The
       
   384 Control Framework supports user interaction in two ways: key-press events
       
   385 and pointer events. Both types of event arrive through the Window Server though
       
   386 they each arrive in a slightly different way. Both are closely related to
       
   387 the concept of 'focus' and the location of the cursor. </p> <p><b>Handling
       
   388 key events </b> </p> <p>Key events are delivered to the AppUi. The Window
       
   389 Server channels them through the root window of its current window group which
       
   390 maps to the AppUi foreground application. The AppUi offers each key event
       
   391 to each of the controls on its control stack in priority order until one of
       
   392 the controls 'consumes' it. </p> <p>To receive key events a control must implement <codeph>CCoeControl::OfferKeyEventL()</codeph>.
       
   393 If it handles the event it must return <codeph>EKeyWasConsumed</codeph>: If
       
   394 it doesn't it must return <codeph>EKeyWasNotConsumed</codeph> so that the
       
   395 next control on the stack receives it. </p> <codeblock id="GUID-448E9DF8-9D63-5BA4-94A7-4FB4B96A6DEA-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-21-6" xml:space="preserve">
       
   396 TKeyResponse CMyControl::OfferKeyEventL( const TKeyEvent&amp; aKeyEvent, TEventCode aType)
       
   397     {
       
   398     TKeyResponse returnValue = EKeyWasConsumed ;
       
   399     switch( aKeyEvent.iCode ) 
       
   400         {
       
   401         case EKeyEnter :
       
   402             // do stuff
       
   403             break ;
       
   404         case EKeyEscape :
       
   405             // do stuff :
       
   406             break ;
       
   407 
       
   408             ...
       
   409                 
       
   410         default :
       
   411             // did not recognise key event
       
   412             returnValue = EKeyWasNotConsumed ;
       
   413             break ;
       
   414         }
       
   415     return returnValue ;
       
   416     }</codeblock> <p>The handling of key events will depend on the design
       
   417 and purpose of the control itself. Compound controls might need to keep track
       
   418 of an input <b>focus</b>, or <b>cursor</b>, and to pass key events amongst
       
   419 its lodgers. Input into one lodger might have an effect on another - pressing
       
   420 a navigation key might cause one control to lose the highlight and another
       
   421 to gain it, pressing a number key might cause a text editor to grow which
       
   422 might, in turn, require all of the components below it to shuffle downwards
       
   423 and a scroll bar to become visible (which might also require some controls
       
   424 to be laid out differently). </p> <p><b>Handling pointer events </b> </p> <p>Pointer
       
   425 events are slightly different as the position of the pointer, rather than
       
   426 of the focus, is significant. The Window Server passes a pointer event to
       
   427 the top-most visible window at the point of contact. The Framework uses the
       
   428 functions <codeph>ProcessPointerEventL()</codeph> and <codeph>HandlePointerEventL()</codeph> to
       
   429 work down the hierarchy. The Framework also uses the <xref href="GUID-A2BF9AE8-CF42-3D94-8763-66DB11EDDA46.dita"><apiname>MCoeControlObserver</apiname></xref> and
       
   430 focussing mechanisms to inform the observer of the controls that will be losing
       
   431 and gaining the focus. </p> <p><b>Using the Control Observer Interface</b></p><p>The
       
   432 Control Framework facilitates this type of relationship between a container
       
   433 and its lodgers with the <codeph>MCoeControlObserver</codeph> interface. Typically
       
   434 the container implements the interface and becomes the observer for each lodger
       
   435 that can receive user input (focus). There is only one function in <codeph>MCoeControlObserver</codeph>:</p><codeblock xml:space="preserve">virtual void HandleControlEventL( CCoeControl *aControl, TCoeEvent aEventType ) = 0 ;</codeblock><p>and it is called when an observed control calls</p><codeblock xml:space="preserve">void CCoeControl::ReportEvent( MCoeControlObserver::TCoeEvent aEvent ) ;</codeblock><p>A control can have only one observer (or none) so <codeph>ReportEvent()</codeph> does
       
   436 not need to specify an observer. An observer may observe any number of controls
       
   437 so <codeph>HandleControlEventL()</codeph> takes the observed control as a
       
   438 parameter. The other piece of information passed to the observer is a <codeph>TCoeEvent</codeph>.</p><codeblock xml:space="preserve">enum TCoeEvent
       
   439     {
       
   440     EEventRequestExit,
       
   441     EEventRequestCancel,
       
   442     EEventRequestFocus,
       
   443     EEventPrepareFocusTransition,
       
   444     EEventStateChanged,
       
   445     EEventInteractionRefused
       
   446 	 };</codeblock><p><codeph>CCoeControl</codeph> also provides <codeph>IsFocused()</codeph>, <codeph>SetFocused()</codeph> and <codeph>IsNonFocussing()</codeph>. Note that Framework does not attempt to ensure exclusivity of focus, nor
       
   447 does it give any visible indication of focus. It is up to the application
       
   448 developer to ensure that only one control has the focus at a time, that the
       
   449 focus is correctly transferred between controls, that only appropriate controls
       
   450 receive the focus and that the focus is visible at all times.</p><codeblock xml:space="preserve">void CContainer::HandleControlEventL(CCoeControl* aControl, TCoeEvent aEventType)
       
   451     {
       
   452 	 switch (aEventType)
       
   453         {
       
   454 		   case EEventRequestFocus:
       
   455 			    {
       
   456 			    if( !(aControl-&gt;IsFocussed()) )
       
   457 				     {
       
   458 				     aControl-&gt;SetFocus( ETrue ) ;
       
   459 				     // remove focus from other controls
       
   460 				     for ( Tint ii = 0 ; ii &lt; CountComponentControls() ; ii++ ) 
       
   461                      {
       
   462 					       CCoeControl* ctl = ComponentControl( ii ) ;
       
   463 					       if( ( ctl != aControl ) &amp;&amp; !( ctl-&gt;IsNonFocussing() ) )
       
   464 						        {
       
   465 						        aControl-&gt;SetFocus( EFalse ) ;
       
   466 						        }
       
   467 					       }
       
   468 				      }
       
   469 			     }
       
   470 			     break;
       
   471 	           ...
       
   472 		     }
       
   473 	    }</codeblock> <p>Control developers may implement <codeph>HandlePointerEventL()</codeph>,
       
   474 which is a virtual function, to perform pointer event functionality. The implementation
       
   475 must, however, call the base class function. </p> <p>Controls may modify their
       
   476 pointer area, possibly if they appear non-rectangular or overlap. To do so
       
   477 requires the addition of a hit test which describes a hit-test region. A hit-test
       
   478 region may cover all or part of one or more controls. A hit for a control
       
   479 is registered in the area covered by both the control and its associated hit
       
   480 test. </p> <p>The diagram below represents three controls, each of which is
       
   481 rectangular but which appears on the screen as a non-rectangular bitmap. Only
       
   482 a hit on a bitmap area should register. This could be achieved by defining
       
   483 a single hit-test region in the shape (and position) of the three blue areas
       
   484 and associating it with each of the controls. The class that implements the
       
   485 hit-test region must implement the MCoeControlHitTest interface. </p> <fig id="GUID-5C856964-8553-543A-B7E2-8D5DCA9BF52C-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-21-22">
       
   486 <title>              Hit-test region example            </title>
       
   487 <image href="GUID-CF34E1C9-48E5-5B91-A48E-C68E647116A0_d0e53527_href.png" placement="inline"/>
       
   488 </fig> <codeblock id="GUID-D2AF9CEB-3072-5239-A157-D19852076CEF-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-21-23" xml:space="preserve">
       
   489 class MCoeControlHitTest
       
   490         ...
       
   491     public:
       
   492         virtual TBool HitRegionContains( const TPoint&amp; aPoint, const CCoeControl&amp; aControl ) const = 0;
       
   493 </codeblock> <p>A hit test is associated with a control using <codeph>CCoeControl::SetHitText()</codeph>.
       
   494 The base class implementation of <codeph>HandlePointerEventL()</codeph> performs
       
   495 the following test: </p> <codeblock id="GUID-35C26C5B-A19A-528A-B5BE-B8177F81B05D-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-21-25" xml:space="preserve">
       
   496     ...
       
   497     const MCoeControlHitTest* hitTest = ctrl-&gt;HitTest() ;
       
   498     if( hitTest )
       
   499         {
       
   500         if( hitTest-&gt;HitRegionContains( aPointerEvent.iPosition, *ctrl ) &amp;&amp;
       
   501                         ctrl-&gt;Rect().Contains( aPointerEvent.iPosition ) )</codeblock> <p>Note
       
   502 that this is performed by a container when deciding which lodger to pass the
       
   503 event onto. This snippet also illustrates how a control can find where (<codeph>iPosition</codeph>)
       
   504 the pointer event actually occurred. </p> <p>Pointer support includes dragging
       
   505 &amp; grabbing. See <xref href="GUID-1FFA0073-3D83-388E-A824-08C31F90CC54.dita"><apiname>TPointerEvent</apiname></xref>. </p> </section>
       
   506 <section id="GUID-FE221E89-1817-5A73-8FBA-212FBC030766-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-22"><title>Implementing
       
   507 the Object Provider (MOP) interface</title> <p>The <xref href="GUID-F32E2F00-B68F-59B2-AABA-181E16354C86-GENID-1-8-1-3-1-1-7-1-7-1-9-1.dita">Object
       
   508 Provider mechanism</xref> exists to allow a control to call a function on
       
   509 another control in the hierarchy for which it does not have a reference. It
       
   510 simply calls <codeph>MopGetObject()</codeph> specifying the interface containing
       
   511 the function. It may also call <codeph>MopGetObjectNoChaining()</codeph> to
       
   512 inquire of a specific object whether it supports the requested interface. </p> <p>Only
       
   513 controls which wish to supply an interface require customisation. In order
       
   514 to be identifiable an interface must have an associated UID. The following
       
   515 code samples show how <xref href="GUID-0DC77F9B-718A-31DF-B076-3C3F83378BF4.dita"><apiname>CEikAlignedControl</apiname></xref> implements and
       
   516 supplies <xref href="GUID-65610725-E873-3F8D-AD60-FC0AD726E0C5.dita"><apiname>MEikAlignedControl</apiname></xref>: </p> <codeblock id="GUID-9926598F-163B-5ACF-B320-66B43D331E1A-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-22-4" xml:space="preserve">
       
   517 class MEikAlignedControl
       
   518         ...
       
   519     public:
       
   520         DECLARE_TYPE_ID( 0x10A3D51B )  // Symbian allocated UID identifies this interface
       
   521         ...
       
   522 </codeblock> <codeblock id="GUID-1C2FE28B-7A1F-5726-8690-50FBA8672A2C-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-22-5" xml:space="preserve">
       
   523 class CEikAlignedControl : public CCoeControl, public MEikAlignedControl
       
   524     {
       
   525         ...
       
   526     private: //from CCoeControl
       
   527         IMPORT_C TTypeUid::Ptr MopSupplyObject( TTypeUid aId ) ;
       
   528         ...
       
   529 </codeblock> <codeblock id="GUID-03CD8613-9C1D-556C-94B7-5D9A1C23FF83-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-22-6" xml:space="preserve">
       
   530 EXPORT_C TTypeUid::Ptr CEikAlignedControl::MopSupplyObject( TTypeUid aId )
       
   531     {
       
   532     if( aId.iUid == MEikAlignedControl::ETypeId )
       
   533         return aId.MakePtr( static_cast&lt;MEikAlignedControl*&gt;( this ) ) ;
       
   534 
       
   535     return CCoeControl::MopSupplyObject( aId ) ; // must call base class!
       
   536     }
       
   537 </codeblock> <p>To get an interface from the object provider framework the
       
   538 caller must use a pointer to the interface. </p> <codeblock id="GUID-CB641ADD-5AFE-5D72-A909-CD3F0C3BAA9A-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-22-8" xml:space="preserve">
       
   539     ...
       
   540     MEikAlignedControl* alignedControl = NULL ;
       
   541     MyControl-&gt;MopGetObject( alignedControl ) ;
       
   542     if ( alignedControl )
       
   543         {
       
   544         ... // etc.</codeblock> <p>To get an interface from a specific object
       
   545 the caller may use the no-chaining function call. </p> <codeblock id="GUID-AEB5EB12-6289-5DCB-BF07-71B8F7A67E33-GENID-1-8-1-6-1-1-4-1-6-1-9-1-2-22-10" xml:space="preserve">
       
   546     ...
       
   547     MEikAlignedControl* alignedControl = NULL ;
       
   548     aControl-&gt;MopGetObjectNoChaining( alignedControl ) ;
       
   549     if ( alignedControl )
       
   550         {
       
   551         ... // etc.</codeblock> </section>
       
   552 </conbody></concept>