Symbian3/SDK/Source/GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290.dita
changeset 8 ae94777fff8f
child 13 48780e181b38
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Symbian3/SDK/Source/GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290.dita	Fri Jun 11 12:39:03 2010 +0100
@@ -0,0 +1,552 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
+<!-- This component and the accompanying materials are made available under the terms of the License 
+"Eclipse Public License v1.0" which accompanies this distribution, 
+and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
+<!-- Initial Contributors:
+    Nokia Corporation - initial contribution.
+Contributors: 
+-->
+<!DOCTYPE concept
+  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
+<concept id="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290" xml:lang="en"><title>How to
+write controls</title><prolog><metadata><keywords/></metadata></prolog><conbody>
+<p>Cone itself does not provide any concrete controls. Uikon and the UI variant
+libraries provide a large number of 'stock' controls for application writers.
+Application writers often need to supplement the standard set of controls
+with application specific controls of their own. These may be completely new
+controls or, more often, compound controls which contain a number of standard
+controls. </p>
+<p>This section describes how to create controls and how to integrate them
+in to the control framework. It is divided into the following sections: </p>
+<p><xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290/GUID-341017B2-8CF9-5124-8D20-C75A8A51F0B7">Creating
+a control</xref>  </p>
+<p><xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290/GUID-3F0E8223-2218-5C95-AFBC-D66AD1DB12A7">Window
+owning or not?</xref>  </p>
+<p><xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290/GUID-795EBF51-AD26-513E-9A82-A99C629CE779">Creating
+a compound control</xref>  </p>
+<p><xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290/GUID-795EBF51-AD26-513E-9A82-A99C629CE779">Size,
+position and layout</xref>  </p>
+<p><xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290/GUID-351911EE-87C7-5D11-8434-BA7FD3741745">Drawing
+and refreshing</xref>  </p>
+<p> <xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290/GUID-FF7DB067-24AD-50C3-BF52-952F836609B0">Drawing
+backgrounds</xref>  </p>
+<p> <xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290/GUID-54C6A39A-CBD0-52E5-8CD0-76BE22247A54">Drawing
+text</xref>  </p>
+<p> <xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290/GUID-D1AED2A8-94AC-54BB-9CEB-C8C3643AFBBD">Drawing
+graphics</xref>  </p>
+<p><xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290/GUID-AC723EE4-1482-59C5-9F13-CAE119C7800D">Handling
+events</xref>  </p>
+<p><xref href="GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290.dita#GUID-B84FA223-3DFD-58C5-8CEF-C5AA73AA6290/GUID-FE221E89-1817-5A73-8FBA-212FBC030766">Implementing
+the Object Provider (MOP) interface</xref>  </p>
+<section id="GUID-341017B2-8CF9-5124-8D20-C75A8A51F0B7"><title>Creating a
+control</title> <p>A control is a class which derives from <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref>.
+It should have a public constructor and, if any leaving function calls or
+memory allocations are required during construction, a <codeph>ConstructL()</codeph> function.
+The majority of re-useable and configurable controls have a <codeph>ConstructFromResourceL()</codeph> function
+which allows a specific instance of a control to be configured using an application's
+resource file. Obviously any memory allocated must be freed in the destructor.
+Before a control is drawn to the screen it must be activated. The <codeph>ActivateL()
+function</codeph> may be overriden to perform last-minute configuration (but
+must call the function in the base class). </p> <codeblock id="GUID-18D48E7E-9846-5CE0-BE1E-FAB723419B90" xml:space="preserve">
+Class CMyControl : public CCoeControl
+    {
+    public:
+        CMyControl() ;
+        void ConstructL(...) ;
+        // from CCoeControl
+        void ConsructFromResourceL( TResourceReader&amp; aReader ) ; 
+    private:
+        ~CMyControl() ;
+
+    // additional functions to handle events 
+    // additional functions to draw the control
+    // additional functions to determine the size, layout and position the control
+    }</codeblock> </section>
+<section id="GUID-3F0E8223-2218-5C95-AFBC-D66AD1DB12A7"><title>Window owning
+or not? </title> <p>The decision over whether to make a control window owning
+or not is usually straightforward. Each view requires a window, so the top-level
+control must be window-owning and a child of the AppUi. Below this a window
+owning control is normally only necessary where a sense of layering is required:
+for instance a pop-up window or a scrolling window. Dialogs and menus are
+window owning controls but these are normally implemented in the Uikon and
+UI variant libraries and do not require custom derivation from <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref>.
+Unnecessary window-owning controls should be avoided as they require more
+infrastructure, place greater demand on the Window Server and reduce performance. </p> <p>If
+a control must be window owning its window must either be created in the <codeph>ConstructL()</codeph> function
+or by the caller. The former is preferred. There are several overloads of
+the <codeph>CreateWindowL()</codeph> and <codeph>CreateBackedUpWindowL()</codeph> functions.
+Those which do not take a parent parameter create a top-level window which
+is a child of the root window. </p> <p>If a control is not window owning its <codeph>SetContainerWindowL()</codeph> function
+must be called when it is instantiated. </p> <p>If it can, the Framework will
+automatically set up the parent pointer when the window, or associated window
+relationship is established. If it cannot do this, because <codeph>CreateWindowL()</codeph> or <codeph>SetContainerWindowL()</codeph> did
+not provide a <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref>, the parent pointer (and MopParent)
+may be set expicitly using <codeph>SetParent()</codeph> and <codeph>SetMopParent()</codeph>. </p> </section>
+<section id="GUID-795EBF51-AD26-513E-9A82-A99C629CE779"><title>Creating a
+compound control</title> <p>Most applications UIs are built from compound
+controls. Many custom controls are built up from stock controls and are therefore
+also compound controls. When a compound control is constructed it constructs
+its components in its <codeph>ConstructL()</codeph> function. When it receives
+commands itself, such as <codeph>ActivateL()</codeph> and <codeph>DrawNow()</codeph> it
+passes them on to each of its components. In most cases the Framework does
+much of the donkey work as long as the compound control has been constructed
+correctly. </p> <p>There are now two methods of creating and managing lodger
+controls. The first method described is the one that should be used. </p> <codeblock id="GUID-F77661F7-6A68-58DB-B875-9D957A937617" xml:space="preserve">
+void MyControl::ConstructL( ... )
+    {
+    // initialise the component array. This must be called once (subsequent calls have no effect)
+    InitComponentArrayL() ; 
+
+    // construct each component control and add it to the component array.
+    CComponent* myComponent = new (ELeave) CComponent ;
+    Components().AppendLC( myComponent ) ; // or InsertLC or InsertAfterLC().  Places item on cleanup stack.
+    myComponent-&gt;ConstructL() ;
+    myComponent-&gt;SetThisAndThatL() ;
+    CleanupStack::Pop( myComponent ) ;    
+    }</codeblock> <p>The return value of the insert and append methods is
+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.
+It will remain valid when other items are inserted or deleted, or even if
+the whole array is re-ordered. </p> <p>The insert and append methods leave
+the component on the Cleanup Stack using a dedicated Cleanup Item that protects
+the parent's array as well as the component itself. </p> <p>The insert and
+append methods allow each component to be given an ID. The ID must be unique
+only within the parent so typically a compound control will have an enum listing
+each of its children's IDs. <xref href="GUID-2D8BFBA2-79AC-364D-875D-E863CD4A2FE1.dita"><apiname>CCoeControlArray</apiname></xref> , accessed
+using <codeph>CCoeControl::Components()</codeph>, has a <codeph>ControlById()</codeph> method
+to retrieve components using their IDs. </p> <p>Components in the array are,
+by default, owned by the parent and will be deleted automatically when the
+parent is deleted. The default may be overridden using <codeph>CCoeControlArray::SetControlsOwnedExternally()</codeph>.
+The setting applies to all of the components. </p> <p>Controls may be removed
+from the array using one of the <codeph>Remove()</codeph> methods. These do
+not delete. </p> <codeblock id="GUID-9F9EC327-E7DE-59B8-838B-F5052E3750D3" xml:space="preserve">
+class CCoeControlArray
+        ...
+    public:
+        IMPORT_C TInt Remove(const CCoeControl* aControl);
+        IMPORT_C CCoeControl* Remove(TCursor aRemoveAt);
+        IMPORT_C CCoeControl* RemoveById(TInt aControlId);
+        ...
+</codeblock> <p>Using the component array as described is now the approved
+method of constructing and managing compound controls. In older versions of
+Symbian OS a specific method of handling components was not provided and developers
+were obliged to design their own. Bypassing the component array is still possible.
+It is necessary to allocate and store the components (typically as member
+data) and to implement the <codeph>CountComponentControls()</codeph> and <codeph>ComponentControl()</codeph> functions
+to return the number of components and a specified component to the framework.
+The new method offers significant advantages when controls are added and removed
+dynamically or are dependant on run-time data. The new method is also integrated
+with new layout managers. </p> </section>
+<section id="GUID-7E144310-9AF4-50F1-AD8A-9F9E05D554D1"><title>Size, position
+and layout</title> <p>There are several factors which contribute to a control's
+size and position. The control itself will require a certain size in order
+to display itself (and its data) correctly. The control's container will be
+responsible for positioning the control but is also likely to be responsible
+for positioning other controls - each of which will have its own requirements.
+Additionally there are the requirements of the UI's look and feel that must
+be complied with. </p> <p>Each control is responsible for implementing its
+own <codeph>Size()</codeph> function. </p> <p>Until Symbian OS version 9.1
+it was normal to write layout code for simple and compound controls in the <codeph>SizeChanged()</codeph> function.
+This is called by the framework, as one might expect, when a control's size
+(its 'extent') is changed. From 9.1, however, Symbian OS supports the use
+of the layout manager interface (<xref href="GUID-A622B8C7-60F4-38E8-B102-14883BCBA249.dita"><apiname>MCoeLayoutManager</apiname></xref>) and
+the <codeph>SizeChanged()</codeph> function is now implemented in the base
+class. (Note that if a control's position is changed, with no size change,
+using <codeph>CCoeControl::SetPosition()</codeph> its <codeph>PositionChanged()</codeph> function
+is called and that default implementation of <codeph>PositionChanged()</codeph> is
+empty). </p> <codeblock id="GUID-53A10820-550A-52C2-AE80-D556FD77E8FA" xml:space="preserve">
+class MCoeLayoutManager
+        ...
+    protected:
+        IMPORT_C MCoeLayoutManager();
+    
+    public:
+        virtual TBool CanAttach() const = 0;
+        virtual void AttachL(CCoeControl&amp; aCompoundControl) = 0;
+        virtual void Detach(CCoeControl&amp; aCompoundControl) = 0;
+        virtual TSize CalcMinimumSize(const CCoeControl&amp; aCompoundControl) const = 0;
+        virtual void PerformLayout() = 0;
+        virtual TInt CalcTextBaselineOffset(const CCoeControl&amp; aCompoundControl, const TSize&amp; aSize) const = 0;
+        virtual void SetTextBaselineSpacing(TInt aBaselineSpacing) = 0;
+        virtual TInt TextBaselineSpacing() const = 0;
+        virtual void HandleAddedControlL(const CCoeControl&amp; aCompoundControl, const CCoeControl&amp; aAddedControl) = 0;
+        virtual void HandleRemovedControl(const CCoeControl&amp; aCompoundControl, const CCoeControl&amp; aRemovedControl) = 0;
+        virtual TInt HandleControlReplaced(const CCoeControl&amp; aOldControl, const CCoeControl&amp; aNewControl) = 0;
+        ...
+</codeblock> <p>A layout manager may be attached to a compound control. </p> <codeblock id="GUID-ACCD143C-8618-5606-B749-D7EFE5C83ACD" xml:space="preserve">
+class CCoeControl
+        ...
+    protected: 
+        IMPORT_C MCoeLayoutManager* LayoutManager() const;
+        IMPORT_C virtual void SetLayoutManagerL(MCoeLayoutManager* aLayoutManager);
+
+    public:
+        IMPORT_C virtual TBool RequestRelayout(const CCoeControl* aChildCtrl);
+        ...</codeblock> <p>The default implementations of <codeph>MinimumSize()</codeph> and <codeph>SizeChanged()</codeph> now
+use the layout manager. </p> <codeblock id="GUID-88340A33-A58C-5856-AD47-C2E1637DD45F" xml:space="preserve">
+EXPORT_C TSize CCoeControl::MinimumSize()
+    { 
+    const MCoeLayoutManager* layoutManager = LayoutManager();
+    if (layoutManager)
+        return layoutManager-&gt;CalcMinimumSize(*this);
+    else    
+        return iSize;
+    }
+
+EXPORT_C void CCoeControl::SizeChanged()
+    {
+    MCoeLayoutManager* layout = LayoutManager();
+    if (layout)
+        layout-&gt;PerformLayout();
+</codeblock> <p>The layout manager is responsible for the size and position
+of the component controls. In practice it's likely that the UI variant libraries
+will provide concrete layout managers. Application developers should use these
+as the basis for control-specific layout managers. </p> </section>
+<section id="GUID-351911EE-87C7-5D11-8434-BA7FD3741745"><title> Drawing and
+refreshing</title> <p>A fundamental requirement of most controls is that they
+are able to render themselves onto the screen. For most controls the drawing
+process involves outputting text, painting backgrounds (either plain or from
+a bitmap), drawing shapes (graphics objects) and drawing component controls. </p> <p>Screen
+drawing may be initiated by the application itself, following something within
+the application changing, or by the Window Server, due to something else in
+the system updating the screen while the application is visible. In both cases
+the control's <codeph>Draw()</codeph> function will be called automatically
+by the framework. For compound controls all of the components' <codeph>Draw()</codeph> functions
+will also be called - unless the component lies completely outside the area
+that requires redrawing. </p> <p>As a control writer you will probably have
+to implement a <codeph>Draw()</codeph> function. </p> <p>Here is the signature
+for <codeph>Draw()</codeph>: </p> <codeblock id="GUID-7A83E8B5-9673-5EBC-B628-674734A07E0F" xml:space="preserve">private:
+    void Draw( const TRect&amp; aRect ) const ;</codeblock> <p>Note that it
+is private, takes a <codeph>const TRect&amp;</codeph> as a parameter, must
+not leave and is <codeph>const</codeph>. </p> <p>It should only be called
+by the framework. Application initiated redraws should be through calls to <codeph>DrawNow()</codeph>, <codeph>DrawDeferred()</codeph> or
+custom functions for drawing smaller elements. </p> <p>The <codeph>aRect</codeph> parameter
+is the part of the control that requires drawing (refreshing). </p> <p>The
+function is <codeph>const</codeph> and non-leaving because it is intended
+to support the decoupling of drawing actions from application state. </p> </section>
+<section id="GUID-FF7DB067-24AD-50C3-BF52-952F836609B0"><title>Drawing backgrounds</title> <p>A
+control's background is typically determined by the current colour scheme
+or skin. It may be a plain colour or a bitmap. It's also possible that a control
+is to appear non-rectangular or transparent in which case some of the background
+will be the control underneath. Prior to Symbian OS 9.1 controls were required
+to clear and update their whole area and creating these effects was rather
+complex. From 9.1 controls are drawn 'backmost first'. </p> <p>Background
+drawing should be done by a dedicated background drawer - i.e. an object which
+implements the <xref href="GUID-88936D48-B801-3D9C-8A9D-3498807937CE.dita"><apiname>MCoeControlBackground</apiname></xref> interface. A background
+can be attached to a <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref> using <codeph>SetBackground()</codeph> and
+is used for that control and all of its children. When a control is drawn
+the framework looks for the nearest background up the run-time hierarchy and
+calls <codeph>MCoeControlBackground::Draw()</codeph>. </p> <p>UI variant libraries
+typically provide backgrounds. They are not owned by the controls to which
+they are attached. </p> </section>
+<section id="GUID-54C6A39A-CBD0-52E5-8CD0-76BE22247A54"><title>Drawing text</title> <p>Text
+must be drawn with the correct color, font, size and direction. As with backgrounds,
+these are determined at runtime according to UI customizations. This is achieved
+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.
+This is a smart pointer (note the use of the <codeph>-&gt;</codeph> operator
+to access <xref href="GUID-C8C7B785-B3CF-3488-AEB1-BE0A70F6C1F2.dita"><apiname>CCoeTextDrawerBase</apiname></xref> functions) which ensures that
+only one text drawer is allocated on the heap at a time. </p> <codeblock id="GUID-511A9CEE-F02C-5667-A334-3C61A2428F0F" xml:space="preserve">
+XCoeTextDrawer textDrawer( TextDrawer() );
+textDrawer-&gt;SetAlignment(iAlignment); 
+textDrawer-&gt;SetMargins(iMargin);
+textDrawer-&gt;SetLineGapInPixels(iGapBetweenLines);
+textDrawer.SetClipRect(aRect); // have to use . [dot] operator for SetClipRect() as not CCoeTextDrawerBase function.
+
+textDrawer.DrawText(gc, *iTextToDraw, Rect(), *Font());
+</codeblock> <p>Text drawers are typically provided by the UI variant library
+or skin manager. Controls within the run-time hierarchy can set the text drawer
+for their children by overriding <codeph>GetTextDrawer()</codeph>. </p> <p>Note
+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
+than a descriptor. Controls should store all display text in <xref href="GUID-07D86324-ED54-3FCD-B301-53B7A6E04AE3.dita"><apiname>TBidiText</apiname></xref> objects.
+Application writers should consider the implications of right-to-left layouts
+for languages such as Hebrew and Arabic. </p> <p>A control's <codeph>GetTextDrawer()</codeph> function
+might look something like this. It checks on the current state of the control
+(<codeph>IsDimmed()</codeph>) and passes the call on to a skin manager. </p> <codeblock id="GUID-155AD8EC-17DD-5155-BE20-23246A33695C" xml:space="preserve">
+EXPORT_C void CMyButtonControl::GetTextDrawer(CCoeTextDrawerBase*&amp; aTextDrawer, const CCoeControl* aDrawingControl, TInt /*aKey*/) const
+    {
+    const TInt textDrawerIndex = (IsDimmed() ? EButtonTextDimmed : EButtonText);
+
+    SkinManager::GetTextDrawer(aTextDrawer, KSkinUidButton, textDrawerIndex, aDrawingControl);
+    }
+</codeblock> <p>If the control is drawing text on its own graphics (and does
+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
+on the stack in its <codeph>Draw()</codeph> method and initiate it from the
+skin that it is currently using to draw its graphics, using the <codeph>CSkinPatch::TextDrawer()</codeph> method,
+like this: </p> <codeblock id="GUID-3DFDBF27-8744-5283-AC7B-EC512EEEBB7D" xml:space="preserve">
+const CSkinPatch&amp; skin = SkinManager::SkinPatch(KSomeSkinUid, KSomeSkinIndex, this);
+
+skin.DrawBitmap(gc, Rect(), aRect);
+XCoeTextDrawer textDrawer( skin.TextDrawer(KSomeSkinUid, ESomeSkinTextDimmed, this) );
+
+const CFont&amp; font = ScreenFont(TCoeFont::NormalFont);
+textDrawer.DrawText(gc, iText, rect, font);
+</codeblock> <p>The example above also illustrates how to retrieve the correct
+font. <xref href="GUID-2A12FE3B-47F2-3016-8161-A971CA506491.dita"><apiname>CFont</apiname></xref> objects must not be stored in control member
+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
+represents a font's size (logical or absolute in pixels) and style (plain,
+bold, italic, subscript, or superscript) should be used. </p> <codeblock id="GUID-864A57DB-BCDA-50B6-B876-9EF62CFB27C6" xml:space="preserve">
+class TCoeFont 
+        ...
+    public: 
+        IMPORT_C TCoeFont(TLogicalSize aSize, TInt aStyle, TInt aFlags = ENoFlags); 
+        IMPORT_C TCoeFont(TInt aHeightInPixels, TInt aStyle, TInt aFlags = ENoFlags); 
+        IMPORT_C TCoeFont(const TCoeFont&amp; aFont);
+        IMPORT_C TCoeFont();
+        ...</codeblock> <p>By creating a <xref href="GUID-463C1928-878D-3B06-ABFD-178BE1BAD776.dita"><apiname>TCoeFont</apiname></xref> object
+describing the properties of the desired font, a <xref href="GUID-2A12FE3B-47F2-3016-8161-A971CA506491.dita"><apiname>CFont</apiname></xref> object
+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>.
+A font provider can be attached to any <xref href="GUID-B06F99BD-F032-3B87-AB26-5DD6EBE8C160.dita"><apiname>CCoeControl</apiname></xref> and
+will keep information about the typeface used by that control and all controls
+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" xml:space="preserve">
+class CCoeControl
+        ...
+    public:
+        IMPORT_C const CCoeFontProvider&amp; FindFontProvider() const;
+        IMPORT_C void SetFontProviderL(const CCoeFontProvider&amp; aFontProvider);
+        ...
+        </codeblock> <p>To get hold of the <xref href="GUID-2A12FE3B-47F2-3016-8161-A971CA506491.dita"><apiname>CFont</apiname></xref> object
+a <codeph>Draw()</codeph> method can be implemented like this: </p> <codeblock id="GUID-45292362-1E39-59B0-AC7F-14C98592F059" xml:space="preserve">
+void CMyControl::Draw(const TRect&amp; aRect)
+    {
+    const CCoeFontProvider&amp; fontProvider = FindFontProvider();
+    const CFont&amp; font = fontProvider.Font(TCoeFont::LegendFont(), AccumulatedZoom());
+
+    XCoeTextDrawer textDrawer( TextDrawer() );
+    textDrawer-&gt;SetAlignment(EHCenterVCenter);
+    textDrawer.DrawText(gc, iText, rect, font);
+    }
+</codeblock> <p>For convenience there’s a <codeph>CCoeControl::ScreenFont()</codeph> method
+that locates the font provider and calls it with the control’s accumulated
+zoom: </p> <codeblock id="GUID-5974F900-84B7-5262-8428-88797911F94A" xml:space="preserve">
+class CCoeControl
+        ...
+    protected:
+        IMPORT_C const CFont&amp; ScreenFont(const TCoeFont&amp; aFont) const;
+        ...
+</codeblock> </section>
+<section id="GUID-D1AED2A8-94AC-54BB-9CEB-C8C3643AFBBD"><title>Drawing graphics</title><p>Controls
+draw graphics objects - lines, rectangles, shapes and bitmaps to a <keyword>graphics
+context</keyword>. The graphics context is provided by the Window Server and
+represents a group of settings appropriate for the physical device that is
+ultimately being drawn to. In most cases the device is a screen and a graphics
+context should be obtained using <codeph>CCoeControl::SystemGc()</codeph>. <codeph>CCoeControl::SystemGc()</codeph> gets
+the current graphics context from the run-time hierarchy. Controls in the
+hierarchy may override graphics context settings which will then be passed
+on to their children. <i>Controls should not get their graphics context directly
+from CCoeEnv as to do so would bypass the hierarchy</i>. </p> <codeblock id="GUID-DC2B7A84-BA93-5AE0-BABA-9CF6B156A54E" xml:space="preserve">
+void CMyControl::Draw( const TRect&amp; aRect )
+    {
+    CWindowGc&amp; gc = SystemGc() ; // get gc from run time hierarchy
+    TRect rect = TRect( Size() ) ;
+    if ( IsBlanked() )
+        {
+        // blank out the entire control
+        gc.SetPenStyle( CGraphicsContext::ENullPen ) ;
+        gc.SetBrushStyle( CGraphicsContext::ESolidBrush ) ;
+        TRgb blankColor = BlankingColor() ;
+        gc.SetBrushColor( blankColor ) ;
+        gc.DrawRect( rect ) ;
+        }
+    else
+        {
+        // draw masked bitmap in the centre of the control 
+        // The parent will draw the background 
+        TInt id = BitMapId() ;
+
+        TInt x = Size().iWidth - iBitmap[id]-&gt;SizeInPixels().iWidth ;
+        TInt y = Size().iHeight - iBitmap[id]-&gt;SizeInPixels().iHeight ;
+
+        TPoint pos = Rect().iTl ;
+        pos.iX = pos.iX + ( x / 2 ) ;
+        pos.iY = pos.iY + ( y / 2 ) ;
+
+        gc.BitBltMasked( pos, iBitmap[id], rect, iMaskBitmap, ETrue ) ;
+        }
+    }</codeblock> <p>Before a graphics context can be used it must be activated.
+After use it must be deactivated. Activation and deactivation are done automatically
+by the framework in <codeph>DrawNow()</codeph>, <codeph>DrawDeferred()</codeph> and <codeph>HandleRedrawEvent()</codeph> but
+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
+may be split into sub functions: <codeph>DrawThis()</codeph>, <codeph>DrawThat()</codeph>, <codeph>DrawTheOther()</codeph>.
+Each of these requires a corresponding <codeph>DrawThisNow()</codeph> and/or <codeph>DrawThisDeferred()</codeph> function. </p> <codeblock id="GUID-EDC0D6F1-61BC-552F-B56D-C32148ADECA3" xml:space="preserve">
+CMyControl::Draw()
+    {
+    DrawThis() ;
+    DrawThat() ;
+    DrawTheOther() ;
+    }</codeblock> <codeblock id="GUID-E026186D-7B55-5AB5-9391-8587E3510D6D" xml:space="preserve">
+CMyControl::DrawThisNow()
+    {
+    ActivateGc() ;
+    DrawThis() ;
+    DeactivateGc() ;
+    }</codeblock> </section>
+<section id="GUID-AC723EE4-1482-59C5-9F13-CAE119C7800D"><title>Handling events </title> <p>The
+Control Framework supports user interaction in two ways: key-press events
+and pointer events. Both types of event arrive through the Window Server though
+they each arrive in a slightly different way. Both are closely related to
+the concept of 'focus' and the location of the cursor. </p> <p><b>Handling
+key events </b> </p> <p>Key events are delivered to the AppUi. The Window
+Server channels them through the root window of its current window group which
+maps to the AppUi foreground application. The AppUi offers each key event
+to each of the controls on its control stack in priority order until one of
+the controls 'consumes' it. </p> <p>To receive key events a control must implement <codeph>CCoeControl::OfferKeyEventL()</codeph>.
+If it handles the event it must return <codeph>EKeyWasConsumed</codeph>: If
+it doesn't it must return <codeph>EKeyWasNotConsumed</codeph> so that the
+next control on the stack receives it. </p> <codeblock id="GUID-448E9DF8-9D63-5BA4-94A7-4FB4B96A6DEA" xml:space="preserve">
+TKeyResponse CMyControl::OfferKeyEventL( const TKeyEvent&amp; aKeyEvent, TEventCode aType)
+    {
+    TKeyResponse returnValue = EKeyWasConsumed ;
+    switch( aKeyEvent.iCode ) 
+        {
+        case EKeyEnter :
+            // do stuff
+            break ;
+        case EKeyEscape :
+            // do stuff :
+            break ;
+
+            ...
+                
+        default :
+            // did not recognise key event
+            returnValue = EKeyWasNotConsumed ;
+            break ;
+        }
+    return returnValue ;
+    }</codeblock> <p>The handling of key events will depend on the design
+and purpose of the control itself. Compound controls might need to keep track
+of an input <b>focus</b>, or <b>cursor</b>, and to pass key events amongst
+its lodgers. Input into one lodger might have an effect on another - pressing
+a navigation key might cause one control to lose the highlight and another
+to gain it, pressing a number key might cause a text editor to grow which
+might, in turn, require all of the components below it to shuffle downwards
+and a scroll bar to become visible (which might also require some controls
+to be laid out differently). </p> <p><b>Handling pointer events </b> </p> <p>Pointer
+events are slightly different as the position of the pointer, rather than
+of the focus, is significant. The Window Server passes a pointer event to
+the top-most visible window at the point of contact. The Framework uses the
+functions <codeph>ProcessPointerEventL()</codeph> and <codeph>HandlePointerEventL()</codeph> to
+work down the hierarchy. The Framework also uses the <xref href="GUID-A2BF9AE8-CF42-3D94-8763-66DB11EDDA46.dita"><apiname>MCoeControlObserver</apiname></xref> and
+focussing mechanisms to inform the observer of the controls that will be losing
+and gaining the focus. </p> <p><b>Using the Control Observer Interface</b></p><p>The
+Control Framework facilitates this type of relationship between a container
+and its lodgers with the <codeph>MCoeControlObserver</codeph> interface. Typically
+the container implements the interface and becomes the observer for each lodger
+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
+not need to specify an observer. An observer may observe any number of controls
+so <codeph>HandleControlEventL()</codeph> takes the observed control as a
+parameter. The other piece of information passed to the observer is a <codeph>TCoeEvent</codeph>.</p><codeblock xml:space="preserve">enum TCoeEvent
+    {
+    EEventRequestExit,
+    EEventRequestCancel,
+    EEventRequestFocus,
+    EEventPrepareFocusTransition,
+    EEventStateChanged,
+    EEventInteractionRefused
+	 };</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
+does it give any visible indication of focus. It is up to the application
+developer to ensure that only one control has the focus at a time, that the
+focus is correctly transferred between controls, that only appropriate controls
+receive the focus and that the focus is visible at all times.</p><codeblock xml:space="preserve">void CContainer::HandleControlEventL(CCoeControl* aControl, TCoeEvent aEventType)
+    {
+	 switch (aEventType)
+        {
+		   case EEventRequestFocus:
+			    {
+			    if( !(aControl-&gt;IsFocussed()) )
+				     {
+				     aControl-&gt;SetFocus( ETrue ) ;
+				     // remove focus from other controls
+				     for ( Tint ii = 0 ; ii &lt; CountComponentControls() ; ii++ ) 
+                     {
+					       CCoeControl* ctl = ComponentControl( ii ) ;
+					       if( ( ctl != aControl ) &amp;&amp; !( ctl-&gt;IsNonFocussing() ) )
+						        {
+						        aControl-&gt;SetFocus( EFalse ) ;
+						        }
+					       }
+				      }
+			     }
+			     break;
+	           ...
+		     }
+	    }</codeblock> <p>Control developers may implement <codeph>HandlePointerEventL()</codeph>,
+which is a virtual function, to perform pointer event functionality. The implementation
+must, however, call the base class function. </p> <p>Controls may modify their
+pointer area, possibly if they appear non-rectangular or overlap. To do so
+requires the addition of a hit test which describes a hit-test region. A hit-test
+region may cover all or part of one or more controls. A hit for a control
+is registered in the area covered by both the control and its associated hit
+test. </p> <p>The diagram below represents three controls, each of which is
+rectangular but which appears on the screen as a non-rectangular bitmap. Only
+a hit on a bitmap area should register. This could be achieved by defining
+a single hit-test region in the shape (and position) of the three blue areas
+and associating it with each of the controls. The class that implements the
+hit-test region must implement the MCoeControlHitTest interface. </p> <fig id="GUID-5C856964-8553-543A-B7E2-8D5DCA9BF52C">
+<title>              Hit-test region example            </title>
+<image href="GUID-CF34E1C9-48E5-5B91-A48E-C68E647116A0_d0e47970_href.png" placement="inline"/>
+</fig> <codeblock id="GUID-D2AF9CEB-3072-5239-A157-D19852076CEF" xml:space="preserve">
+class MCoeControlHitTest
+        ...
+    public:
+        virtual TBool HitRegionContains( const TPoint&amp; aPoint, const CCoeControl&amp; aControl ) const = 0;
+</codeblock> <p>A hit test is associated with a control using <codeph>CCoeControl::SetHitText()</codeph>.
+The base class implementation of <codeph>HandlePointerEventL()</codeph> performs
+the following test: </p> <codeblock id="GUID-35C26C5B-A19A-528A-B5BE-B8177F81B05D" xml:space="preserve">
+    ...
+    const MCoeControlHitTest* hitTest = ctrl-&gt;HitTest() ;
+    if( hitTest )
+        {
+        if( hitTest-&gt;HitRegionContains( aPointerEvent.iPosition, *ctrl ) &amp;&amp;
+                        ctrl-&gt;Rect().Contains( aPointerEvent.iPosition ) )</codeblock> <p>Note
+that this is performed by a container when deciding which lodger to pass the
+event onto. This snippet also illustrates how a control can find where (<codeph>iPosition</codeph>)
+the pointer event actually occurred. </p> <p>Pointer support includes dragging
+&amp; grabbing. See <xref href="GUID-1FFA0073-3D83-388E-A824-08C31F90CC54.dita"><apiname>TPointerEvent</apiname></xref>. </p> </section>
+<section id="GUID-FE221E89-1817-5A73-8FBA-212FBC030766"><title>Implementing
+the Object Provider (MOP) interface</title> <p>The <xref href="GUID-F32E2F00-B68F-59B2-AABA-181E16354C86.dita">Object
+Provider mechanism</xref> exists to allow a control to call a function on
+another control in the hierarchy for which it does not have a reference. It
+simply calls <codeph>MopGetObject()</codeph> specifying the interface containing
+the function. It may also call <codeph>MopGetObjectNoChaining()</codeph> to
+inquire of a specific object whether it supports the requested interface. </p> <p>Only
+controls which wish to supply an interface require customisation. In order
+to be identifiable an interface must have an associated UID. The following
+code samples show how <xref href="GUID-0DC77F9B-718A-31DF-B076-3C3F83378BF4.dita"><apiname>CEikAlignedControl</apiname></xref> implements and
+supplies <codeph>MEikAlignedControl</codeph>: </p> <codeblock id="GUID-9926598F-163B-5ACF-B320-66B43D331E1A" xml:space="preserve">
+class MEikAlignedControl
+        ...
+    public:
+        DECLARE_TYPE_ID( 0x10A3D51B )  // Symbian allocated UID identifies this interface
+        ...
+</codeblock> <codeblock id="GUID-1C2FE28B-7A1F-5726-8690-50FBA8672A2C" xml:space="preserve">
+class CEikAlignedControl : public CCoeControl, public MEikAlignedControl
+    {
+        ...
+    private: //from CCoeControl
+        IMPORT_C TTypeUid::Ptr MopSupplyObject( TTypeUid aId ) ;
+        ...
+</codeblock> <codeblock id="GUID-03CD8613-9C1D-556C-94B7-5D9A1C23FF83" xml:space="preserve">
+EXPORT_C TTypeUid::Ptr CEikAlignedControl::MopSupplyObject( TTypeUid aId )
+    {
+    if( aId.iUid == MEikAlignedControl::ETypeId )
+        return aId.MakePtr( static_cast&lt;MEikAlignedControl*&gt;( this ) ) ;
+
+    return CCoeControl::MopSupplyObject( aId ) ; // must call base class!
+    }
+</codeblock> <p>To get an interface from the object provider framework the
+caller must use a pointer to the interface. </p> <codeblock id="GUID-CB641ADD-5AFE-5D72-A909-CD3F0C3BAA9A" xml:space="preserve">
+    ...
+    MEikAlignedControl* alignedControl = NULL ;
+    MyControl-&gt;MopGetObject( alignedControl ) ;
+    if ( alignedControl )
+        {
+        ... // etc.</codeblock> <p>To get an interface from a specific object
+the caller may use the no-chaining function call. </p> <codeblock id="GUID-AEB5EB12-6289-5DCB-BF07-71B8F7A67E33" xml:space="preserve">
+    ...
+    MEikAlignedControl* alignedControl = NULL ;
+    aControl-&gt;MopGetObjectNoChaining( alignedControl ) ;
+    if ( alignedControl )
+        {
+        ... // etc.</codeblock> </section>
+</conbody></concept>
\ No newline at end of file