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(¤tPort); /* 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(¤tPort); /* 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(¤tPort); /* 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(¤tPort); /* 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