#if 0

  PressureView.m -- Pressure sensitive View subclass for painting

  by Peter Graffagnino, NeXT Computer Inc.

  PressureView is a view subclass responsible for:

  - maintaining a special trackingrect to inform the low-level event
    system of its interest in pressure and event coalescing.
  - maintaining an NXImage backingstore for the View.
  - implementing a mouseDown: painting loop and using a Brush object for
    painting
  - handling flagsChanged: events to update pen proximity state

  You may freely copy, distribute, and reuse the code in this example.
  NeXT disclaims any warranty of any kind, expressed or  implied, as to its
  fitness for any particular use.

#endif

#import <appkit/appkit.h>
#include <math.h>
#include <dpsclient/wraps.h>
#import "PressureView.h"
#import "Brush.h"
#import "pressurerect.h"

@implementation PressureView : View

- initFrame:(const NXRect *)r
{
    self = [super initFrame:r];
    [self allocateGState];
    backingImage = [[NXImage alloc] initSize: &r->size];
    [backingImage setBackgroundColor: NX_COLORWHITE];
    coalesceState = YES;
    pressureState = YES;
    [self clear: self];
    return self;
}

- free
{
    [backingImage free];
    return [super free];
}

- clear:sender
{
    if (! [backingImage lockFocus]) return self;
    NXSetColor(NX_COLORWHITE);
    NXRectFill(&bounds);
    [backingImage unlockFocus];
    [self display];
    return self;
}

- drawSelf:(const NXRect *)rects :(int)rectCount
{
    [backingImage composite: NX_COPY fromRect: rects toPoint: &rects->origin];
    return self;
}

- sizeTo: (NXCoord) x : (NXCoord) y
{
    NXSize size;
    [super sizeTo: x : y];
    size.width = x;
    size.height = y;
    [backingImage setSize: &size];
    return self;
}

- mouseDown:(NXEvent *)e
{
    NXPoint p;
    NXRect dirty;
    int emask=[window addToEventMask:(NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK)];

    if( ! [backingImage lockFocus] ) return self;

    p = e->location;
    [self convertPoint: &p fromUCi: nil];
    p.x += .5; p.y += .5;
    [brush brushMoveTo: p.x : p.y withPressure: e->data.mouse.pressure/255.0
                  dirtyRect: &dirty];
    [self display: &dirty : 1];
    while(1) {
	e=[NXApp getNextEvent:(NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK)];
	if(e->type == NX_MOUSEUP)
	    break;
	p = e->location;
	[self convertPoint: &p fromView: nil];
	p.x += .5; p.y += .5;
	[brush brushLineTo: p.x : p.y withPressure: 
		e->data.mouse.pressure/255.0
     		dirtyRect: &dirty];
	[self display: &dirty : 1];
	NXPing();    
    }
    [backingImage unlockFocus];
    [window setEventMask:emask];
    return self;
}


- (BOOL) acceptsFirstResponder
{
    return YES;
}

- awakeFromNib
{
    [window addToEventMask:NX_FLAGSCHANGEDMASK];
    return self;
}

/*
 * we implement flagsChanged in order to receive proximity events from the
 * tablet.  We just use this to update a status field.
 */

- flagsChanged:(NXEvent *)e
{
    BOOL proximity;
    
    proximity = e->flags & NX_STYLUSPROXIMITYMASK;
    [proximityText setStringValue:
     	proximity ?
     	NXLocalString("in proximity", NULL, NULL) :
	NXLocalString ("out of proximity", NULL, NULL)];
    return self;    
}


/* 
 * Target/Action methods used to control the special tracking rect options
 * (pressure and coalescing).
 */

- setCoalesceState:sender
{
    coalesceState = [sender state];
    [self setPressureRect];
    return self;
}

- setPressureState:sender
{
    pressureState = [sender state];
    [self setPressureRect];
    return self;
}

/*
 * resetCursorRects will be called to give the view an opportunity to
 * re-establish its tracking rects after the relative geometry between the
 * Window and the View has changed.  We use this opportunity to set up oue
 * special tracking rects for pressure and coalescing.
 */

- resetCursorRects
{
    return [self setPressureRect];
}

- setPressureRect
{
    NXRect visibleRect;

    [self lockFocus];
    [self getVisibleRect: &visibleRect];

    /*
     *  Setup the pressure rect.  Use our object address as the trackingrect
     *  tag.
     */
    
    set_pressure_rect(visibleRect.origin.x,
		      visibleRect.origin.y,
		      visibleRect.size.width,
		      visibleRect.size.height,
		      coalesceState,
		      pressureState,
		      (int) self);
    
    [self unlockFocus];
    return self;
}

@end
