/* -------------------------------------------------------------------

	Chris Walters

	Objective-C source file for the class RDRGridView

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


                             RDRGridView                              

	1. Introduction

	A simple grid.  No snap to yet.  Uses user paths.  Just as
	an example.

	2. Revision History

	0.1	The starting point.	       Chris Walters/1992-6-09

	        Released to the net...

	3. Source Code

------------------------------------------------------------------- */

/* ------------------------- Import files ------------------------- */
#import <appkit/nextstd.h>
#import <dpsclient/wraps.h>
/* ------------------------  Classes used  ------------------------ */
#import <appkit/View.h>

/* -------------------------  Externals  -------------------------- */


/* --------------------------  Defines  --------------------------- */

/* horizontal & vertical spacing */

#define HORIZ_SPACING_MAX 300
#define VERT_SPACING_MAX 300
#define HORIZ_SPACING_MIN 4
#define VERT_SPACING_MIN 4

/* linewidths */

#define LINEWIDTH_MIN 0.0
#define LINEWIDTH_MAX 100.0

/* colors */

#define DEFAULT_FOREGROUND_COLOR NX_COLORBLACK
#define DEFAULT_BACKGROUND_COLOR NX_COLORWHITE

/* defaults */

#define DEFAULT_HORIZ_SPACING 8
#define DEFAULT_VERT_SPACING 8
#define DEFAULT_HORIZ_LINEWIDTH 0.0
#define DEFAULT_VERT_LINEWIDTH 0.0

#define CLASS_VERSION 0
/* ----------------------  Class variables  ----------------------- */


/*====================================================================
                 Implementation of class RDRGridView                  
====================================================================*/
#import "RDRGridView.h"

@implementation RDRGridView : View
{
				/* attribute stuff */
    NXColor bgColor, fgColor;
    int horizontalSpacing, verticalSpacing;
    float horizontalLineWidth, verticalLineWidth;
    BOOL gridEnabled;
				/* user path stuff */
    short *gridPoints;
    int numPoints;
    char *gridOps;
    short *gridBounds;
}

/*====================================================================
                              Initialize                              
====================================================================*/
/*--------------------------------------------------------------------
|-initFrame:(const NXRect *)frameRect| 
Return self.
                                                Chris Walters/1992--14
--------------------------------------------------------------------*/
-initFrame:(const NXRect *)frameRect
{
    [super initFrame:frameRect];
    [self allocateGState];
    fgColor = DEFAULT_FOREGROUND_COLOR;
    bgColor = DEFAULT_BACKGROUND_COLOR;
    horizontalSpacing = DEFAULT_HORIZ_SPACING;
    verticalSpacing = DEFAULT_VERT_SPACING;
    horizontalLineWidth = DEFAULT_HORIZ_LINEWIDTH;
    verticalLineWidth = DEFAULT_VERT_LINEWIDTH;
    gridEnabled = TRUE;

    [self makeUserPath];
    
    return self;
}

/*====================================================================
                     setting/querying attributes                      
====================================================================*/
/*--------------------------------------------------------------------
|-(NXColor)foregroundColor|

Returns the current foreground color of the grid.

--------------------------------------------------------------------*/
-(NXColor)foregroundColor
{
    return fgColor;
}

/*--------------------------------------------------------------------
|-setGridForegroundColor:(NXColor)newColor|

Set the foreground color of the grid.
Return self.

--------------------------------------------------------------------*/
-setGridForegroundColor:(NXColor)newColor
{
    fgColor = newColor;
    return self;
}


/*--------------------------------------------------------------------
|-(NXColor)backgroundColor|

Returns the current background color of the grid.

--------------------------------------------------------------------*/
-(NXColor)backgroundColor
{
    return bgColor;

}

/*--------------------------------------------------------------------
|-setGridBackgroundColor:(NXColor)newColor|

Set the background color of the gridView.
Return self.
--------------------------------------------------------------------*/
-setGridBackgroundColor:(NXColor)newColor
{
    bgColor = newColor;
    return self;
}

/*--------------------------------------------------------------------
|-(BOOL)isEnabled|

Returns TRUE if the grid is enabled, FALSE if not.

--------------------------------------------------------------------*/
-(BOOL)isEnabled
{
    return gridEnabled;
}

/*--------------------------------------------------------------------
|-setEnabled:(BOOL)flag|

Set the enabled flag of the view. If the view is disabled, it will
not draw the grid, but it will fill in the background with the
current background color.

Return self.
--------------------------------------------------------------------*/
-setEnabled:(BOOL)flag
{
    gridEnabled = flag;
    return self;
}

/*--------------------------------------------------------------------
|-setHorizontalWidth:(float)newWidth|

Sets the width of horizontal lines of the grid.  

Return self.
--------------------------------------------------------------------*/
-setHorizontalWidth:(float)newWidth
{
    if (newWidth < LINEWIDTH_MIN)
	horizontalLineWidth = LINEWIDTH_MIN;
    else if (newWidth > LINEWIDTH_MAX)
	horizontalLineWidth = LINEWIDTH_MAX;
    else horizontalLineWidth = newWidth;
    return self;
}

/*--------------------------------------------------------------------
|-(float)horizontalWidth|

Returns the current linewidth used for horizontal lines.

--------------------------------------------------------------------*/
-(float)horizontalWidth
{
    return horizontalLineWidth;
}

/*--------------------------------------------------------------------
|-setVerticalWidth:(float)newWidth|

Sets the linewidth used to draw vertical lines.
Return self.
--------------------------------------------------------------------*/
-setVerticalWidth:(float)newWidth
{
    if (newWidth < LINEWIDTH_MIN)
	verticalLineWidth = LINEWIDTH_MIN;
    else if (newWidth > LINEWIDTH_MAX)
	verticalLineWidth = LINEWIDTH_MAX;
    else verticalLineWidth = newWidth;
    return self;
}

/*--------------------------------------------------------------------
|-(float)verticalWidth|

Returns the current width used for drawing vertical lines.

--------------------------------------------------------------------*/
-(float)verticalWidth
{
    return verticalLineWidth;
}

/*--------------------------------------------------------------------
|-setHorizontalSpacing:(int)newSpacing|

Set the spacing used between horizontal lines of the grid.
Return self.
--------------------------------------------------------------------*/
-setHorizontalSpacing:(int)newSpacing
{
    if (newSpacing < HORIZ_SPACING_MIN)
	horizontalSpacing = HORIZ_SPACING_MIN;
    else if (newSpacing > HORIZ_SPACING_MAX)
	horizontalSpacing = HORIZ_SPACING_MAX;
    else horizontalSpacing = newSpacing;
    return self;
}

/*--------------------------------------------------------------------
|-(int)horizontalSpacing|

Returns the current spacing used between horizontal lines.

--------------------------------------------------------------------*/
-(int)horizontalSpacing
{
    return horizontalSpacing;
}

/*--------------------------------------------------------------------
|-setVerticalSpacing:(int)newSpacing| 
Return self.
--------------------------------------------------------------------*/
-setVerticalSpacing:(int)newSpacing
{
    if (newSpacing < VERT_SPACING_MIN)
	verticalSpacing = VERT_SPACING_MIN;
    else if (newSpacing > VERT_SPACING_MAX)
	verticalSpacing = VERT_SPACING_MAX;
    else verticalSpacing = newSpacing;
    
    return self;
}

/*--------------------------------------------------------------------
|-(int)verticalSpacing| 
Return self.
--------------------------------------------------------------------*/
-(int)verticalSpacing
{
    return verticalSpacing;
}

/*====================================================================
                           drawing methods                            
====================================================================*/
/*--------------------------------------------------------------------
|-drawSelf:(const NXRect *)rects :(int)rectCount| 
Return self.
--------------------------------------------------------------------*/
-drawSelf:(const NXRect *)rects :(int)rectCount
{

    NXSetColor(bgColor);
    NXRectFillList(rects,rectCount);

    PSsetlinewidth(horizontalLineWidth);
    NXSetColor(fgColor);

    PSsetlinewidth(verticalLineWidth);
    [self makeUserPath];
    if (gridEnabled) {
	NXSetColor(fgColor);
	DPSDoUserPath(gridPoints, numPoints, dps_short,
		      gridOps, numPoints >> 1, gridBounds, dps_ustroke);
    }
    return self;
}


/*====================================================================
                           User path setup                            
====================================================================*/
/*--------------------------------------------------------------------
|-makeUserPath|

This routine sets up the user path for the grid.
Lifted from the Draw example.

Return self.
--------------------------------------------------------------------*/
-makeUserPath
{
    int x, y, i, j;
    short w, h;

    if (horizontalSpacing < HORIZ_SPACING_MIN) return self;

    x = (int)bounds.size.width / horizontalSpacing;
    y = (int)bounds.size.height / verticalSpacing;
    numPoints = (x << 2) + (y << 2);
    if (gridPoints) {
	NX_FREE(gridPoints);
	NX_FREE(gridOps);
	NX_FREE(gridBounds);
    }
    NX_ZONEMALLOC([self zone], gridPoints, short, numPoints);
    NX_ZONEMALLOC([self zone], gridOps, char, numPoints >> 1);
    NX_ZONEMALLOC([self zone], gridBounds, short, 4);
    w = bounds.size.width;
    h = bounds.size.height;
    j = 0;
    for (i = 1; i <= y; i++) {
	gridPoints[j++] = 0.0;
	gridPoints[j++] = i * verticalSpacing;
	gridPoints[j++] = w;
	gridPoints[j] = gridPoints[j-2];
	j++;
    }
    for (i = 1; i <= x; i++) {
	gridPoints[j++] = i * horizontalSpacing;
	gridPoints[j++] = 0.0;
	gridPoints[j] = gridPoints[j-2];
	j++;
	gridPoints[j++] = h;
    }
    i = numPoints >> 1;
    while (i) {
	gridOps[--i] = dps_lineto;
	gridOps[--i] = dps_moveto;
    }
    gridBounds[0] = gridBounds[1] = 0;
    gridBounds[2] = bounds.size.width + 1;
    gridBounds[3] = bounds.size.height + 1;
    
    return self;
}

/*--------------------------------------------------------------------
|-sizeTo:(NXCoord)width :(NXCoord)height| 
Return self.
--------------------------------------------------------------------*/
-sizeTo:(NXCoord)width :(NXCoord)height
{
    if (width != bounds.size.width || height != bounds.size.height) {
	[super sizeTo:width :height];
	[self makeUserPath];
	[self display];
    }
    return self;
}

/*====================================================================
                                 Free                                 
====================================================================*/
/*--------------------------------------------------------------------
|-free|

Frees the data structures associated with the user path (used for
drawing the grid) and returns super free.

--------------------------------------------------------------------*/
-free
{
    if (gridPoints) {
	NX_FREE(gridPoints);
	NX_FREE(gridOps);
	NX_FREE(gridBounds);
    }
    return [super free];
}

/*====================================================================
                               Archival                               
====================================================================*/
/*--------------------------------------------------------------------
|-read:(NXTypedStream *)stream| 
Return self.
--------------------------------------------------------------------*/
-read:(NXTypedStream *)stream
{
    [super read:stream];

    bgColor = NXReadColor(stream);
    fgColor = NXReadColor(stream);
    NXReadTypes(stream,"iiffi",
		&horizontalSpacing,
		&verticalSpacing,
		&horizontalLineWidth,
		&verticalLineWidth,
		&gridEnabled);
    
    return self;
}

/*--------------------------------------------------------------------
|-write:(NXTypedStream *)stream| 
Return self.
--------------------------------------------------------------------*/
-write:(NXTypedStream *)stream
{
    [super write:stream];

    NXWriteColor(stream,bgColor);
    NXWriteColor(stream,fgColor);
    NXWriteTypes(stream,"iiffi",
		 &horizontalSpacing,
		 &verticalSpacing,
		 &horizontalLineWidth,
		 &verticalLineWidth,
		 &gridEnabled);
		 
    return self;
}

/*--------------------------------------------------------------------
|-awake| 
Return self.
--------------------------------------------------------------------*/
-awake
{
    [super awake];
    return self;
}

- (const char *)inspectorName
{
    return "RDRGridViewInspector";
}



@end

