/*
Pencil V2.0, Copyright 1994, 95 by Florian Marquardt.
This program may be distributed under the terms of the GNU general
public license (Start Pencil and select "Copyright" in the Help panel for a copy of the
license).
Pencil has a built-in TCL interpreter (tcl 7.3 by John Ousterhout). This is under a separate
license (see "Copyright").
*/
// changed 23_10_94: added save/restore for EPS-hack
#import "PencilImage.h"
#import <math.h>

extern BOOL globalOutlines;
extern BOOL movementStatus;
extern BOOL globalComposite;
#define M_180_PI 180.0/M_PI
extern void expandRect(NXRect *, float, float);
extern void initM( float *m);
extern void transformPt( float *m, float x, float y, float *dx, float *dy);
#define TX m[4]
#define TY m[5]

extern unsigned long long int layersVisible1;
extern unsigned long long int layersVisible2;
extern unsigned long long int layersSelectable1;
extern unsigned long long int layersSelectable2;

BOOL globPrintTransp=NO;

extern Tcl_Interp *TCLip;

@implementation PencilImage
- initFromFile:(const char *)fn
{
	[super init];
	initM( m);
	transformed=NO;
	if(theImage=[NXImage alloc])
	{
		[theImage setDataRetained:YES];
		if([theImage  loadFromFile:fn])
		{
			[theImage getSize: &originalSize];
			[theImage setScalable: YES];
			if(Tcl_GetVar( TCLip, "P_getImageFromFile", TCL_GLOBAL_ONLY)) {
				filename=(char *)malloc(sizeof(char)*(strlen(fn)+1));
				strcpy(filename, fn);
			} else filename=NULL;
			return self;
		}
		else
		{
			[theImage free];
			return nil;
		}
	}
	else
		return nil;
}

- free
{
	if(theImage)	[theImage free];
	return [super free];
}

+ initialize
{
	[self setVersion: 2];
	return self;
}

- (BOOL)selected:(NXEvent *)te:(int *)cp:(id)view
{
	NXPoint pt;

	if(layer<=63 ? (layersSelectable1&(1ULL<<layer)): (layersSelectable2&(1ULL<<(layer-64)))) {
	pt=te->location;
	[self transformPoint:&pt];
	if(pt.x>=0 && pt.y>=0 && pt.x<=originalSize.width && pt.y<=originalSize.height)
		return(YES);
	else
		return(NO);
	}
	else
		return NO;
}

- (BOOL)move:(NXEvent *)tte:(int *)cp:(id)view:(float)bsize
{
	return NO;
}

- (void)draw:(NXRect *)re
{
	if(layer<=63 ? (layersVisible1&(1ULL<<layer)): (layersVisible2&(1ULL<<(layer-64)))) {
	if(!re || NXIntersectsRect(&bounds, re))
	{
	if(globalOutlines)
	{
	switch(transformed) {
		case TRANSLATION: PSgsave(); PStranslate(TX, TY); break;
		case MATRIX: PSgsave(); PSconcat(m); break;
	}
	PSsetlinewidth(0);
	PSsetgray(.333);
	PSrectstroke(0,0,originalSize.width,originalSize.height);
	if(transformed) PSgrestore();
	}
	else
	{
	PSgsave();
	switch(transformed) {
		case TRANSLATION: PStranslate(TX, TY); break;
		case MATRIX: PSconcat(m); break;
	}
	if(!theImage) {
		if(filename)
		{
				Tcl_VarEval( TCLip, "P_Img ", filename, NULL);
				[theImage=[NXImage alloc] loadFromFile: TCLip->result];
				[theImage setScalable: YES];
				[theImage setDataRetained: YES];
		}
		else
		{
			return;
		}
	} 
	if((transformed!=MATRIX || (m[1]==0 && m[2]==0)) && globalComposite)	{
		NXPoint or;
		NXSize size, bs;
		
		or.x=or.y=0;
		[theImage getSize: &size];
		
		bs=bounds.size;
		[[NXApp focusView] convertSize: &bs toView:nil];
		if(size.width!=bs.width || size.height!=bs.height)
			[theImage setSize: &bs];
		[theImage composite: NX_SOVER toPoint:&or];
	}
	else
		if([[theImage bestRepresentation] isKindOf:[NXEPSImageRep class]])
	{	// Sorry, we need this very UGLY hack, because
		// we want rotated images and therefore we would
		// need "draw", but unfortunately "draw" uses a
		// different DPS context for EPS images (which results in wrong clipping), so...
		char *theEPScode; int length;
		char *thetext;
		NXRect box;

		[[(NXEPSImageRep *)[theImage bestRepresentation] getBoundingBox:&box] getEPS:&theEPScode length:&length];
		thetext=(char *)malloc(sizeof(char)*(length+1));
		strncpy(thetext, theEPScode, length);
		thetext[length]=0;
		// UGLY:
		DPSPrintf(DPSGetCurrentContext(), "0 setgray 0 setlinewidth save [] 0 setdash /showpage {} def %g %g translate\n%s\nrestore\n", -box.origin.x, -box.origin.y, thetext);
		free(thetext);
	}
	else // we need "draw", since we want rotated tiff images, too
		[[theImage bestRepresentation] draw];
	PSgrestore();
	}
	}
	}
}

- (void)drawPath
{
	DPSPrintf(DPSGetCurrentContext()," matrix currentmatrix ");
	switch(transformed) {
		case TRANSLATION:  PStranslate(TX, TY); break;
		case MATRIX: PSconcat(m); break;
	}
	PSmoveto(0,0);
	PSlineto(originalSize.width,0);
	PSlineto(originalSize.width,originalSize.height);
	PSlineto(0, originalSize.height);
	PSclosepath();
	DPSPrintf(DPSGetCurrentContext()," setmatrix\n");
}

- calculateBoundingBox:(id)view
{
	float llx, lly, urx, ury, nx, ny;

	llx=lly=0;
	urx=originalSize.width;
	ury=originalSize.height;
	transformPt( m, llx, lly, &bounds.origin.x, &bounds.origin.y);
	bounds.size.width=bounds.size.height=0;
	transformPt( m, llx, ury, &nx, &ny);
	expandRect(&bounds, nx, ny);
	transformPt( m, urx, ury, &nx, &ny);
	expandRect(&bounds, nx, ny);
	transformPt( m,urx, lly, &nx, &ny);
	expandRect(&bounds, nx, ny);
	return self;
}

- (void)drawControl:(NXRect *)re:(int)cp:(float)bsize
{
	if(!movementStatus || ![[theImage bestRepresentation] isKindOf:[NXEPSImageRep class]] || ((transformed!=MATRIX || (m[1]==0 && m[2]==0)) && globalComposite))
		[self draw:re];
	switch(transformed) {
		case TRANSLATION: PSgsave(); PStranslate(TX, TY); break;
		case MATRIX: PSgsave(); PSconcat(m); break;
	}
	PSsetlinewidth(0);
/*	if([[theImage bestRepresentation] isKindOf:[NXEPSImageRep class]])
	{
		PSsetgray(.5);
		PSsetlinewidth(0);
		PSmoveto(0,0); 
		PSlineto(originalSize.width,originalSize.height);
		PSstroke();
		PSmoveto(originalSize.width,0);
		PSlineto(0,originalSize.height);
		PSstroke();
	}
	PSsetgray(.8);
	PSrectstroke(2,2,originalSize.width-4,originalSize.height-4);
*/
	PSsetrgbcolor(1,0,0);
	PSsetlinewidth(2);
#define WW originalSize.width*.1
#define HH originalSize.height*.1
#define HO (originalSize.height-2)
#define WO (originalSize.width-2)
	PSmoveto(WW+2,2);
	PSrlineto(-WW,0);
	PSrlineto(0, HH);
	PSstroke();
	PSmoveto(WW+2,HO);
	PSrlineto(-WW,0);
	PSrlineto(0,-HH);
	PSstroke();
	PSmoveto(WO-WW,2);
	PSrlineto(WW,0);
	PSrlineto(0,HH);
	PSstroke();
	PSmoveto(WO-WW,HO);
	PSrlineto(WW,0);
	PSrlineto(0,-HH);
	PSstroke();
	if(transformed)	PSgrestore();
}

- (void)drawIfNeeded:(NXRect *)re:(int)cp:(float)bsize
{ 	if([[theImage bestRepresentation] isKindOf:[NXEPSImageRep class]]) 		[self drawControl:re:cp:bsize];  }
//  used for redrawing EPS after a move...

- write:(NXTypedStream *)stream
{
	[super write:stream];
	NXWriteType(stream, "*", &filename);
	NXWriteSize(stream, &originalSize);
	if(!filename) {
	NXWriteObject(stream,theImage);
	} else NXWriteObject(stream, nil);
	return self;	
}

- read:(NXTypedStream *)stream
{
	[super read:stream];
	if(NXTypedStreamClassVersion(stream, "PencilImage")>=2) {
		NXReadType(stream, "*", &filename);
		NXReadSize(stream, &originalSize);
	}
	theImage=NXReadObject(stream);
	return self;
}

- (int)type
{
	return 3;
}

- (void)scaleCenter:(float)cx:(float)cy by:(float)scx:(float)scy
{
	[super scaleCenter:cx:cy by:scx:scy];
	[self calculateBoundingBox: nil];
}

- (void)giveDescription:(Tcl_Interp *)interp
{
	static char str[30];
	
	[super giveDescription:interp];
	if(filename)
		Tcl_AppendElement( interp, filename);
	else
		Tcl_AppendElement( interp, "");
	sprintf(str, "%g", originalSize.width);
	Tcl_AppendElement( interp, str);
	sprintf(str, "%g", originalSize.height);
	Tcl_AppendElement( interp, str);
}
@end
