[mod.mac.sources] Ascii Chart DA

st94wb@sdcc12.UUCP (wade blomgren) (09/03/86)

#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	ascii_chart.c
sed 's/^X//' << 'SHAR_EOF' > ascii_chart.c
X/*************************************************************************/
X/*   Ascii Chart - a Desk Accessory for the Macintosh written by:        */
X/*   Wade S. Blomgren    (c) 1986             version 1.0                */
X/*   UC San Diego                                                        */
X/*                                                                       */
X/*   Both source and executable files may be freely distributed for      */
X/*   NON-COMMERCIAL USE ONLY provided this copyright notice is left      */
X/*   intact.                                                             */
X/*                                                                       */
X/*   This program is intended as an example for persons beginning to     */
X/*   learn about programming the Macintosh. It is NOT meant to be an     */
X/*   example of excellent programming or a particularly fabulous         */
X/*   idea for a program.  It IS supposed to be chock full of comments    */
X/*   and to have some examples of common uses for the toolbox.           */
X/*                                                                       */
X/*    This program was written using LightspeedC (c) from Think          */
X/*    Technologies, INC. and therefore includes material that is         */
X/*    copyright Think Technologies INC.                                  */
X/*                                                                       */
X/*    Some techniques were gleaned from a PD desk accessory called       */
X/*    ZoomIdle by Paul DuBois, University of Wisconsin                   */
X/*                                                                       */
X/*    Wade S. Blomgren  UCSD-ACS   mailcode B-028  La Jolla, CA 92093    */
X/*                                                                       */
X/*************************************************************************/
X
X#include "devicemgr.h"
X#include "quickdraw.h"
X#include "windowmgr.h"
X#include "dialogmgr.h"
X#include "eventmgr.h"
X#include "controlmgr.h"
X
X/* since this is a DA and not a standalone application we do not have to */
X/* initialize the various managers                                       */
X
X/* Global Variables for the DA */
X
X/* the chart data is stored in two dimensional arrays so we can use the */
X/* drawtext routine (faster than repeated calls to drawchar) (IM I-172) */
X
X char octdata[23][47] = {
X        "000 NUL  026 SYC  054 ,  102 B  130 X  156 n  ",
X        "001 SOH  027 ETB  055 -  103 C  131 Y  157 o  ",
X        "002 STX  030 CAN  056 .  104 D  132 Z  160 p  ",
X        "003 ETX  031 EM   057 /  105 E  133 [  161 q  ",
X        "004 EOT  032 SUB  060 0  106 F  134 \\  162 r  ",
X        "005 ENQ  033 ESC  061 1  107 G  135 ]  163 s  ",
X        "006 ACK  034 FS   062 2  110 H  136 ^  164 t  ",
X        "007 BEL  035 GS   063 3  111 I  137 _  165 u  ",
X        "010 BS   036 RS   064 4  112 J  140 `  166 v  ",
X        "011 HT   037 US   065 5  113 K  141 a  167 w  ",
X        "012 LF   040 SPA  066 6  114 L  142 b  170 x  ",
X        "013 VT   041 !    067 7  115 M  143 c  171 y  ",
X        "014 FF   042 ''   070 8  116 N  144 d  172 z  ",
X        "015 CR   043 #    071 9  117 O  145 e  173 {  ",
X        "016 SO   044 $    072 :  120 P  146 f  174 |  ",
X        "017 SI   045 %    073 ;  121 Q  147 g  175 }  ",
X        "020 DLE  046 &    074 <  122 R  150 h  176 ~  ",
X        "021 DC1  047 '    075 =  123 S  151 i  177 DEL",        
X        "022 DC2  050 (    076 >  124 T  152 j         ",
X        "023 DC3  051 )    077 ?  125 U  153 k         ",
X        "024 DC4  052 *    100 @  126 V  154 l         ",
X        "025 NAK  053 +    101 A  127 W  155 m         "};
X        
X char decdata[23][47] = {
X       "000 NUL  022 SYC  044 ,  066 B  088 X  110 n  ",
X       "001 SOH  023 ETB  045 -  067 C  089 Y  111 o  ",
X       "002 STX  024 CAN  046 .  068 D  090 Z  112 p  ",
X       "003 ETX  025 EM   047 /  069 E  091 [  113 q  ",
X       "004 EOT  026 SUB  048 0  070 F  092 \\  114 r  ",
X       "005 ENQ  027 ESC  049 1  071 G  093 ]  115 s  ",
X       "006 ACK  028 FS   050 2  072 H  094 ^  116 t  ",
X       "007 BEL  029 GS   051 3  073 I  095 _  117 u  ",
X       "008 BS   030 RS   052 4  074 J  096 `  118 v  ",
X       "009 HT   031 US   053 5  075 K  097 a  119 w  ",
X       "010 LF   032 SPA  054 6  076 L  098 b  120 x  ",
X       "011 VT   033 !    055 7  077 M  099 c  121 y  ",
X       "012 FF   034 ''   056 8  078 N  100 d  122 z  ",
X       "013 CR   035 #    057 9  079 O  101 e  123 {  ",
X       "014 SO   036 $    058 :  080 P  102 f  124 |  ",
X       "015 SI   037 %    059 ;  081 Q  103 g  125 }  ",
X       "016 DLE  038 &    060 <  082 R  104 h  126 ~  ",
X       "017 DC1  039 '    061 =  083 S  105 i  127 DEL",        
X       "018 DC2  040 (    062 >  084 T  106 j         ",
X       "019 DC3  041 )    063 ?  085 U  107 k         ",
X       "020 DC4  042 *    064 @  086 V  108 l         ",
X       "021 NAK  043 +    065 A  087 W  109 m         " };
X       
X char hexdata[23][47] = {
X
X       "000 NUL  016 SYC  02C ,  042 B  058 X  06E n  ",
X       "001 SOH  017 ETB  02D -  043 C  059 Y  06F o  ",
X       "002 STX  018 CAN  02E .  044 D  05A Z  070 p  ",
X       "003 ETX  019 EM   02F /  045 E  05B [  071 q  ",
X       "004 EOT  01A SUB  030 0  046 F  05C \\  072 r  ",  /* escape the \
Xcharacter */
X       "005 ENQ  01B ESC  031 1  047 G  05D ]  073 s  ",
X       "006 ACK  01C FS   032 2  048 H  05E ^  074 t  ",
X       "007 BEL  01D GS   033 3  049 I  05F _  075 u  ",
X       "008 BS   01E RS   034 4  04A J  060 `  076 v  ",
X       "009 HT   01F US   035 5  04B K  061 a  077 w  ",
X       "00A LF   020 SPA  036 6  04C L  062 b  078 x  ",
X       "00B VT   021 !    037 7  04D M  063 c  079 y  ",
X       "00C FF   022 ''   038 8  04E N  064 d  07A z  ",
X       "00D CR   023 #    039 9  05F O  065 e  07B {  ",
X       "00E SO   024 $    03A :  050 P  066 f  07C |  ",
X       "00F SI   025 %    03B ;  051 Q  067 g  07D }  ",
X       "010 DLE  026 &    03C <  052 R  068 h  07E ~  ",
X       "011 DC1  027 '    03D =  053 S  069 i  07F DEL",        
X       "012 DC2  028 (    03E >  054 T  06A j         ",
X       "013 DC3  029 )    03F ?  055 U  06B k         ",
X       "014 DC4  02A *    040 @  056 V  06C l         ",
X       "015 NAK  02B +    041 A  057 W  06D m         " };
X   
X    DCtlPtr dce;         /* pointer to the device control entry struct */
X    int DAisOpen = 0;    /* flag so we know if the DA is already open  */
X    
X#define rALRT 0          /* the About box's resource ID # */   
X
X/* allocate control handles to the various control buttons */
X       
X	ControlHandle OctPtr,HexPtr,DecPtr,curControl,whichControl,AbPtr;
X	
X
X	int line;     /* counter for the text drawing loop */
X	int y;        /* coordinate variable for positioning the text */
X	
X/* define rectangles for the DA's window and the control buttons  */
X/* BlankRect is the entire data area & is used to erase the data  */
X    static Rect bounds = { 60,60, 335, 350 };
X    static Rect OctRect = { 225,12,242,80 };
X    static Rect HexRect = { 225,115, 242, 185 };
X    static Rect DecRect = { 225,200, 242, 268 };
X    static Rect AbRect  = { 250,85, 270, 205 };
X    static Rect BlankRect = { 3,12,220,280 };
X    
X/* various functions begin here - see 'main' for calling sequence  */
X    
X    
XaboutDA()                    /* creates an alert dialog message about  */
X                             /* the DA and gives an OK button to exit  */
X{
X  /* the alert resource and accompanying item list are stored in a   */
X  /* file called "ascii_chart.rsrc" which was created with ResEdit   */
X  /* ..since the OK button is the default (highlighted) choice, we   */
X  /* do not have to have a filterProc   (IM I-419)                   */
X  /* If you examine the DA file with ResEdit, you will see that the  */
X  /* resource ID for the ALRT is -16000, which translates into an    */
X  /* 'owned' resource ID of '0' (zero) for a DRVR (our program)      */
X  /* with an ID of '12'. This is the ID number that LightspeedC      */
X  /* assigns to a Desk Accesory that it creates.  When you install   */
X  /* a DA with the Font/DA mover, it checks to see that the ID# does */
X  /* not conflict with that of an existing DA. If it does, the F/DA  */
X  /* will change our DA's ID to an unused #, and all of the 'owned'  */
X  /* resource ID's will be shifted accordingly. Read IM I-108,109.   */
X     
X  Alert(rsrcID(rALRT),0L);   /* invoke the alert   (IM I-418) */
X  
X} 
X
X/* this routine from the LightspeedC demo DA by Michael Kahl...     */
X/* returns the correct resource ID number "no matter what driver #  */
X/* the Font/DA Mover has assigned us... "  (IM I-109)               */
X
XrsrcID(id)
X{
X     return(0xc000 + (~dce->dCtlRefNum << 5 ) + id);
X}
X
X  
X/* window update routine -  if it's a result of a radix change, scope */
X/* is 0 (update everything) - if it is a system update event, update  */
X/* only the area that needs it, by using BeginUpdate & EndUpdate      */
X/* (see calls to 'updateDisplay()' in 'main' and 'DAEvent'            */
X
XupdateDisplay(scope)   
Xint scope;
X{
X
XGrafPtr currentPort;
XPtr dataAddr;                /* a generic 'pointer' data type */
X
XGetPort(&currentPort);       /* save the current grafport  (IM I-447)  */
XSetPort(dce->dCtlWindow);    /* set the grafport to our window         */
X
X  if (scope)
X    BeginUpdate(dce->dCtlWindow);   /* set the visRgn to only the part */
X                                    /* that needs updating (IM I-292)  */
X                                    /* otherwise, redraw the whole window */
X                   
X    DrawControls(dce->dCtlWindow);  /* draw the controls in our window   */
X    EraseRect(&BlankRect);          /* blank out the old data (IM I-177) */
X    y = 10;
X    
X    if (curControl == OctPtr)     /* determine which control was pressed */
X       dataAddr = (Ptr) octdata;   /* & cast the address of the 2D array */
X    else if (curControl == DecPtr) /* into our generic data pointer      */
X       dataAddr = (Ptr) decdata;
X    else if (curControl == HexPtr)
X       dataAddr = (Ptr) hexdata;
X       
X    TextFont(4);   /* Monaco font for evenly spaced columns (IM I-219)  */
X    TextSize(9);   /* these are quickdraw functions                     */
X   
X    for (line  = 0; line  < 22; line++) { 
X    
X    /* we have 23 lines per 'page' - use quickdraw to output the data   */
X    /* the starting address for DrawText is (line# * 47) to get to the  */
X    /* proper position in the 2D array                                  */
X     
X         MoveTo(12,y);           
X         DrawText(dataAddr + (line * 47),0,46);    /* (IM I-172)        */
X          y = y +10;
X          }  
X
X    if (scope) EndUpdate(dce->dCtlWindow);          
X                                
XSetPort(currentPort);         /* restore the current grafport (IM I-447) */
X
X}    /* end of updateDisplay */ 
X
X   
X 
XopenDA()              /* open the desk accessory */
X{
X    
X    GrafPtr currentPort;
X    
X    if (DAisOpen) return;     /* if it is already open, just ignore */
X    GetPort(&currentPort);    /* save the current grafport */
X
X/* create our window, set the device control entry (dce) window field  */
X/* to our window, set the window's windowKind field to the reference # */
X/* for the driver  (IM I-445)                                          */
X    
X    dce->dCtlWindow = NewWindow(0,&bounds,"\pAscii Chart",0,16,-1,1,0);
X    ((WindowPeek) (dce->dCtlWindow))->windowKind = dce->dCtlRefNum;
X    
X 	SetPort(dce->dCtlWindow);    /* set the grafport to our window */
X 	ShowWindow(dce->dCtlWindow); /* display the window             */
X 	
X 	
X    /* create new controls for the various radixes and the about box */
X    /* set the octal radix control to be 'on'... (IM I-319)          */ 
X    OctPtr = NewControl(dce->dCtlWindow,&OctRect,"\poctal",1,1,0,1,2,0);
X 	HexPtr = NewControl(dce->dCtlWindow,&HexRect,"\phex",1,0,0,1,2,0);
X 	DecPtr = NewControl(dce->dCtlWindow,&DecRect,"\pdecimal",1,0,0,1,2,0);
X 	AbPtr  = NewControl(dce->dCtlWindow,&AbRect,"\pabout ascii
Xchart",1,1,0,0,0,0);
X  
X 	curControl = OctPtr;     /* set default for current control button */
X 	
X/* we do not need to explicitly call "updateDisplay" because the open  */
X/* routine will cause an update event to be sent to the Desk Manager   */
X     
X     DAisOpen = 1;                 /* set the DA 'on' (our own flag)   */
X     SetPort(currentPort);         /* restore original grafport        */
X     
Xreturn(0);
X   
X}        /* end of the openDA routine */
X
X
XDAevent(theEvent)
XEventRecord *theEvent;      /* argument is a pointer to an event record */
X{
X
XGrafPtr currentPort;
X
XGetPort(&currentPort);     /* save the system's current grafport   */
X
X/* at this point we know there has been an event in the DA window  */
X/* content region, so we must process the event */
X
XSetPort(dce->dCtlWindow);     /* set the port to our window        */
X   
Xswitch (theEvent->what) {     /* examine the 'what' field of event */
X                              /* (IM I-263,264)                    */
X     case activateEvt:	      /* the DA window has become active   */     
X            updateDisplay(1);
X            return(0); 
X            
X     case updateEvt:	      /* we need to update (result of drag, etc) */     
X            updateDisplay(1);
X            return(0); 
X            
X     case mouseDown:
X          /* convert the location to local coordinates  (IM I-193,323)   */
X         GlobalToLocal(&(theEvent->where));
X   
X         /* find where mouse was pressed - (the part code) (IM I-334)    */
X       
X         switch (FindControl(theEvent->where,dce->dCtlWindow,&whichControl)) {
X             
X           case (11):         /* a RADIO button has been hit - track it  */
X           
X               /* track control routine makes sure mouse is released in button
X*/
X               if (TrackControl(whichControl,theEvent->where,0)) {
X               
X                   if (whichControl != curControl) {      /* a new radix */
X                     SetCtlValue(curControl,0);
X                     curControl = whichControl; /* set new 'current' ctl */
X                     SetCtlValue(curControl,1);
X                     updateDisplay(0);            /* update whole window */
X                     }                 /* end new radix */
X               }                /* end if track control */
X               break;
X           case (10):      /* SIMPLE button (must be the about box) */
X           
X              /* create an alert dialog with an OK button to terminate */
X           
X              aboutDA();
X              break;
X                  
X           } /* end possible control mousedown */
X           
X         LocalToGlobal(&theEvent->where); /* put the coordinates back to global
X*/
X
X     } /* end of the event switch */
X               
X SetPort(currentPort);   /* restore the grafport */
X         
X}   /* end of DAevent */
X
X
X
X/* close DA function */
X
XcloseDA()
X{
X   GrafPtr currentPort;
X   
X   GetPort(&currentPort);         /* save the system's grafport */
X   DisposeWindow(dce->dCtlWindow);/* dispose our window */
X   dce->dCtlWindow = 0L;          /* set the driver's window ptr to null */
X                                  /* (IM I-446) */
X   SetPort(currentPort);          /* restore the system's grafport */
X   return(0);
X 
X}
X/* main driver routine - three parameters are passed to us through the */
X/* device manager.   1. the control parameter pointer                  */
X/*                   2. the pointer to the dce record                  */
X/*                   3. the  driver routine (open, control, or close)  */
X/*                   (IM II-201, I-445 )                               */
X
X     
Xmain (p,d,n)
XcntrlParam *p;
XDCtlPtr d;
Xint n;
X
X
X{
X
Xif (d->dCtlStorage == 0 ) {
X     if (n == 0) {            /* open but no data */
X          SysBeep(3);
X          CloseDriver(d->dCtlRefNum);
X          }
X          return(0);
X    }
X    
X    dce = d;
X
X/* find the appropriate driver routine */
X    
X    switch(n) {        /* 0 = open, 2 = control event, 4 = close */
X    
X       case 0:         /* open the DA */
X          openDA();
X          break;
X          
X       case 2:         /* action in the DA */
X          switch(p->csCode) {
X          
X               case accEvent:
X                  DAevent(((EventRecord *) * (long *) &p->csParam)); 
X                  
X /* casting the *address of* p->csParam as an pointer to a long, and the */
X /* long is cast as a pointer to a pointer to an Event Record (I think?) */
X /* (from ZoomIdle 1.1 by Paul DuBois)                                   */
X /* the pointer is passed as the parameter to DAevent                    */
X                  
X                  
X                 }  /* end of case 2 switch */
X                 break;
X             
X       case 4:       /* close box has been clicked */
X          closeDA();
X          break;
X          
X     }   /* end of the main switch */
X     
X   return(0);
X   
X
X}       /* end of main */
SHAR_EOF
exit