Drawing

I want a graphic clock, which looks like this:

Figure 12.21. Custom view with analog clock

Custom view with analog clock

It is very simple. I only need to add a new GUI component in the class TimeView. I call this new class "ClockView". Since "ClockView" will be the subview of "TimeView", when "TimeView" is update, I also need to update the "ClockView".

ClockView.h:

#import <AppKit/AppKit.h>
#include <math.h>

@interface ClockView : NSView
{
   NSPoint posHour, posMinute;
}

- (void) setDate: (NSCalendarDate *) aDate;
@end

ClockView.m:

#import "ClockView.h"

@implementation ClockView
- (id) init
{
   self = [super init];
   posHour = NSMakePoint(0,0);
   posMinute = NSMakePoint(0,0);
   return self;
}

- (void) drawRect: (NSRect) frame
{
   NSPoint origin = NSMakePoint(frame.size.width/2, frame.size.height/2);

   NSBezierPath *bp = [NSBezierPath bezierPathWithRect: [self bounds]];
   [[NSColor yellowColor] set];
   [BP fill];

   BP = [NSBezierPath bezierPathWithRect: NSMakeRect(1, 1,
                                                     frame.size.width-2,
                                                     frame.size.height-2)];
   [[NSColor blackColor] set];
   [BP stroke];

   BP = [NSBezierPath bezierPath];
   [BP setLineWidth: 3];
   [BP moveToPoint: origin];
   [BP relativeLineToPoint: posHour];
   [BP stroke];

   [BP setLineWidth: 1];
   [BP moveToPoint: origin];
   [BP relativeLineToPoint: posMinute];
   [BP stroke];
}

- (void) setDate: (NSCalendarDate *) date;
{
   int hour = [date hourOfDay];
   int minute = [date minuteOfHour];
   float hour_x = 40*sin((M_PI*hour/6)+(M_PI*minute/360));
   float hour_y = 40*cos((M_PI*hour/6)+(M_PI*minute/360));
   float minute_x = 60*sin(M_PI*minute/30);
   float minute_y = 60*COs(M_PI*minute/30);

   posHour = NSMakePoint(hour_x, hour_y);
   posMinute = NSMakePoint(minute_x, minute_y);
   [self setNeedsDisplay: YES];
}

@end

ClockView inherits from NSView. The most important method it should override is -drawRect:. When this view need to update, -drawRect: will be called. Therefore, I put all the drawing in this method. NSBezierPath is how GNUstep draws. I assign the path, set the color, then draw. There are good article about drawing: Introduction to Cocoa Graphics, Part I, Part II.

A few codes are needed to include ClockView in TimeView. One is to add ClockView as a subview of NSBox in TimeView. Another is to update ClockView when TimeView is update. In method -setDate: of ClockView, it uses [self setNeedsDisplay: YES] to make this view update. This modification is easy to do. You can play around it.