home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Programming / DrawingServant / Source / DrawingServant.m < prev    next >
Encoding:
Text File  |  1993-07-13  |  10.9 KB  |  511 lines

  1. /*DrawingServant Version 0.1
  2.  
  3. A utility program for putting a NeXT graphics head on a
  4. terminal based program.  Since this is never intended to be
  5. a REAL NeXT application, many parts of an "official" application
  6. (i.e. Preferences, Help, language selection...) are omitted.
  7. This program is primarily intended to be forked from another process
  8. and communicated to through pipes. (Although you can invoke it
  9. directly and have yet another PS hacker's treat.  Perhaps it is
  10. slightly easier to use than pft.)
  11. Comments, additions, subtractions are appreciated
  12.     joe@ril3.tamri.com
  13. Copyright 1993 Joe Carlson
  14. Permission is granted for non-commercial reproduction and
  15. redistribution of this code provided this copyright notice
  16. remains.
  17. If you want to port some common program with this, drop me
  18. a note.  I'll try to keep track of what is out there.
  19.  
  20. This is IB free.  The code is maybe slightly more amenable to hacking
  21. because of it.
  22. */
  23.  
  24. #import <appkit/appkit.h>
  25. #import "DrawingServant.h"
  26.  
  27. /* Default values for in and out pipes, x and y location
  28. and height and width of the window.  Last number is initial
  29. size of PS code */
  30. #define DEFINPIPE 0
  31. #define DEFOUTPIPE 1
  32. #define DEFX 400.
  33. #define DEFY 250.
  34. #define DEFH 500.
  35. #define DEFW 500.
  36. #define MAXSTRINGSSTART 512
  37. static char *VERSIONID = "Drawing Servant Version 0.1\n";
  38. static char *ACKSTRING = "Ok\n";
  39.  
  40. /* things for possible improvements and additions:
  41.     1) multiple windows
  42.     2) error handling
  43.     3) why do I need the gsave/grestore?
  44. */
  45.  
  46. id DrawView;
  47. id DrawWindow;
  48. id myWindow, myMenu, windowText;
  49. id Panelview,myPanel;
  50.  
  51. void setUp(argc,argv)
  52. int argc;
  53. char **argv;
  54. {
  55.  
  56.  
  57.     NXRect aRect;
  58.     int i;
  59.  
  60.     void *data;
  61.     void iohandler();
  62.  
  63.     /* Set up a Panel */
  64.  
  65.     NXSetRect(&aRect, 150.0, 600.0, 300.0, 200.0);
  66.     Panelview = [[InfoPanel alloc]init];
  67.     [Panelview setOpaque:YES];
  68.     myPanel = [[Panel alloc] initContent:&aRect
  69.                     style:NX_TITLEDSTYLE
  70.                     backing:NX_BUFFERED
  71.                     buttonMask:NX_CLOSEBUTTONMASK
  72.                 defer:YES];
  73.     [myPanel setTitle:"About Drawing Servant"];
  74.     [myPanel setContentView:Panelview];
  75.  
  76.     /* set up the drawing window */
  77.     DrawView = [[Drawclass alloc] init];
  78.     [DrawView commandlineargs:argc:argv];
  79.     [DrawView setOpaque:YES];
  80.     DrawWindow = [[Window alloc]initContent:[DrawView viewbox:nil]
  81.                     style:NX_TITLEDSTYLE
  82.                     backing:NX_BUFFERED
  83.                     buttonMask:NX_CLOSEBUTTONMASK
  84.                     defer:NO];
  85.  
  86.     [DrawWindow setTitle:"Drawing Servant"];
  87.     [DrawWindow setContentView:DrawView];
  88.     [DrawWindow orderFront:nil];
  89.     [DrawWindow display];
  90.     [DrawView mouseoff:nil];
  91.     [DrawView ackon:nil];
  92.     [DrawView expandstringarea:MAXSTRINGSSTART From:0];
  93.     [[DrawView window]addToEventMask: NX_RMOUSEDOWNMASK];
  94.  
  95.  
  96.     /* Set up a Menu */
  97.     myMenu = [[Menu alloc] initTitle:"Drawing Servant"];
  98.     [[myMenu addItem:"Info..."
  99.             action:@selector(orderFront:)
  100.             keyEquivalent:'\0']
  101.                 setTarget:myPanel];
  102.     /* gee...I'd like to get this working next... */
  103.     /*[[myMenu addItem:"New"
  104.             action:@selector(newview:)
  105.             keyEquivalent:'n']
  106.             setTarget:DrawView];*/
  107.     [[myMenu addItem:"Clear"
  108.             action:@selector(clearview:)
  109.             keyEquivalent:'c']
  110.             setTarget:DrawView];
  111.     [[myMenu addItem:"Save"
  112.             action:@selector(saveview:)
  113.             keyEquivalent:'s']
  114.             setTarget:DrawView];
  115.     [[myMenu addItem:"Print"
  116.             action:@selector(printview:)
  117.             keyEquivalent:'p']
  118.             setTarget:DrawView];
  119.     [myMenu addItem:"Hide"
  120.             action:@selector(hide:)
  121.             keyEquivalent:'h'];
  122.     [myMenu addItem:"Quit"
  123.             action:@selector(terminate:)
  124.             keyEquivalent:'q'];
  125.     [myMenu sizeToFit];
  126.     [NXApp setMainMenu:myMenu];
  127.  
  128.  
  129.     /* prepare to interrupt on input */
  130.     DPSAddFD([DrawView inpipe:nil],iohandler,data,NX_BASETHRESHOLD);
  131.     
  132.     return;
  133. }
  134. void
  135. iohandler(fd,data)
  136. int fd;
  137. void *data;
  138. {
  139.  
  140.     char string[BUFSIZ];
  141.     int i;
  142.     void processcommand();
  143.  
  144.     read([DrawView inpipe:nil],string,sizeof(string)-1);
  145.  
  146.     /* just make sure we are terminated */
  147.     for(i=0;i<strlen(string);i++) {
  148.         if(string[i]=='\n' || string[i]==0){
  149.             string[i]='\n';
  150.             /* zero out the rest, just to be safe... */
  151.             for(i++;i<strlen(string);string[i++]=0);
  152.             break;
  153.         }
  154.     }
  155.  
  156.     processcommand(string);
  157. }
  158.  
  159. processcommand(string)
  160. char *string;
  161. {
  162.     if(!strncmp(string,"DSversion",9) ) {
  163.         write([DrawView outpipe:nil],VERSIONID,strlen(VERSIONID));
  164.  
  165.     } else if (!strncmp(string,"DSclear",7) ) {
  166.         [DrawView clearview:nil];
  167.  
  168.     } else if (!strncmp(string,"DSsave",6) ) {
  169.         [DrawView saveview:nil];
  170.  
  171.     } else if (!strncmp(string,"DSoops",6) ) {
  172.         [DrawView subfromstrings:string];
  173.  
  174.     } else if (!strncmp(string,"DSprint",7) ) {
  175.         [DrawView printview:nil];
  176.  
  177.     } else if (!strncmp(string,"DSmouseon",9) ) {
  178.         [DrawView mouseon:nil];
  179.  
  180.     } else if (!strncmp(string,"DSmouseoff",10) ) {
  181.         [DrawView mouseoff:nil];
  182.  
  183.     } else if (!strncmp(string,"DSackon",7) ) {
  184.         [DrawView ackon:nil];
  185.  
  186.     } else if (!strncmp(string,"DSackoff",8) ) {
  187.         [DrawView ackoff:nil];
  188.  
  189.     } else if (!strncmp(string,"DSfront",7) ) {
  190.         [[DrawView window] orderFrontRegardless];
  191.  
  192.     } else if (!strncmp(string,"DShide",6) ) {
  193.         [NXApp hide:nil];
  194.  
  195.     } else if (!strncmp(string,"DSquit",6) ) {
  196.         [NXApp terminate:nil];
  197.  
  198.     } else {
  199.         [DrawView addtostrings:string];
  200.     }
  201.     /* 'S alright? */
  202.     if([DrawView isackon:nil])
  203.     write([DrawView outpipe:nil],ACKSTRING,strlen(ACKSTRING));
  204.  
  205. }
  206.  
  207. @implementation Drawclass
  208. -drawSelf: (NXRect *)rects: (int)rectCount;
  209. {
  210.     int i;
  211.     
  212.     /* just clear the screen */
  213.     if(needtoclear) {
  214.         PSsetgray(NX_WHITE);
  215.         PSrectfill(bounds.origin.x,bounds.origin.y,
  216.                 bounds.size.width,bounds.size.height);
  217.         PSsetgray(NX_BLACK);
  218.         needtoclear = NO;
  219.     /* just write the last string to the window server */
  220.     } else if(justlast) {
  221.         if(nstrings) {
  222.         /* can someone tell me why the save/restore is needed?*/
  223.             PSgrestore();
  224.             DPSPrintf(DPSGetCurrentContext(),
  225.                     "%s \n",psstrings[nstrings-1]);
  226.             PSgsave();
  227.         }
  228.     /* the whole thing */
  229.     } else {
  230.         for(i=0;i<nstrings;) {
  231.             DPSPrintf(DPSGetCurrentContext(),"%s \n",psstrings[i++]);
  232.         }
  233.     }
  234.     return self;
  235. }
  236. -addtostrings:(char *)string;
  237. {
  238.     /* if we got too many strings, allocate space for more */
  239.     if(nstrings==maxstrings)
  240.         [self expandstringarea:2*maxstrings From:maxstrings];
  241.  
  242.     psstrings[nstrings] = malloc(strlen(string)+1);
  243.     strcpy(psstrings[nstrings++],string);
  244.  
  245.     /* when the string is added to the list, we just need to
  246.     update the screen with the last line */
  247.     justlast = YES;
  248.     [self display];
  249.  
  250.     /* otherwise (for printing or saving) we'll want to send to
  251.     entire list of postscript commands */
  252.     justlast = NO;
  253.     return;
  254. }
  255. -subfromstrings:(char *)string;
  256. {
  257.     /* remove the last */
  258.     if(nstrings)
  259.         free(psstrings[--nstrings]);
  260.     /*redraw all the ps code */
  261.     justlast = NO;
  262.     [self display];
  263. }
  264. -clearview:sender;
  265. {
  266.     for(;nstrings;) {
  267.         free(psstrings[--nstrings]);
  268.     }
  269.     needtoclear = YES;
  270.     [self display];
  271.     return self;
  272. }
  273. -saveview:sender;
  274. {
  275.     id save;
  276.     save = [[SavePanel new]
  277.             setRequiredFileType:"eps"];
  278.  
  279.     if ([save runModal]==1) {
  280.         NXStream *aStream;
  281.         aStream = NXOpenMemory(0,0,NX_WRITEONLY);
  282.         [self copyPSToStream:aStream forView:self];
  283.         NXSaveToFile(aStream, [save filename]);
  284.         NXCloseMemory(aStream, NX_FREEBUFFER);
  285.     }
  286.     return self;
  287. }
  288. -copyPSToStream:(NXStream *)aStream forView:view;
  289. {
  290.     NXRect boundingbox;
  291.  
  292.     [view getBounds:&boundingbox];
  293.     [view copyPSCodeInside:&boundingbox to:aStream];
  294.     return self;
  295. }    
  296. -printview:sender
  297. {
  298.     [self printPSCode:nil];
  299.     return self;
  300. }    
  301. -(int)inpipe:sender
  302. {
  303.     return inpipenumber;
  304. }
  305. -(int)outpipe:sender
  306. {
  307.     return outpipenumber;
  308. }
  309. -(NXRect *)viewbox:sender
  310. {
  311.     return &windowrectangle;
  312. }
  313. -expandstringarea:(int)to From:(int)from
  314. {
  315.     char **temp;
  316.     int i;
  317.  
  318.     temp = (char **) malloc(to*sizeof(char *));
  319.     for(i=0;i<from;i++) {
  320.         temp[i] = psstrings[i];
  321.     }
  322.     if(from)
  323.         free(psstrings);
  324.     psstrings = temp;
  325.     maxstrings = to;
  326.     return;
  327. }
  328. -mouseon:sender
  329. {
  330.     printmouseclicks = YES;
  331.     return self;
  332. }
  333. -mouseoff:sender
  334. {
  335.     printmouseclicks = NO;
  336.     return self;
  337. }
  338. -mouseDown:(NXEvent *)theEvent
  339. {
  340.     char string[80];
  341.  
  342.     if(printmouseclicks) {
  343.         sprintf(string,"left mouse %f %f\n",
  344.             theEvent->location.x,theEvent->location.y);
  345.         write([DrawView outpipe:nil],string,strlen(string));
  346.     }
  347.     return;
  348.  
  349. return self;
  350. }
  351. -rightMouseDown:(NXEvent *)theEvent
  352. {
  353.     char string[80];
  354.  
  355.     if(printmouseclicks) {
  356.         sprintf(string,"right mouse %f %f\n",
  357.             theEvent->location.x,theEvent->location.y);
  358.         write([DrawView outpipe:nil],string,strlen(string));
  359.     }
  360.     return;
  361.  
  362. return self;
  363. }
  364.  
  365. -ackon:sender
  366. {
  367.     sendackstring = YES;
  368.     return self;
  369. }
  370. -ackoff:sender
  371. {
  372.     sendackstring = NO;
  373.     return self;
  374. }
  375. -(BOOL)isackon:sender
  376. {
  377.     if(sendackstring)
  378.         return YES;
  379.     else
  380.         return NO;
  381. }
  382. -commandlineargs: (int)argc: (char **)argv;
  383. /* process the command line arguments. Nothing fancy here, just
  384. plow through things.  - signs before args are not required.*/
  385. {
  386.     int i;
  387.  
  388.     /* reasonable guesses for things like in and outpipes,
  389.     height width and placement */
  390.     height = DEFH;
  391.     width = DEFW;
  392.     xoffset = DEFX;
  393.     yoffset = DEFY;
  394.     inpipenumber = DEFINPIPE;
  395.     outpipenumber = DEFOUTPIPE;
  396.     for(i=1;i<argc;) {
  397.         /* strip off tabs and blanks */
  398.         for(;argv[i][0]==' ' || argv[i][0]=='    ';)
  399.             strcpy(argv[i],argv[i]+1);
  400.         /* perhaps arguments have a - in front; or maybe not.
  401.         we are processing everything as a switch, strip off the - */
  402.         if(argv[i][0]=='-') 
  403.             strcpy(argv[i],argv[i]+1);
  404.         switch (argv[i][0]) {
  405.             case 'h': case 'H':
  406.                 if(argv[i][1]==0){
  407.                     if(++i==argc) 
  408.                         break;
  409.                     height = atof(argv[i]);
  410.                 } else {
  411.                     height = atof(argv[i]+1);
  412.                 }
  413.                 i++;
  414.                 break;
  415.             case 'w': case 'W':
  416.                 if(argv[i][1]==0) {
  417.                     if(++i==argc)
  418.                         break;
  419.                     width = atof(argv[i]);
  420.                 } else {
  421.                     width = atof(argv[i]+1);
  422.                 }
  423.                 i++;
  424.                 break;
  425.             case 'x': case 'X':
  426.                 if(argv[i][1]==0) {
  427.                     if(++i==argc)
  428.                         break;
  429.                     xoffset = atof(argv[i]);
  430.                 } else {
  431.                     xoffset = atof(argv[i]+1);
  432.                 }
  433.                 i++;
  434.                 break;
  435.             case 'y': case 'Y':
  436.                 if(argv[i][1]==0) {
  437.                     if(++i==argc)
  438.                         break;
  439.                     yoffset = atof(argv[i]);
  440.                 } else {
  441.                     yoffset = atof(argv[i]+1);
  442.                 }
  443.                 i++;
  444.                 break;
  445.             case 'i': case 'I':
  446.                 if(argv[i][1]==0) {
  447.                     if(++i==argc)
  448.                         break;
  449.                     inpipenumber=atoi(argv[i]);
  450.                 } else {
  451.                     inpipenumber=atoi(argv[i]+1);
  452.                 }
  453.                 i++;
  454.                 break;
  455.             case 'o': case 'O':
  456.                 if(argv[i][1]==0) {
  457.                     if(++i==argc)
  458.                         break;
  459.                     outpipenumber=atoi(argv[i]);
  460.                 } else {
  461.                     outpipenumber=atoi(argv[i]+1);
  462.                 }
  463.                 i++;
  464.                 break;
  465.             default:
  466.                 i++;
  467.             }
  468.         }
  469.  
  470.     NXSetRect([self viewbox:nil],xoffset,yoffset,width,height);
  471. }
  472. @end
  473.  
  474. main(argc,argv)
  475. int argc;
  476. char **argv;
  477. {
  478.     [Application new];
  479.     setUp(argc,argv);
  480.     [NXApp run];
  481.     [NXApp free];
  482. }
  483. @implementation InfoPanel
  484. -drawSelf: (NXRect *)rects: (int) rectCount;
  485. {
  486.     NXRect aRect;
  487.     DPSTimedEntryProc melter();
  488.  
  489.     NXSetRect(&aRect,0.,0., 300.0, 200.0);
  490.     PSsetgray(NX_WHITE);
  491.     PSrectfill(bounds.origin.x,bounds.origin.y,
  492.                 bounds.size.width,bounds.size.height);
  493.     PSsetgray(NX_BLACK);
  494.     PSmoveto(45.,150.);
  495.     PSselectfont("Times-Roman",20.);
  496.     PSshow(VERSIONID);
  497.  
  498.     PSselectfont("Times-Roman",12.);
  499.     PSmoveto(45.,100.);
  500.     PSshow("Copyright 1993 by J Carlson");
  501.     PSmoveto(45.,85.);
  502.     PSshow("Permission is granted for noncommercial");
  503.     PSmoveto(45.,70.);
  504.     PSshow("Redistribution of this program");
  505.     PSmoveto(45.,55.);
  506.     PSshow("Provided this copyright notice stays intact.");
  507.  
  508.     return self;
  509. }
  510. @end
  511.