Drawing in Views
****************

Although GNUstep readily provides most of the objects you'll need for creating GUI's, you may sometimes want to create your own view's. The first thing you will need to do is subclass NSView. You may wish to consider first whether or not it is necessary to build a NSView subclass. NSControl may be more useful for your needs, especially if what you need to achieve fits within the Cell/Control concept that is modelled in those classes.

If you decide that you need to subclass NSView, classes and methods exist to make drawing consistent, especially if you plan to port your code across to Cocoa. GNUstep provides two important classes for drawing: NSAffineTransform and NSBezierPath.  There is also methods in NSImage and the NSFont* classes to render images and text.

Writing drawing code
====================

All drawing code in GNUstep stems from calls to a NSView method called -drawRect:. It's in here that most of the drawing magic happens. GNustep sets everything up for your class to begin drawing within it's bounds before this method is called. When this method is called, it becomes your view's responsibility to redraw itself within the rectangle provided.

Importantly, it sets the origin of your bounds to the bottom left corner of your view and it sets a clipping rectangle around the frame of your view, to ensure that any drawing code you call does not trash your parent view or any subviews of your parent view.  (The origin for your bounds may have been shifted from the bottom-left corner of the frame rectangle by previous calls to NSView methods made by code in your programme. If you haven't done this, then the defaults apply.)

This way, you are not required to calculate your position within the window. Instead, you can assume that your origin is at (0,0) in the bottom-left corner, and one point is approximately 1/72 of an inch, corresponding to a pixel.

NSAffineTransform
=================

NSAffineTransform is used to perform coordinate transformations so that you can transparently resize and shift the elements in views. It is used quite extensively in the internal implementation of the GUI library and the backends, so it's worth taking advantage of. For more information about affine transformations, see Affine Transformations.

To stretch the coordinate system, use -scaleBy: method with a scaling factor, or scaleXBy:yBy: to scale each axis differently. The coordinate system can be rotated counter-clockwise by using the rotateByDegrees: or the rotateByRadians methods. It can be shifted using the translateXBy:yBy: method.

A number of methods are provided for transforming rectangles, sizes and points with the affine transform. Take a look at the sizeInMatrixSpace:, rectInMatrixSpace and transformPoint methods. Note that GNUstep provides more convenience methods than Cocoa does.

For those familiar with Postscript matrices, NSAffineTransforms' can be set and instantiated using those. Check out the NSAffineTransformStruct for transporting the matrix elements, and -setTransformStruct: in NSAffineTransform.

NSBezierPath
============

This class is an abstract representation of a bezier path. A bezier path contains a series of straight and curved lines, with information on how the shapes constructed by these lines should be drawn, e.g. whether they should be filled, what kind of pen width to use, pen dash information, the current point, etc.

A bezier path also consists of a number of sub-paths. After a series of move, line and curve operations, a close path operation is inserted to into the bezier path to indicate the end of a sub path. This concept is important with the filling commands.

A number of convenience class methods exist for simple drawing operations, setting defaults and getting information about the current state of the drawing view, aka the graphics state. (A graphics state is a concept inherited from GNUstep's Display Postscript heritage. In Postscript a graphics state object, or gstate, would contain all the information about the current colours, the current affine transform, the width to draw lines with, any fill patterns, and other such information. They could be saved onto a stack and recalled later by name. GNUstep provides a more cut down and logical implementation of similiar concepts across the NSBezierPath class and others.) We can call +strokeRect: or +fillRect: directly to add a new rectangle or filled rectangle to the current drawing view. The -clipRect: method can be used to set a smaller clipping rectangle, intersecting with the current clipping rectangle (which is set by default to be the frame of your view, just before a call to -drawRect: is made.

Graphics Operations and the Current Point
-----------------------------------------

A bezier path represents a series of graphical primitives operations. You call methods corresponding to these operations on the NSBezierPath object, and when it is drawn, these operations are executed in the order that you call them on the bezier path. It also has a concept of a current point. After every graphics operation, a new, internal point is set that will be used as the start point for the next operation. This is usually the destinatio point of the previous operation. For example, if you want a bezier path to move to the point origin, then draw a line from the origin to point (10,20), then a line from (10,20) to (20,20) you only require three operations, i.e. (in psuedocode):

     move to (0,0)
     draw a line to (10,20)
     draw a line to (20,20)

In this case, the bezier path first sets the current point to (0,0). Then, when the line operation is called, you only pass in the destination point, (10,20), which causes it to draw a line from (0,0) to (10,20). After this operation, the current point is set to the destination of the line operation, i.e. (10,20). Then, the next line operation draws a line from (10,20) to (20,20). In this way, we only need specify the destination point for line and move operations, as the start point is determined by the destination point of the previous operation. There is no need to specify the start point for each drawing operation, as this is implied by the destination point of the previous. You can get the current point by calling the currentPoint: method.

These operations are listed in the table below:

Move Operation
     A move operation lifts the pen up and puts it at a new location, i.e. changes the current coordinates without drawing. It implicitly starts a new internal path. This can be achieved throught the -moveToPoint: method, which takes a point as it's first parameter.

Line Operation
     A line operation draws a line from the current point to a new point. The current point is set either through a move operation, or through the last point in a previous line or curve operation. Once the line operation is complete, the current point is set as the destination point. We can draw a line using the lineToPoint: method.

Curve Operation
     This one is more complex, as it involves the real magic of bezier paths. It consists of four points: the start point, the destination point, and two control points. How this works is beyond the scope of this manual (Wikipedia has good information on the mathematics and theory behind bezier curves/paths) and is not required to draw simple circles, ellipses and arcs. We can draw a circle or an ellipse by calling appendBezierPathWithOvalInRect:, passing in a rectangle for the shape to be drawn in. A few methods are provided for adding arcs, with appendBezierPathWithArcFromPoint: toPoint: radius: useful for adding an arc between two points and the appendBezierPathWithArcWithCenter: radius: startAngle: endAngle: method useful for drawing an arc with a particular centre point. For those familiar with bezier curves or who know their control points, the curveToPoint:controlPoint1:controlPoint2: method can be used to draw curves that way. All curve operations set the current point to the destination of the curve.

Close Path Operation
     As bezier paths actually consist of many sub-paths, one can close the current set of path operations with the closePath method to avoid creating a new NSBezierPath method.

Stroking, Filling and Clipping
------------------------------

Once you've assembled a path, you can render it in a number of ways. It can be drawn (stroked), filled, or turned into a clipping region. A simple stroke operation is induced by calling the stroke operation.

Filling operations are induced by calling the fill method. Two winding rules for filling are provided: the even-odd and non-zero winding rules. FIXME: explain the difference between the even-odd and non-zero winding fill rules.

The clip operation (clipping) is a bit different. It takes the bezier path and uses the outline defined by it to set the current clipping region. The clipping region is an area or areas (or series of "regions") that restrict the output of all drawing operations to the region of the device space defined by it's boundaries. A current clipping region is defined for the period of time that you perform drawing operations in your drawRect: method. The default clipping region is set to the bounds of your view.  We can intersect the current clipping region with the bounds of the path with the -addClip method or we can set the current clipping region with the -setClip method. It is also affected by the winding rule in the same way as fill operations.