/* Implementation of ClipView class
 *
 * Copyright (C)  1994  The Board of Trustees of  
 * The Leland Stanford Junior University.  All Rights Reserved.
 *
 * Authors: Paul Kunz
 *
 * This file is part of an Objective-C class library for a window system.
 *
 * ClipView.m,v 1.16 1995/12/13 22:32:57 fedor Exp
 */

#include "ClipView.h"

#include "NXCursor.h"
#include "ScrollView.h"
#include <objc/List.h>
#include "stdmacros.h"

@interface View(WidgetSet)
- _init;
@end

@implementation ClipView

/* Private methods not declared in interface */

- _scrollClip:cView to:(const NXPoint *)newOrigin
{
    if ( [superview respondsTo:@selector(scrollClip:to:) ] ) {
        [superview scrollClip:self to:newOrigin];
    } else {
        [self rawScroll:newOrigin];
	[superview reflectScroll:self];
    }
    return self;
}

- _validateScroll:(NXPoint *)aPoint
{
    NXPoint	maxpoint;
    
    if ( docView ) {
	[docView getFrame:&_docRect];
    } else {
        _docRect.origin.x = 0;
	_docRect.origin.y = 0;
	_docRect.size.width = 0;
	_docRect.size.height = 0;
    }
    maxpoint.x = _docRect.size.width  - frame.size.width;
    maxpoint.y = _docRect.size.height - frame.size.height;
    maxpoint.x = MAX(maxpoint.x, 0);
    maxpoint.y = MAX(maxpoint.y, 0);
    aPoint->x = MIN(aPoint->x, maxpoint.x);
    aPoint->y = MIN(aPoint->y, maxpoint.y);
    aPoint->x = MAX(aPoint->x, 0 );
    aPoint->y = MAX(aPoint->y, 0 );
    return self;
}

/* Private methods */

- _init
{
    [super _init];
    instancename = "ClipView";
    return self;
}
/* Public methods */

- initFrame:(const NXRect *)frameRect
{
    [super initFrame:frameRect];
    return self;
}
    
- setDocView:aView
{
    View	*oldView;
    
    if ( docView ) {
    	oldView = [self replaceSubview:docView with:aView];
    } else {
        [self addSubview:aView];
	oldView = nil;
    }
    docView = [subviews objectAt:0];	/* makes sure it got accepted */
    [docView notifyAncestorWhenFrameChanged:YES];
    [docView getFrame:&_docRect];
    _docRect.origin.x = 0;
    _docRect.origin.y = 0;
    [docView setFrame:&_docRect]; /* avoid moveTo:: */
    [superview reflectScroll:self];
    return oldView;
}

- docView
{
    return docView;
}

- getDocRect:(NXRect *)aRect
{
    if ( docView ) {
	[docView getFrame:aRect];
    } else {
        aRect->origin.x = 0;
	aRect->origin.y = 0;
	aRect->size.width = 0;
	aRect->size.height = 0;
    }
    aRect->size.width  = MAX(aRect->size.width,  frame.size.width);
    aRect->size.height = MAX(aRect->size.height, frame.size.height);
    return self;
}

- setDocCursor:anObj
{
    NXCursor	*oldCursor;
    
    oldCursor = cursor;
    cursor = anObj;
    return oldCursor;
}

- resetCursorRects
{
  return [self notImplemented:_cmd];
}

- getDocVisibleRect:(NXRect *)aRect
{
    if ( docView ) {
	[docView getFrame:&_docRect];
    } else {
        _docRect.origin.x = 0;
	_docRect.origin.y = 0;
	_docRect.size.width = 0;
	_docRect.size.height = 0;
    }
    aRect->origin.x = - _docRect.origin.x;
    aRect->origin.y = - _docRect.origin.y;
    aRect->size.width  = frame.size.width;
    aRect->size.height = frame.size.height;    
    return self;
}

- descendantFrameChanged:sender
{
    if ( sender == docView ) {
        [(ScrollView *)superview reflectScroll:sender];
    }
    return [superview descendantFrameChanged:sender];
}

- descendantFlipped:sender
{
  return [self notImplemented:_cmd];
}

- setCopyOnScroll:(BOOL)flag
{
  return [self notImplemented:_cmd];
}

- setDisplayOnScroll:(BOOL)flag
{
  return [self notImplemented:_cmd];
}

- autoscroll:(NXEvent *)theEvent
{
  return [self notImplemented:_cmd];
}

- constrainScroll:(NXPoint *)newOrigin
{
    bounds.origin.x = newOrigin->x;
    bounds.origin.y = newOrigin->y;
    return self;
}

- rawScroll:(const NXPoint *)newOrigin
{
    bounds.origin.x = newOrigin->x;
    bounds.origin.y = newOrigin->y;
    [docView moveTo:-bounds.origin.x :-bounds.origin.y];
    return self;
}

// in category 
- write:(NXTypedStream *)stream
{
    [super write:stream];
    /* FIXME: Implement */
    return self;
}

- read:(NXTypedStream *)stream
{
    [super read:stream];
    docView = [subviews objectAt:0];
    NXReadRect(stream, &_docRect);
    return self;
}

- free
{
  return [super free];
}

- rotate:(NXCoord)angle
{
    return self;	/* over-ride to disable rotation */
}
- rotateTo:(NXCoord)angle
{
    return self;	/* over-ride to disable rotation */
}
- setDrawRotation:(NXCoord)angle
{
    return self;	/* over-ride to disable rotation */
}

- awake
{
    [super awake];

    /* until it's archived in View */
    [docView notifyAncestorWhenFrameChanged:YES];
    
    return self;
}

- moveTo:(NXCoord)x :(NXCoord)y
{
  return [self notImplemented:_cmd];
}

- sizeTo:(NXCoord)width :(NXCoord)height
{
  return [self notImplemented:_cmd];
}

- setDrawOrigin:(NXCoord)x :(NXCoord)y
{
  return [self notImplemented:_cmd];
}

- setDrawSize:(NXCoord)width :(NXCoord)height
{
  return [self notImplemented:_cmd];
}

- translate:(NXCoord)x :(NXCoord)y
{
  return [self notImplemented:_cmd];
}

- scale:(NXCoord)x :(NXCoord)y
{
  return [self notImplemented:_cmd];
}

- _setScrollFloatValue:(float) xPercent :(float) yPercent
{
    NXRect	rect;
    NXSize	range;
    NXPoint	point;
    
    if ( docView ) {
	[docView getFrame:&_docRect];
    } else {
        _docRect.origin.x = 0;
	_docRect.origin.y = 0;
	_docRect.size.width = 0;
	_docRect.size.height = 0;
    }
    [self getDocRect:&rect];
    range.width = rect.size.width - frame.size.width;
    range.height = rect.size.height - frame.size.height;
    point.x = xPercent * range.width;
    point.y = yPercent * range.height;
    [self _scrollClip:self to:&point];
    return self;
}

- _scrollLine:(int)amount vertical:(BOOL)aFlag
{
    NXPoint	point;
    
    point.x = bounds.origin.x;
    point.y = bounds.origin.y;
    if ( aFlag ) {
        point.y += amount;
    } else {
        point.x += amount;
    }
    [self _validateScroll:&point]; 
    [self _scrollClip:self to:&point];
    return self;
}

- _scrollPage:(int)context vertical:(BOOL)vFlag up:(BOOL)uFlag
{
    int		amount;
    
    if ( vFlag ) {
    	amount = frame.size.height - context;
    } else {
    	amount = frame.size.width - context;
    }
    if ( uFlag ) {
        amount = - amount;
    }
    return [self _scrollLine:amount vertical:vFlag];
}

@end
