// -*- objc -*-

#import "ImageView.h"

@implementation ImageView

- initFrame: (const NXRect*) prectFrame
{
    [super initFrame: prectFrame];

    imgrep = nil;

    return self;
}

- (NXImageRep*) imageRep
{
    return imgrep;
}

- setImageRep: (NXImageRep*) imgrep_
{
    [imgrep free];

    imgrep = imgrep_;

    [self update];

    return self;
}

- delegate
{
    return delegate;
}

- setDelegate: newDelegate
{
    delegate = newDelegate;

    return self;
}

- (BOOL) acceptsFirstMouse
{
    return YES;
}

- drawSelf: (const NXRect*) prectRects : (int) iNumRects
{
    NXPoint pnt;

    [self lockFocus];

    PSsetgray(NX_LTGRAY);
    NXRectFill(prectRects);
    pnt.x = pnt.y = 0.0;
    [imgrep drawAt: &pnt];

    [self unlockFocus];

    return self;
}

- sizeTo: (NXCoord) width : (NXCoord) height
{
    [super sizeTo: width : height];

    if (delegate && [delegate respondsTo: @selector(imageView:sizedTo::)])
	[delegate imageView: self sizedTo: width : height];

    return self;
}

static void
AdjustRect (NXRect *rect, const NXRect *sourceRect)
{
    *rect = *sourceRect;

    if (rect->origin.x < 0.0)
    {
	rect->size.width += rect->origin.x;
	rect->origin.x = 0.0;
    }
    if (rect->origin.y < 0.0)
    {
	rect->size.height += rect->origin.y;
	rect->origin.y = 0.0;
    }

    if (rect->size.width < 0.0)
	rect->size.width = 0.0;
    if (rect->size.height < 0.0)
	rect->size.height = 0.0;
}

static void
SaveRect (const NXRect *theRect, NXBitmapImageRep **bitmaps)
{
    NXRect rect,
	anotherRect;

    rect.origin = theRect->origin;
    rect.size.width = theRect->size.width;
    rect.size.height = 1.0;
    AdjustRect(&anotherRect, &rect);

    bitmaps[0] = [[NXBitmapImageRep alloc] initData: NULL
					   fromRect: &anotherRect];

    rect.origin.y += 1.0;
    rect.size.width = 1.0;
    rect.size.height = theRect->size.height - 1.0;
    AdjustRect(&anotherRect, &rect);

    bitmaps[1] = [[NXBitmapImageRep alloc] initData: NULL
					   fromRect: &anotherRect];

    rect.origin.x += theRect->size.width - 1.0;
    AdjustRect(&anotherRect, &rect);

    bitmaps[2] = [[NXBitmapImageRep alloc] initData: NULL
					   fromRect: &anotherRect];

    rect.origin.x = theRect->origin.x + 1.0;
    rect.origin.y = theRect->origin.y + theRect->size.height - 1.0;
    rect.size.width = theRect->size.width - 2.0;
    rect.size.height = 1.0;
    AdjustRect(&anotherRect, &rect);

    bitmaps[3] = [[NXBitmapImageRep alloc] initData: NULL
					   fromRect: &anotherRect];
}

static void
AdjustPoint (NXPoint *pnt, const NXPoint *sourcePnt)
{
    *pnt = *sourcePnt;

    if (pnt->x < 0.0)
	pnt->x = 0.0;
    if (pnt->y < 0.0)
	pnt->y = 0.0;
}

static void
RestoreRect (const NXRect *theRect, NXBitmapImageRep **bitmaps)
{
    NXPoint pnt,
	anotherPnt;

    pnt = theRect->origin;
    AdjustPoint(&anotherPnt, &pnt);

    [bitmaps[0] drawAt: &anotherPnt];

    pnt.y += 1.0;
    AdjustPoint(&anotherPnt, &pnt);

    [bitmaps[1] drawAt: &anotherPnt];

    pnt.x += theRect->size.width - 1.0;
    AdjustPoint(&anotherPnt, &pnt);

    [bitmaps[2] drawAt: &anotherPnt];

    pnt.x = theRect->origin.x + 1.0;
    pnt.y = theRect->origin.y + theRect->size.height - 1.0;
    AdjustPoint(&anotherPnt, &pnt);

    [bitmaps[3] drawAt: &anotherPnt];
}

static void
FreeBitmaps (NXBitmapImageRep **bitmaps)
{
    int i;

    for (i = 0; i < 4; ++i)
	[bitmaps[i] free];
}

static void
DrawRect (const NXRect *theRect)
{
    NXFrameRect(theRect);

    /*
    PScompositerect(theRect->origin.x, theRect->origin.y,
		    theRect->size.width, 1.0, NX_XOR);
    PScompositerect(theRect->origin.x, theRect->origin.y + 1.0,
		    1.0, theRect->size.height - 1.0, NX_XOR);
    PScompositerect(theRect->origin.x + theRect->size.width,
		    theRect->origin.y + 1.0,
		    1.0, theRect->size.height - 1.0, NX_XOR);
    PScompositerect(theRect->origin.x + 1.0,
		    theRect->origin.y + theRect->size.height,
		    theRect->size.width - 2.0, 1.0, NX_XOR);
		    */
}

- mouseDown: (NXEvent*) theEvent
{
    if (theEvent->flags & NX_SHIFTMASK)
    {
	NXPoint dragOrigin;
	NXRect rect;
	NXBitmapImageRep *bitmaps[4];

	dragOrigin = theEvent->location;

	[self convertPoint: &dragOrigin fromView: nil];

	oldEventMask = [window addToEventMask:
				   NX_MOUSEDRAGGEDMASK | NX_MOUSEUPMASK];

	[self lockFocus];

	PSsetgray(NX_BLACK);

	rect.origin = dragOrigin;
	rect.size.width = rect.size.height = 0.0;

	SaveRect(&rect, bitmaps);

	do
	{
	    theEvent =
		[NXApp getNextEvent: NX_MOUSEDRAGGEDMASK | NX_MOUSEUPMASK];

	    if (theEvent->type != NX_MOUSEUP)
	    {
		NXPoint pnt = theEvent->location;

		RestoreRect(&rect, bitmaps);
		FreeBitmaps(bitmaps);

		[self convertPoint: &pnt fromView: nil];

		if (dragOrigin.x < pnt.x)
		{
		    rect.origin.x = dragOrigin.x;
		    rect.size.width = pnt.x - dragOrigin.x;
		}
		else
		{
		    rect.origin.x = pnt.x;
		    rect.size.width = dragOrigin.x - pnt.x;
		}
		if (dragOrigin.y < pnt.y)
		{
		    rect.origin.y = dragOrigin.y;
		    rect.size.height = pnt.y - dragOrigin.y;
		}
		else
		{
		    rect.origin.y = pnt.y;
		    rect.size.height = dragOrigin.y - pnt.y;
		}

		SaveRect(&rect, bitmaps);
		DrawRect(&rect);
		[window flushWindow];
	    }
	} while (theEvent->type != NX_MOUSEUP);

	RestoreRect(&rect, bitmaps);
	FreeBitmaps(bitmaps);
	[window flushWindow];

	[self unlockFocus];

	[window setEventMask: oldEventMask];

	if (delegate != nil &&
	    [delegate respondsTo: @selector(imageView:selectedRect:)])
	    [delegate imageView: self selectedRect: &rect];
    }
    else
    {
	NXPoint pnt = theEvent->location;

	[self convertPoint: &pnt fromView: nil];

	if (delegate != nil &&
	    [delegate respondsTo: @selector(imageView:mouseDown::)])
	    [delegate imageView: self mouseDown: pnt.x : pnt.y];

	if (delegate != nil &&
	    [delegate respondsTo: @selector(imageView:mouseDragged::)])
	    oldEventMask = [window addToEventMask:
				       NX_MOUSEDRAGGEDMASK | NX_MOUSEUPMASK];
    }

    return self;
}

- mouseDragged: (NXEvent*) theEvent
{
    NXPoint pnt = theEvent->location;

    if (delegate && [delegate respondsTo: @selector(imageView:mouseDragged::)])
    {
	[self convertPoint: &pnt fromView: nil];

	[delegate imageView: self mouseDragged: pnt.x : pnt.y];
    }

    return self;
}

- mouseUp: (NXEvent*) theEvent
{
    if (delegate && [delegate respondsTo: @selector(imageView:mouseDragged::)])
	[window setEventMask: oldEventMask];

    return self;
}

@end
