Basic Drawing

This section looks at the classes that form the foundations for performing basic drawing. You should be familiar with the application framework, as shown in Chapter 4, and also with the use of controls, as shown in Chapter 5, since most of the examples will perform drawing within a CCoeControl -derived class. This hides away most of the complexities of explicitly having to create a Window Server client, and it provides a window to draw to.

You can create your own base for drawing without CCoeControl , but this is more complex and is unnecessary for illustrating the basic concepts. The function calls for drawing shapes , bitmaps and fonts are exactly the same, whether or not a CCoeControl is used, as drawing always takes place to a window using a graphics context.

The following code snippets are taken from the BasicDrawing application's Draw() function, and this simply draws some horizontal lines on the screen with differing colors and widths, as shown in Figure 11-2.

Figure 11-2. Basic drawing screen.


Initially a handle on the system graphics context is obtained. A graphics context performs various drawing functions, and later in the function it will be used to draw lines between two points on the screen using the DrawLine() method:

 void CBasicDrawingContainer::Draw(const TRect& /*aRect*/) const    {    // Get graphics context and clear it    CWindowGc& gc = SystemGc();    gc.Clear();    ... 

The TPoint class is used to represent coordinate points on the screen, while TSize represents a graphical object's width and height:

 ... // Set up points and increment value for drawing TPoint point1(KPoint1Begin, KPoint1End); TPoint point2(KPoint2Begin, KPoint2End); // Set up pen sizes for drawing TSize penSize(KPenSize, KPenSize); ... 

In order to make the drawn lines visible, the graphics context's pen is set to an appropriate color . The trgb class represents color, and colors are defined using the AKN_LAF_COLOR() macro (see the subsection Color and Display Modes later in this chapter).

The pen is used to determine the physical appearance of the line to be drawn. A pen has a style property, and this sets whether the line is solid, dotted or dashed. A line is then drawn on the screen from the location specified by the x and y coordinates belonging to point1 to the location specified by point2 :

 ... //Set up drawing colors by using the AKN_LAF_COLOR() macro TRgb colorBlue = AKN_LAF_COLOR(KColorBlue); TRgb colorRed = AKN_LAF_COLOR(KColorRed); TRgb colorGreen = AKN_LAF_COLOR(KColorGreen); TRgb colorYellow = AKN_LAF_COLOR(KColorYellow); // Set pen to be blue and solid. Then draw line gc.SetPenColor(colorBlue); // make pen solid gc.SetPenStyle(CGraphicsContext::ESolidPen); gc.DrawLine(point1, point2); ... 

The function continues with similar operations being performed. In the first block the pen color is changed from blue to red, and the pen style is updated. You can also see that the pen size is altered using the TSize object, penSize . TSize is a generic class embodying size and is used in conjunction with various objects that are drawn to the screen, such as shapes, bitmaps and fonts.

TPoint and TSize have their mathematical operators overloaded; this allows a developer to quickly apply transformations, such as increasing the pen size and incrementing the point coordinates:

 ... // Draw Red Line, increase pen size and set pen to be dotted gc.SetPenColor(colorRed); // make pen dotted gc.SetPenStyle(CGraphicsContext::EDottedPen); // set pen size to (2,2) gc.SetPenSize(penSize); // increment starting point of line point1 += KIncrementPoint; // increment ending point of line point2 += KIncrementPoint; gc.DrawLine(point1, point2); // Draw Green Line gc.SetPenColor(colorGreen); // make pen dashed gc.SetPenStyle(CGraphicsContext::EDashedPen); // increase the size of the pen penSize += KIncrementPenSize; // set pen size to increment value gc.SetPenSize(penSize); // increment starting point of line point1 += KIncrementPoint; // increment ending point of line point2 += KIncrementPoint; gc.DrawLine(point1, point2); ... } 

This Draw() function covers many of the fundamental concepts that form the basis for drawing in a Series 60 application ”in particular, screen geometry, graphics devices and contexts, color and pens.

Screen Coordinates and Geometry

The coordinate system of the screen of a Series 60 device has the standard origin ( 0, 0 ) at the top left-hand corner of the screen. Moving rightward and downward from the origin increases the x and y coordinates, respectively. Measurements are in pixels, and the minimum Series 60 screen size is 176 by 208 pixels. Graphics tend to be drawn in a rectangular fashion, regardless of their true shape, and the geometry classes available reinforce this. The classes of note are TPoint , TSize and TRect . Their members are public for ease of use.

  • TPoint ” A two-dimensional x, y Cartesian coordinate position represented using two TInt members: iX and iY . Both members can be reset by passing the new coordinate values into the SetXY() function.

  • TSize ” Contains two public TInt members, iWidth and iHeight , to represent a two-dimensional size value. The SetSize() function is equivalent to SetXY() of TPoint and changes the size to the parameters passed in.

  • trect ” Represents a rectangular area derived from two TPoint members. The top left corner of the rectangle is stored in the iTl member, the bottom right corner in the iBr member. A somewhat confusing aspect is that iBr lies (1, 1) pixels outside the rectangle, such that iBr.iX iTl.iX is the width of the rectangle. trect has many useful functions ”for example, Center() returns the center point of the rectangle, and Intersects() determines whether this trect overlaps another.

Throughout the examples in this chapter TPoint , TSize and trect will be employed extensively. They are essential for drawing graphics to the screen with the desired positions and size. Figure 11-3 shows the relation between these classes.

Figure 11-3. Relation of the geometry classes TPoint, TSize and TRect.


Graphics Devices and Graphics Contexts

A graphics device represents what is being drawn to ”for example, the screen, a bitmap in memory, or even a printer. Attributes of graphics devices include the size of the device area and the number of colors supported by that device.

In order to be able to perform drawing operations they must have an associated graphics context and consequently a CreateGraphicsContext() function. The abstract class CGraphicsDevice provides an interface for all graphics devices, while CBitmapDevice is an interface for bitmapped graphics devices derived from CGraphicsDevice .

CGraphicsDevice provides functions for obtaining a device's current display mode, its size and the number of font typefaces associated with it.

CBitmapDevice allows you to obtain information about particular pixels and device scan-lines. CWsScreenDevice and CFbsBitmapDevice are concrete graphics device implementations representing the device screen via the Window Server and an in-memory bitmap, respectively. Their associated graphics contexts are CWindowGc and CFbsBitGc . By drawing inside a CCoeControl class, the BasicDrawing example does not require an explicit reference to a particular graphics device.

Figure 11-4 shows some of the various types of graphics devices and how they are architecturally related .

Figure 11-4. Inheritance relationship of a selection of graphics device types.


Table 11-3 provides an overview of the classes shown in Figure 11-4.

Table 11-3. Overview of Graphics Device Classes

Graphics Device

Description

CGraphicsDevice

Abstract base class for graphics devices.

CBitmapDevice

Abstract base class for bitmapped graphics devices.

CFbsDevice

Abstract base class for devices that use the Font and Bitmap Server for drawing fonts and bitmaps.

CPrinterDevice

Abstract base class for devices that make use of printing.

CWsScreenDevice

Concrete representation of the device screen in software employing the Window Server.

CFbsBitmapDevice

Concrete implementation using a bitmap maintained by the Font and Bitmap Server as a graphics device.


Graphics devices and other key graphics classes often have methods that refer to Twips . Twips are a device-independent method for measurement, with a single twip equal to 1/1440th of an inch. This contrasts with pixels, whose size is device dependent.


Graphics contexts are used to perform the physical drawing to a graphics device. Consequently, they contain numerous functions for drawing shapes, text and bitmaps. As it would be cumbersome to have to provide attributes ”for example, the color of a shape or the font of some text ”every time a drawing function is called, they are contained within settings variables of the graphics context. This is illustrated in the BasicDrawing example, where the pen color and style are set before a line is drawn, and any subsequent drawing operations will use these properties unless they are explicitly changed:

 // Set pen to be blue and solid. Then draw line gc.SetPenColor(colorBlue); // make pen solid gc.SetPenStyle(CGraphicsContext::ESolidPen); gc.DrawLine(point1, point2); 

The variety of graphics context functions and types will become evident as the chapter unfolds and the example applications illustrate bitmap, text, shape and animation drawing.

Color and Display Modes

Colors are represented by the trgb class, which is a 32-bit value employing 8 bits each for Red, Green and Blue, with 8 bits spare. As Series 60 is highly customizable for different licensees , the color scheme of the user interface can be changed. In order to ensure consistency between colors and the palette in use, it is necessary to employ the AKN_LAF_COLOR() macro to define colors. This can be found in the aknutils.h header file, which should be included by your application code.

Table 11-4 lists some common integer values and the corresponding color they will produce when passed into the AKN_LAF_COLOR() macro. (A full list of values can be found in the Series 60 Style Guide, in the SDK documentation.)

An example of how to use the AKN_LAF_COLOR macro is shown here:

 const TInt KColorYellow = 5; TRgb colorYellow = AKN_LAF_COLOR(KColorYellow); // Set pen to be yellow gc.SetPenColor(colorYellow); 

If the color scheme is changed by the user, then applications are informed of the change with the value KEikMessageColorSchemeChange passed to CCoeControl::HandleResourceChange() . Any derived control class may override this method to take appropriate action. If you have stored a trgb value as member data, it should be reset whenever the palette changes.


The range of colors available for use is subject to two key factors: the number of colors the device can physically display, and the current display mode. Display modes are the color depths available and are represented by the tdisplayMode enumeration.

Table 11-4. Color Palette Values for the AKN_LAF_COLOR() Macro

Integer Value

Corresponding Color

Integer Value

Corresponding Color

White

137

Dark Brown

5

Yellow

141

Dark Purple

9

Light Yellow

146

Light Green 2

13

Light Purple

159

Green 2

17

Dark Yellow

172

Grey 12

20

Light Red

176

Dark Violet

23

Orange

185

Green

35

Red

210

Blue

43

Grey 3

215

Black

51

Light Brown

216

Grey 1

76

Light Green

217

Grey 2

84

Light Violet

218

Grey 4

86

Grey 6

219

Grey 5

92

Light Purple

220

Grey 7

95

Brown

221

Grey 8

105

Purple

222

Grey 10

107

Dark Red

223

Grey 11

120

Light Blue

224

Grey 13

129

Grey 9

225

Grey 14

131

Dirty Dark Yellow

 

Obviously the number of colors in a display mode cannot exceed the amount a device is physically able to display. Series 60 devices support a minimum 12-bit display of 4096 colors expressed by the EColor4K display mode. This uses 4 bits for Red, Green and Blue with 4 bits spare to make 16-bits (2 bytes) for ease of use ”it is faster to move bytes than to perform bit operations. Some current Series 60 devices support a 16-bit display, expressed by EColor64K .

Devices have a "preferred display mode" to which graphics will be converted for display. As time will be spent performing any conversion, there can be a performance bottleneck if your graphics are not in the "preferred display mode." For static graphics this is not so much of a problem, but for animations and games you may need to take account of this fact ”multiple versions of bitmaps can be created, with only the applicable ones installed, or loaded at runtime.

Pens and Brushes

Pens provide attributes of the outline, and brushes attributes of the filled regions , of drawable items, such as shapes. Both have color and style properties, the styles being represented by the TPenStyle and TBrushStyle enumerations, respectively. An example of a pen style would be EDashedPen that will draw a dashed outline, while EVerticalHatchBrush will fill a region with a vertical line pattern. For a full listing of the styles available look in the \epoc32\include\gdi.h header file in the root directory of your SDK.

The View from a Window and the Relationship with CCoeControl

From the BasicDrawing application it would appear that there are no references to windows , yet drawing takes place in a window. How can this be? By employing the application framework, and in particular using a class derived from CCoeControl , the window-related aspects of drawing are hidden.

Indeed, every CCoeControl has an association to a window, either by owning it or by lodging in the window of another control. CCoeControl has two functions with respect to this, CreateWindowL() and SetContainerWindowL() , one of which should always be called at construction time. It is possible to gain a handle on a CCoeControl 's window by calling its Window() function.

The Window Server will redraw areas of a window, should they be marked as invalid. This can occur because all, or part, of a control has been temporarily overlapped by another, and the overlapping control has been dismissed. The region of the window that was hidden by the overlapping control will now be marked as invalid, and the control will have to redraw that area of the window that it occupies.

To "force" a redraw of the control, the DrawNow() or DrawDeferred() function of CCoeControl can be called, or areas of the control's window can be marked as invalid ”this is achieved by obtaining a handle to the window and calling its Invalidate() function. Invalidating an area will cause a redraw initiated by the Window Server to inform the control's window to begin redrawing. This latter mechanism is used in the Animation example.

When redrawing without using the DrawNow() function, care must be taken not to draw outside the boundary of the control. This is easily achieved through clipping, which is implemented through the SetClippingRect() function of a graphics context. This should be provided with a TRect parameter of suitable dimensions.


Another advantage of employing a CCoeControl to handle drawing is that a variety of useful functions are provided "for free" that enable you to perform a wide variety of tasks ” ranging from querying screen devices to employing resource files for handling localized descriptor strings. The control environment member variable of CCoeControl , iCoeEnv , is particularly valuable in this respect. Table 11-5 lists some of the functions this provides. For a list of all of the functions available, look in the file \epoc32\include\coemain.h in the root directory of your SDK, or in the SDK documentation for CCoeEnv .

Table 11-5. Useful Control Environment Functions

CCoeEnv Function

Description

AppUi()

Obtains a handle to the application AppUi, as type CCoeAppUiBase .

FsSession()

Obtains a handle to a File Server session.

WsSession()

Obtains a handle to the application's Window Server session.

NormalFont()

Obtains a handle to the Normal font of the system.

ScreenDevice()

Obtains a handle to the screen device.

ReadResource()

Reads a descriptor resource into a descriptor variable.

AllocReadResourceL()

Reads general resource into a descriptor for later conversion into true class type ”for example, a User Interface component declared in a resource file.

SimulateKeyEventL()

Simulates key presses and can aid debugging.


Drawing without the application framework is possible, but it would be much more complex, as you would have to write your own Window Server client to provide the functionality offered by CCoeControl . One advantage would be less overhead when communicating with the Window Server, but a full illustration is beyond the scope of this chapter. However, examples are provided by the SDK. (In Series 60 2.x they can be found in the directory \Examples\graphics\ws in the root directory of your SDK ”in earlier versions of the SDK they reside in \ Epoc32Ex\graphics\ws . ) As touched upon earlier, drawing will still take place via a graphics context, so all of the drawing concepts covered here are still valid.



Developing Series 60 Applications. A Guide for Symbian OS C++ Developers
Developing Series 60 Applications: A Guide for Symbian OS C++ Developers: A Guide for Symbian OS C++ Developers
ISBN: 0321227220
EAN: 2147483647
Year: 2003
Pages: 139

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net