This is TGIF.m in view mode; [Download] [Up]
#import "TGIF.h"
#import "ListCell.h"
#import "ListMatrix.h"
#import "NXBitmapGraphicRep.h"
#import "PolyInspector.h"
#import "TGIFCell.h"
#import "miscutil.h"
#import <appkit/Application.h>
#import <appkit/Matrix.h>
#import <appkit/NXCursor.h>
#import <appkit/OpenPanel.h>
#import <appkit/SavePanel.h>
#import <appkit/ScrollView.h>
#import <appkit/Window.h>
#import <appkit/color.h>
#import <appkit/graphics.h>
#import <appkit/nextstd.h>
#import <stdio.h>
#import <streams/streams.h>
#import <sys/param.h>
// import command cell objects
#import "CmdBgcolor.h"
#import "CmdBgnpoly.h"
#import "CmdCircle.h"
#import "CmdComment.h"
#import "CmdDraw.h"
#import "CmdEndpoly.h"
#import "CmdFgcolor.h"
#import "CmdFps.h"
#import "CmdHold.h"
#import "CmdMove.h"
#import "CmdNewframe.h"
#import "CmdVertex.h"
#import "AbsPoly.h"
NXBitmapGraphicRep *theBitmap=nil;
@implementation TGIF
id backup; // for undo
id openPanel, savePanel;
id pbList; // for a "pasteboard" of cells.
BOOL getOpenPath(char *buf, char const *type1, char const *type2)
{
char const *fileTypes[3] = {0,0,0};
if (!openPanel)
openPanel = [OpenPanel new];
[openPanel allowMultipleFiles:NO];
if (type1 && *type1)
fileTypes[0] = type1;
if (type2 && *type2)
fileTypes[1] = type2;
[NXApp setAutoupdate:NO];
if ([openPanel runModalForDirectory:(const char*)buf
file:"" types:fileTypes]) {
strcpy(buf,[openPanel filename]);
[NXApp setAutoupdate:YES];
return YES;
} else {
[NXApp setAutoupdate:YES];
return NO;
}
}
BOOL getSavePath(char *returnBuf, char *dir, char *name, char const *theType)
{
if (!savePanel) {
savePanel = [SavePanel new];
[savePanel setTitle:"GraphicsWrap Save"];
}
if (theType && *theType)
[savePanel setRequiredFileType:theType];
[NXApp setAutoupdate:NO];
if ([savePanel runModalForDirectory:dir file:name]) {
strcpy(returnBuf,[savePanel filename]);
[NXApp setAutoupdate:YES];
return YES;
} else {
[NXApp setAutoupdate:YES];
return NO;
}
}
void parsePath(char *path, char *dir, char *name)
{
char *c1, *c2;
int dirlen, namelen;
c1 = strrchr(path, '.');
c2 = strrchr(path, '/');
dirlen = (c2) ? c2-path+1 : 0;
namelen = ((c1) ? c1-path : strlen(path)) -dirlen;
strncpy(dir,path,dirlen);
dir[dirlen] = '\0';
strncpy(name, path+dirlen, namelen);
name[namelen] = '\0';
}
void getPath(char *path, char *dir, char *name, char *ext)
/* construct a path given a file name, directory, and type */
{
strcpy(path,(dir)?dir:NXHomeDirectory());
if (name) {
strcat(path,name);
if (strlen(ext) && (ext[0] != '.'))
strcat(path,".");
strcat(path,ext);
}
}
- displayMatrix:aMatrix
{
[aMatrix sizeToCells];
[aMatrix display];
return self;
}
- initMatrix
{
NXRect aRect, bRect;
NXSize cellSpacing={0.0,0.0}, cellSize;
[tgif_view getFrame:&aRect];
[ScrollView getContentSize:&(bRect.size) forFrameSize:&(aRect.size)
horizScroller:YES vertScroller:YES borderType:NX_BEZEL];
tgif_matrix = [[ListMatrix alloc] initFrame:&bRect mode:NX_LISTMODE
cellClass:[TGIFCell class] numRows:0 numCols:1];
[tgif_matrix setIntercell:&cellSpacing];
[tgif_matrix allowEmptySel:YES];
[tgif_matrix setControlDrag:YES];
[tgif_matrix getCellSize:&cellSize];
cellSize.width = NX_WIDTH(&bRect);
[tgif_matrix setCellSize:&cellSize];
[tgif_matrix sizeToCells];
[tgif_matrix setAutosizeCells:YES];
[tgif_matrix setAutoscroll:YES];
[tgif_view setDocView:tgif_matrix];
[[tgif_matrix superview] setAutoresizeSubviews:YES];
[tgif_matrix setAutosizing:NX_WIDTHSIZABLE];
[tgif_matrix setBackgroundGray:NX_LTGRAY];
[tgif_matrix setCellBackgroundGray:NX_LTGRAY];
[tgif_view setBackgroundGray:NX_LTGRAY];
[tgif_view setDocCursor:NXArrow];
[tgif_matrix setTarget:self];
[tgif_matrix setAction:@selector(tgif_click:)];
[self displayMatrix:tgif_matrix];
return self;
}
- initWithBitmap:abp andView:av;
{
char title[100];
[super init];
[NXApp loadNibSection:"TGIF.nib" owner:self withNames:NO];
theBitmap=abp;
bitmap_view=av;
poly_insp=[[PolyInspector alloc] init];
NX_MALLOC(filePath,char,MAXPATHLEN+1);
NX_MALLOC(fileName,char,MAXPATHLEN+1);
NX_MALLOC(fileDir,char,MAXPATHLEN+1);
sprintf(title,"UNTITLED.tgif");
[tgif_window setTitleAsFilename:(const char*)title];
NXPing();
sprintf(filePath,"~/");
sprintf(fileName,title);
sprintf(fileDir,"~/");
[self initMatrix];
return self;
}
- perform:sender
{
id cellList=[tgif_matrix cellListIncludeAll:NO];
int i, max=[cellList count];
if(!max)cellList=[tgif_matrix cellListIncludeAll:YES];
for(i=0;i<max;i++){
[[cellList objectAt:i] doCmd];
[bitmap_view display];
}
return self;
}
- tgif_click:sender
{
id tList=[tgif_matrix cellListIncludeAll:NO];
if(([tList count] == 1) && [[tList objectAt:0] isMemberOf:[AbsPoly class]]){
[poly_insp inspect:[tList objectAt:0]];
[[poly_insp window] makeKeyAndOrderFront:self];
} else [[poly_insp window] orderOut:self];
return self;
}
- saveToFile
{
int i;
id cmdList;
NXStream *theStream;
if (!getSavePath(filePath,fileDir,fileName,"tgif"))
return self;
parsePath(filePath, fileDir, fileName);
theStream=NXOpenMemory(NULL, 0, NX_WRITEONLY);
cmdList=[tgif_matrix cellListIncludeAll:YES];
for(i=0;i<[cmdList count];i++)
NXPrintf(theStream, "%s", [[cmdList objectAt:i] emitCmd]);
NXFlush(theStream);
NXSaveToFile(theStream, filePath);
NXClose(theStream);
return self;
}
- addRowTo:newCell
{
int rc, cc;
[tgif_matrix getNumRows:&rc numCols:&cc];
[tgif_matrix addRow];
[tgif_matrix putCell:newCell at:rc :0];
return self;
}
id curPoly;
BOOL polyMode;
- addActiveCmd:(char *)cmd
{
long arg1=-1, arg2=-1, arg3=-1;
int cc=0, argnum=0;
char *c[3];
c[0]=c[1]=c[2]=(char *)nil;
while(cmd[cc]!='\0'){
if(cmd[cc]==' '){
cmd[cc]='\0';
c[argnum++]=&cmd[++cc];
} else cc++;
}
if(c[0]) arg1=atol(c[0]);
if(c[1]) arg2=atol(c[1]);
if(c[2]) arg3=atol(c[2]);
if (polyMode){
// check for "endpoly"
if(!strcmp(cmd, "endpoly") || !strcmp(cmd,"ep")){
[curPoly addCommand:[[CmdEndpoly alloc] initCmd]];
polyMode=FALSE;
}
//check for "vertex"
else if(!strcmp(cmd, "vertex") || !strcmp(cmd,"v"))
[curPoly addCommand:[[CmdVertex alloc] initCmd:arg1 :arg2]];
else fprintf(stderr, "Illegal token in PolyGon definition:%s %d %d %d\n",
cmd, arg1, arg2, arg3);
} else {
// check for "move"
if(!strcmp(cmd, "move") || !strcmp(cmd,"m"))
[self addRowTo:[[CmdMove alloc] initCmd:arg1 :arg2]];
// check for "draw"
else if(!strcmp(cmd, "draw") || !strcmp(cmd,"d"))
[self addRowTo:[[CmdDraw alloc] initCmd:arg1 :arg2]];
// check for "circle"
else if(!strcmp(cmd, "circle") || !strcmp(cmd,"c"))
[self addRowTo:[[CmdCircle alloc] initCmd:arg1]];
//check for "fgcolor"
else if(!strcmp(cmd, "fgcolor") || !strcmp(cmd,"fg"))
[self addRowTo:[[CmdFgcolor alloc] initCmd:arg1 :arg2 :arg3]];
// check for "bgcolor"
else if(!strcmp(cmd, "bgcolor") || !strcmp(cmd,"bg"))
[self addRowTo:[[CmdBgcolor alloc] initCmd:arg1 :arg2 :arg3]];
// check for "bgnpoly"
else if(!strcmp(cmd, "bgnpoly") || !strcmp(cmd,"bp")){
curPoly=[[AbsPoly alloc] init];
[self addRowTo:curPoly];
[curPoly addCommand:[[CmdBgnpoly alloc] initCmd]];
polyMode=TRUE;
}
// check for "newframe"
else if(!strcmp(cmd, "newframe") || !strcmp(cmd,"n"))
[self addRowTo:[[CmdNewframe alloc] initCmd]];
// check for "fps"
else if(!strcmp(cmd, "fps"))
[self addRowTo:[[CmdFps alloc] initCmd:arg1]];
// check for "hold"
else if(!strcmp(cmd, "hold"))
[self addRowTo:[[CmdHold alloc] initCmd:arg1]];
else fprintf(stderr, "Bad Token (ignore -1): %s %d %d %d\n",
cmd, arg1, arg2, arg3);
}
return self;
}
- openFile
{
char path[MAXPATHLEN+1], cmd[2000];
char c;
int rc, cc;
NXStream *theStream;
if (getOpenPath(path,"tgif",fileDir)) {
[tgif_matrix getNumRows:&rc numCols:&cc];
for(cc=0;cc<rc;cc++)
[tgif_matrix removeRowAt:cc andFree:YES];
theStream=NXMapFile(path, NX_READONLY);
cc=0;
while((c=NXGetc(theStream))!=EOF){
cmd[cc]=c;
if(c=='\n'){
cmd[cc]='\0';
cc=0;
if(cmd[0]=='#') {
// this is a comment line
[self addRowTo:[[CmdComment alloc] initComment:cmd]];
} else
// this is really a command, process it as one
[self addActiveCmd:cmd];
} else cc++;
}
NXClose(theStream);
}
[self displayMatrix:tgif_matrix];
strcpy(filePath, path);
parsePath(filePath, fileDir, fileName);
[tgif_window setTitleAsFilename:(const char*)filePath];
return self;
}
- newFile
{
char title[100];
int i, rc, cc;
[tgif_matrix getNumRows:&rc numCols:&cc];
for(i=0;i<rc;i++)
[tgif_matrix removeRowAt:0 andFree:YES];
[self displayMatrix:tgif_matrix];
sprintf(title,"UNTITLED.tgif");
[tgif_window setTitleAsFilename:(const char*)title];
NXPing();
sprintf(filePath,"~/");
sprintf(fileName,title);
sprintf(fileDir,"~/");
return self;
}
- cmdMove:(int)x :(int)y
{
[self addRowTo:[[CmdMove alloc] initCmd:x :y]];
[self displayMatrix:tgif_matrix];
return self;
}
- cmdDraw:(int)x :(int)y
{
[self addRowTo:[[CmdDraw alloc] initCmd:x :y]];
[self displayMatrix:tgif_matrix];
return self;
}
-cmdNewFrame
{
[self addRowTo:[[CmdNewframe alloc] initCmd]];
[self displayMatrix:tgif_matrix];
return self;
}
- cmdForeColor:(NXColor)aColor
{
[self addRowTo:[[CmdFgcolor alloc] initCmdColor:aColor]];
[self displayMatrix:tgif_matrix];
return self;
}
- cmdBackColor:(NXColor)aColor
{
[self addRowTo:[[CmdBgcolor alloc] initCmdColor:aColor]];
[self displayMatrix:tgif_matrix];
return self;
}
- cmdComment:(char *)comment
{
char *tmp;
tmp=(char *) malloc((strlen(comment)+3)*sizeof(char));
sprintf(tmp, "#%s\n", comment);
[self addRowTo:[[CmdComment alloc] initComment:tmp]];
free(tmp);
return self;
}
- cmdNewPoly
{
// create new polygon
id aPoly=[[AbsPoly alloc] init];
// add polygon to our matrix
[self addRowTo:aPoly];
[self displayMatrix:tgif_matrix];
// return polygon to caller for vertex addition
return aPoly;
}
// through first responder
- delete:sender
{
id cellList;
int i, rc, cc;
cellList=[tgif_matrix cellListIncludeAll:NO];
for(i=0;i<[cellList count];i++){
[tgif_matrix getRow:&rc andCol:&cc ofCell:[cellList objectAt:i]];
[tgif_matrix removeRowAt:rc andFree:NO];
}
[cellList freeObjects];
[self displayMatrix:tgif_matrix];
return self;
}
- cut:sender
{
int i, rc, cc;
if(pbList) [pbList free]; else pbList=[[List alloc] init];
pbList=[tgif_matrix cellListIncludeAll:NO];
for(i=0;i<[pbList count];i++){
[tgif_matrix getRow:&rc andCol:&cc ofCell:[[pbList objectAt:i] copy]];
[tgif_matrix removeRowAt:rc andFree:YES];
}
[self displayMatrix:tgif_matrix];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.