ftp.nice.ch/pub/next/graphics/vector/PencilTWO.s.tar.gz#/PencilTWO/Source/PencilText.m

This is PencilText.m in view mode; [Download] [Up]

/*
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").
*/
#import "PencilText.h"
#import "PencilView.h"
#import <math.h>

extern BOOL globalOutlines;
extern id globalText; // used for drawing the text

#define M_180_PI 180.0/M_PI
extern void expandRect(NXRect *, float, float);
extern float angle(float x1,float y1,float x2,float y2);

// convert ( and ) to \( and \) (and other special characters)
// isn't very good for Ùöö etc. (--> \Ù\ö\ö, should be sort of \331 etc., don't know how
// to do it (must be somewhere in NS!))
void
convertToPSString(char *to, char *from)
{
	while(*from!=0) {
		if((*from>='*' && *from<='Z') || (*from>='^' && *from<='}'))
			*(to++)=*(from++);
		else
		{
			*(to++)='\\';
			*(to++)=*(from++);
		}
	}
	*to=0;
}

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

@implementation PencilText
- free
{
	if(rich) free(rich);
	return [super free];
}

- editText:(NXEvent *)te:(id)view:(id)flippedView
{
	static const NXSize maxsize={ 2000, 2000 };
	static const NXSize minsize={ 12, 12 };
	NXPoint pt;
	id text;

	pt=te->location;
	[flippedView convertPoint:&pt fromView:nil];
	if(text=[[view window] getFieldEditor:YES for:self])
	{
		[[view window] endEditingFor:[view window]];
	   	[text setCharFilter:NXEditorFilter];
		[text setEditable:YES];
		[text setDelegate:self];
		[text setHorizResizable:YES];
		[text setVertResizable:YES];
		[text setOpaque:YES];
		[text setMaxSize:&maxsize];
		[text setMinSize:&minsize];
		[text setMonoFont:NO];
		[text setFontPanelEnabled:YES];
		[text setAlignment:NX_LEFTALIGNED];
		[flippedView addSubview:text];
		if(rich)
		{
		NXStream *stream;
		NXRect myframe;

		myframe=bounds;
		[view convertRect:&myframe toView:flippedView];
		[text moveTo:myframe.origin.x:myframe.origin.y];
		[text sizeTo:myframe.size.width:myframe.size.height];
		[text setHorizResizable:NO];
		stream=NXOpenMemory(rich,length,NX_READONLY);
		[text readRichText:stream];
		NXClose(stream);
		[view convertPoint: &te->location toView: nil];
		te->data.mouse.click=1;
		}
		else
		{
		[text moveTo:pt.x:pt.y];
		[text sizeTo:12:12];
		[text setText:""];
		}
		[text display];
		[[view window] makeFirstResponder:text];
		if(rich) [text mouseDown: te]; else [text selectText:self];
	}
	return self;
}

- textDidEnd:sender endChar:(unsigned short)why
{
NXStream *stream;
int maxlen;
id theview;
char *buf;

// GETTING THE rich-TEXT AND THE FRAME
if(rich) free(rich);
stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
[sender writeRichText:stream];
NXGetMemoryBuffer(stream,&buf,&length,&maxlen);
if(rich=(char *)malloc(sizeof(char)*(length+1)))
	strcpy(rich,buf);
NXCloseMemory(stream, NX_FREEBUFFER);
[sender getFrame:&bounds];
[ [sender superview] convertRect:&bounds toView:theview=[[sender superview] superview]];
// CLEANING UP
[sender setCharFilter:NXFieldFilter];
[sender removeFromSuperview];
[theview richTextEnded:self];
[theview display:&bounds:1];
[theview displayCurrentGraphic];
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>=bounds.origin.x && pt.y>=bounds.origin.y && pt.x<=bounds.size.width+bounds.origin.x && pt.y<=bounds.size.height+bounds.origin.y)
		return(YES);
	else
		return(NO);
	}
	else
		return NO;
}

#define ADJUST [view convertPoint:&te->location fromView:nil]

- (BOOL)move:(NXEvent *)tte:(int *)cp:(id)view:(float)bsize
{
    int	oldMask;
	BOOL shouldLoop=YES;
	NXEvent *te;
	NXEvent mte;
	float x, y;
	
	mte=*tte;
	te=&mte;
	[view lockFocus];
	[self transformPoint:&te->location];
	x=te->location.x;
	y=te->location.y;
	
	if(y<=bounds.origin.y+4 && y>=bounds.origin.y-4 && x>=bounds.origin.x+bounds.size.width-4 && x<=bounds.origin.x+bounds.size.width+4)
	{
		NXEvent thisEvent;
		
    	oldMask = [[view window] addToEventMask:NX_LMOUSEDRAGGEDMASK];

	PSsetinstance(YES);
    while (shouldLoop) {
        do {
	te = [NXApp getNextEvent:(NX_LMOUSEUPMASK |
                                         NX_LMOUSEDRAGGEDMASK)];
    	} while(te->type==NX_LMOUSEDRAGGED && ([NXApp peekNextEvent:NX_LMOUSEDRAGGEDMASK into:&thisEvent]));

   	ADJUST;
	if(te->type==NX_LMOUSEUP)
		shouldLoop=NO; 
	else {
	[self transformPoint:&te->location];
	bounds.size.width+=te->location.x-x;
	bounds.size.height-=te->location.y-y;
	bounds.origin.y+=te->location.y-y;
	y=te->location.y;
	x=te->location.x;
	PSnewinstance();
	[self drawControl:NULL:*cp:bsize];
	PSflushgraphics();
	NXPing();
	}
    }
	PSsetinstance(NO);
	[view unlockFocus];
    [[view window] setEventMask:oldMask];
		
		return YES;
	}
	else
	{
		[view unlockFocus];
		return NO;
	}
}

- calculateBoundingBox:(id)view
{
	return self;
}

- (void)draw:(NXRect *)re
{
	if(layer<=63 ? (layersVisible1&(1ULL<<layer)): (layersVisible2&(1ULL<<(layer-64)))) {
	if(!re || NXIntersectsRect(&bounds, re))
	{
//	if(globalOutlines)
//	{
//	PSgsave();
//	if(translated)	PStranslate(tx,ty);
//	if(rotated)		PSrotate(M_180_PI*phi);
//	if(scaled)		PSscale(s,s);
//	PSsetlinewidth(0);
//	PSsetgray(.5);
//	PSrectstroke(bounds.origin.x,bounds.origin.y,bounds.size.width,bounds.size.height);
//	PSgrestore();
//	}
//	else
//	{
//	PSgsave();
//	if(translated)	PStranslate(tx,ty);
//	if(rotated)		PSrotate(M_180_PI*phi);
//	if(scaled)		PSscale(s,s);

if(rich)
{
NXStream *stream;

stream=NXOpenMemory(rich,length,NX_READONLY);
[globalText readRichText:stream];
NXClose(stream);
[[NXApp focusView] addSubview:globalText];
[globalText setFrame:&bounds];
[globalText display];
[globalText removeFromSuperview];
}
//	PSgrestore();
//	}
	}
	}
}

- (void)rotateAroundCenter:(float)x:(float)y fromPoint:(NXPoint *)pt1 toPoint:(NXPoint *)pt2
{
	float dphi, dx, dy;

	dphi=angle(pt1->x-x,pt1->y-y,pt2->x-x,pt2->y-y);
	dx=bounds.origin.x-x;
	dy=bounds.origin.y-y;
	bounds.origin.x=x+cos(dphi)*dx-sin(dphi)*dy;
	bounds.origin.y=y+sin(dphi)*dx+cos(dphi)*dy;
}

- (void)scaleCenter:(float)cx:(float)cy by:(float)scx:(float)scy
{
	bounds.origin.x=cx+(bounds.origin.x-cx)*scx;
	bounds.origin.y=cy+(bounds.origin.y-cy)*scy;
/*	sx*=scx;
	sy*=scy; */
}

- (void)drawPath
{
	DPSPrintf(DPSGetCurrentContext()," matrix currentmatrix ");
	if(transformed)	PStranslate(m[4],m[5]);
/*	if(rotated)		PSrotate(M_180_PI*phi);
	if(scaled)		PSscale(sx,sy); */
	PSmoveto(bounds.origin.x,bounds.origin.y);
	PSrlineto(bounds.size.width,0);
	PSrlineto(0,bounds.size.height);
	PSrlineto(bounds.size.width,0);
	PSclosepath();
	DPSPrintf(DPSGetCurrentContext()," setmatrix\n");
}

- (void)drawControl:(NXRect *)re:(int)cp:(float)bsize
{
	[self draw:re];
	if(transformed) { PSgsave(); PStranslate( m[4], m[5]); }
	PSsetlinewidth(0);
	PSsetgray(.5);
	PSrectstroke(bounds.origin.x,bounds.origin.y,bounds.size.width,bounds.size.height);
	if(transformed)	PSgrestore();
}

- addTranslation:(float)dtx:(float)dty
{
	bounds.origin.x+=dtx;
	bounds.origin.y+=dty;
	return self;
}

- makeCharacterPath:view:cp
{
	char *special;
	char *buf;
	
if(rich)
{
NXStream *stream;

stream=NXOpenMemory(rich,length,NX_READONLY);
[globalText readRichText:stream];
NXClose(stream);
}
	buf=(char *)malloc(sizeof(char)*(2+[globalText textLength]));
	special=(char *)malloc(sizeof(char)*(200+[globalText textLength]));
	// special=(char *)malloc(sizeof(char)*(200));
	[globalText getSubstring: buf start: 0 length: [globalText textLength]+1];
	sprintf(special,"/text (");
	convertToPSString(special+strlen(special), buf);
	sprintf(special+strlen(special), ") def\n/font (%s) def /fontsize %g def", [[globalText font] name], [[globalText font] pointSize]);
	
	[cp setMethodname:"charP"];
	[cp setDrawingMethod:"dF"];
	[cp setFillMethod:"fill"];
	[cp setStrokeMethod:"stroke"];
	[cp setSpecialAttributes:special];
	[cp setColor1:NXConvertRGBToColor(0,0,0)];
	[cp setColor2:NXConvertRGBToColor(0,0,0)];
	[cp setLineWidth: .5];
	[cp initWithControlPt: bounds.origin.x: bounds.origin.y];
	free(special);
	free(buf);
	return self;
}

- write:(NXTypedStream *)stream
{
	[super write:stream];
	NXWriteTypes(stream,"*i",&rich,&length);
	return self;	
}

- read:(NXTypedStream *)stream
{
	[super read:stream];
	NXReadTypes(stream,"*i",&rich,&length);
	return self;
}

- (int)type
{
	return 1;
}

#define WRITE_STRING(a) if((a) && strcmp(a,"")) NXPrintf(to, "{%s} ", a); else NXPrintf(to, "{} ")

- (void)giveDescription:(Tcl_Interp *)interp
{
	[super giveDescription:interp];
	Tcl_AppendElement( interp, rich);
}

- (void)specialDescription: (Tcl_Interp *)interp: (int)argc: (char **)argv
{
	if(argc>=19) {
		if(rich) free(rich);
		rich=(char *)malloc(sizeof(char)*((length=strlen(argv[18]))+1));
		strcpy(rich, argv[18]);
		sscanf(argv[8], "%f %f %f %f", &bounds.origin.x, &bounds.origin.y, &bounds.size.width, &bounds.size.height);
	}
}

- setMethodname: (char *)name
{
	return self;
}
@end

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.