/* RULER - CLI version * * See Ruler.doc for operating instructions * * Revision History: * ----------------- * * Version 5.0 21-Apr-1991 ©1991 Dave Schreiber, Chad Netzer, and * Thad Floryan * Based upon code from: * * Version 4.0 29-Dec-1989 ©1989 Chad Netzer and Thad Floryan * * Based upon code, idea, and logic from: * * Version 1.0 7-Nov-1988 ©1988 Thad Floryan * * Revision history: * 21-April-1991 - (Ver. 5.00) (DKS): * 1 Window is sized to make room for > 8 point fonts in the * title bar and main window (for compatibility with AmigaOS * 2.x) * 2 Added the ability to put Ruler's window on any screen at * will. * 3 Added the ability to get the font scale from any window. * 4 Added menus for: * * About * * Quit * * Change Screen (#2) * * Change Font (#3) * These menus are layed out by the 2.x function * LayoutMenusA(). This function is called only if Ruler * is running under 2.0 or later (i.e. Ruler is 1.3 * compatible). * * 29-December-1989 - (Ver. 4.0) - Added an offset so that you can * just stick the window on the left edge of the workbench screen, * and it will automatically be lined up with the characters. * Fixed some more minor bugs and rearranged the code a bit. * Added ARP support for those who want it. (CFN) * * 09-March-1989 - (Ver. 3.1) - Fixed a visual bug so that scale can * no longer be less than eight. (CFN) * * 06-Dec-1988 - (Ver. 3.0) - Added support for measuring fonts of * varying widths (selectable scale). (CFN) * * 22-Nov-1988 - (Ver. 2.2) - More adjustments to code, No major * changes. Program size is slightly smaller. (CFN) * * 14-Nov-1988 - (Ver. 2.1) - Fixed a few minor (harmless) bugs. The * right edge of the ruler is now always redrawn after resizing. * I got rid of that GOTO statement (which in 'C', is considered a * bug. :-) Version 2.1 now lets you open a ruler to be as low as * 12 characters wide, which 2.0 only advertised. (CFN) * * 13-Nov-1988 - (Ver. 2.0) - I added minor enhancements, most * noteably, the ability to resize the window, and support for * overscanned screens. (CFN) * * * Feel welcome to use this program for any non-commercial purposes or * for your personal learning. Commercial users are requested to contact * Thad at either: * * UUCP: thad@cup.portal.com (OR) ..!sun!portal!cup.portal.com!thad * BBS: BBS-JC, 415/961-7250 (300/1200/2400), "Thad Floryan" | "SYSOP" * * Chad at: * * UUCP: chad@ucscb.ucsc.edu (during school term) * UUCP: chad@cup.portal.com (holidays, summer, etc.) * BBS: BBS-JC, 415/961-7250 (300/1200/2400), "Chad Netzer" * * or Dave at: * * UUCP: davids@ucscb.ucsc.edu * BBS: BBS-JC, "Dave Schreiber" * * * Building instructions (SAS/C V5.10): * * lc -Lcd -v Ruler * */ #include #include #include #include #include #define AMIGA_2.0 1 /*Delete if include files for 2.0 or later are*/ /*not available*/ #ifdef AMIGA_2.0 #include struct TagItem menuTag[] = { {TAG_DONE,NULL} }; #endif #include "GUI.h" /*Some constants*/ #define HEIGHT titleBarHeight+textHeight-2 #define DEF_HEIGHT 12L+HEIGHT #define RULER_MARK_Y 11L+HEIGHT #define OFFSET_START_Y 2L+titleBarHeight #define BIG_TIC_Y 5L+HEIGHT #define SMALL_TIC_Y 9L+HEIGHT #define TEXT_Y 3L+HEIGHT #define DRAW_AREA_Y 3L+titleBarHeight #define DRAW_AREA_HEIGHT 24L+textHeight #define NEW(typ) AllocMem((ULONG)sizeof(typ), MEMF_CLEAR) #define FREE(p,typ) FreeMem(p,(ULONG)sizeof(typ)) #define ever (;;) /* used for infinite loops */ #define FATAL 20 /* exit code */ #define WARN 10 /* exit code */ #define NORMAL 0 /* exit code */ #define LEFT_OFFSET 3L /* "dead space" on left side of ruler margin */ extern void *OpenLibrary(); extern void *OpenWindow(); extern void *GetMsg(); extern void *AllocMem(); extern void ReplyMsg(); /* Prototypes for functions defined in ruler5.c */ void __regargs release_resources(void); void __regargs error_exit(char *message); int __regargs handleMenu(USHORT NUM); void __regargs printAboutWindow(void); void __regargs changeFSize(void); void __regargs changeScreen(void); void __regargs readArg(int argc, char **argv, long *fsize, long *w); UWORD titleBarHeight,textHeight,textWidth,screenWidth; struct NewWindow window_def = { 0, 0, /* Initial LeftEdge, TopEdge */ 241, 17, /* Default pixel-width, pixel-height */ 0, 1, /* DetailPen, BlockPen */ CLOSEWINDOW | /* IDCMP flags */ MENUPICK | NEWSIZE, WINDOWDRAG | /* window flags */ WINDOWDEPTH | WINDOWCLOSE | WINDOWSIZING | ACTIVATE | SMART_REFRESH | NOCAREREFRESH, NULL, /* Gadget list */ NULL, /* checkmark stuff */ NULL, /* window title (to be filled in later) */ NULL, /* custom screen pointer */ NULL, /* bitmap pointer */ 97 + LEFT_OFFSET, 0, /* Minwidth, no MinHeight */ -1, 0, /* no MaxWidth, MaxHeight */ CUSTOMSCREEN /* screen type */ }; struct Window *window; struct RastPort *rp; struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct Library *GadToolsBase; struct Screen *screen; struct IntuiMessage *sys_message; ULONG class; USHORT code; int resource_state; long fsize; /* The font size of ruler scale */ APTR visualInfo; char *version = "Text Ruler V5.00 (CLI) 21-Apr-91 ©1991 "; /**********************************************************************/ main (argc, argv) int argc; char *argv[]; { long fivec; /* pixel size of five chars */ long w; /* character width of ruler */ long w_lim; /* pixel width (w * fsize) */ long x; /* present window x coordinate */ long y; /* present window y coordinate */ char buf[5]; int redoWindow; /*Boolean flag*/ resource_state = 0; /* * Open Intuition and Graphics so we can get screen size and * default font information. */ if((IntuitionBase = OpenLibrary ("intuition.library", NULL))==NULL) error_exit("?Cannot open intuition.library\n"); ++resource_state; if((GfxBase = OpenLibrary ("graphics.library", NULL))==NULL) error_exit("?Cannot open graphics.library\n"); ++resource_state; GadToolsBase = OpenLibrary("gadtools.library",NULL); if(GadToolsBase) window_def.IDCMPFlags|=(ACTIVEWINDOW|INACTIVEWINDOW); /* * Get WorkBench screen information */ screen=window_def.Screen=IntuitionBase->ActiveScreen; w = 30L; /* default ruler is 30 chars for a filename */ /*Get default scale*/ fsize=textWidth=GfxBase->DefaultFont->tf_XSize; /* * Parse command line to obtain requested parameters. */ readArg(argc,argv,&fsize,&w); w_lim = w * fsize; /* * Main loop */ for ever { /* Get width of screen */ screenWidth=screen->Width; /* Determine spacing from current font information */ titleBarHeight = screen->Font->ta_YSize; textHeight = GfxBase->DefaultFont->tf_YSize; /* * Now calculate window sizing and placement parameters and setup title. */ window_def.Width = w_lim + LEFT_OFFSET + 1; window_def.Height = DEF_HEIGHT; window_def.Title = (UBYTE *)version; /* * Shorten the window if it would be wider than the screen */ if (window_def.Width > screenWidth ) { window_def.Width = screenWidth; w_lim = (window_def.Width) - 1 - LEFT_OFFSET; } /* * Open the ruler display window. */ window = OpenWindow (&window_def); if (window == NULL) { error_exit("?Cannot open window\n"); } ++resource_state; /* * Set screen and window titles */ SetWindowTitles(window,version,"Text Ruler V5.00"); /* * If running under 2.0 or later, adjust menu spacing information * to compensate for a non-8 point font size. */ if(GadToolsBase != NULL) { visualInfo = (APTR)GetVisualInfoA(screen,menuTag); LayoutMenusA(&Menu1,visualInfo,menuTag); FreeVisualInfo(visualInfo); } /* * Install menus */ SetMenuStrip(window,&Menu1); /* * Get pointer to raster port. */ rp = window -> RPort; /* * Inner loop (loop until the window needs to be closed and another * opened). */ redoWindow=FALSE; while(!redoWindow) { redoWindow=FALSE; fivec = 5L * fsize; /* * Use RectFill to blank the window area and set pen for drawing. */ SetAPen(rp, NULL); RectFill(rp, LEFT_OFFSET+1, DRAW_AREA_Y, w_lim + LEFT_OFFSET, DRAW_AREA_Y+DRAW_AREA_HEIGHT); /* * Now set pen to draw. */ SetAPen(rp, 1L); /* * When I use the ruler, I like to jam it up against the left hand side of * my workbench screen, so that it to measure something on the CLI. * However, the CLI is offset by a small amount, so I compensate by * starting the "virtual" area of the ruler a little to the right... * * Fill in the offset area that is unused. */ RectFill(rp, NULL, OFFSET_START_Y, LEFT_OFFSET, DRAW_AREA_Y+DRAW_AREA_HEIGHT+1); /* * Draw ruler and text */ for (x = NULL; x < (w_lim + fsize); x += fsize) { /*big tic every 5 chars*/ if ((x % fivec) == NULL) y = BIG_TIC_Y; else y = SMALL_TIC_Y; /* small tic every char */ Move (rp, x + LEFT_OFFSET, y); Draw (rp, x + LEFT_OFFSET, RULER_MARK_Y); /* * Label ruler. * The test for position `fivec' (in the Move()) is for centering ``5'' * differently than the centering for two-digit numbers. */ if ((x > NULL) && (x < w_lim) && ((x % fivec) == NULL)) { stci_d(buf,x/fsize); Move (rp, (x == fivec) ? (x - textWidth + (textWidth/2) + LEFT_OFFSET) : (x - textWidth + LEFT_OFFSET), TEXT_Y); Text (rp, buf, (long) strlen (buf)); } } SetAPen(rp,1); Move(rp,w_lim+LEFT_OFFSET,titleBarHeight); Draw(rp,w_lim+LEFT_OFFSET,DEF_HEIGHT); /* * Wait for gadget activation. No busy-/spin-/wait-loops here! */ Wait (1L << window -> UserPort -> mp_SigBit); /* * Retrieve LAST message in Message Port */ sys_message = GetMsg(window -> UserPort); class = sys_message -> Class; code = sys_message -> Code; ReplyMsg(sys_message); /* * Dump uneeded messages (respond only to the last on LIFO queue). */ while (sys_message = GetMsg(window -> UserPort)) { ReplyMsg(sys_message); } /*Handle various IDCMP events*/ switch(class) { case CLOSEWINDOW: release_resources(); exit (NORMAL); case NEWSIZE: w_lim = (window -> Width) - 1 - LEFT_OFFSET; break; case INACTIVEWINDOW: SetWindowTitles(window,version,"Text Ruler V5.00"); break; case MENUPICK: redoWindow=handleMenu(code); } } } } /********************************************************************** * * cleanup routine * * The ``switch'' on resource_state is to assure we don't attempt to * free something we don't have. Items are released in the reverse * order they were obtained (by "falling thru" the cases). */ void __regargs release_resources() { switch (resource_state) { case 3: ClearMenuStrip(window); CloseWindow (window); case 2: CloseLibrary(GfxBase); case 1: CloseLibrary(IntuitionBase); } if(GadToolsBase != NULL) CloseLibrary(GadToolsBase); } /********************************************************************** * * error handler */ void __regargs error_exit(message) char *message; { if (message == NULL) { puts("Internal failure, exiting gracefully...\n"); } else { puts(message); } release_resources(); exit (FATAL); } /* * Decode menu choice */ int __regargs handleMenu(USHORT NUM) { struct MenuItem *item; USHORT menuNum,itemNum; while(NUM != MENUNULL) { menuNum=MENUNUM(NUM); itemNum=ITEMNUM(NUM); item=(struct MenuItem *)ItemAddress(&Menu1,NUM); if(menuNum==0) if(itemNum==0) printAboutWindow(); /*About*/ else { release_resources(); /*Quit*/ exit(NORMAL); } else if(itemNum==0) { changeFSize(); /*Change Scale*/ return(FALSE); } else { changeScreen(); /*Change Screen*/ return(TRUE); } NUM=item->NextSelect; } return(0); } /* * Display the About window */ void __regargs printAboutWindow() { struct Window *aboutWdw; if((NewAboutWindow.LeftEdge=(screenWidth-NewAboutWindow.Width)/2) > 200) NewAboutWindow.LeftEdge = 200; /* * Determine About window position */ NewAboutWindow.TopEdge=(screen->Height-NewAboutWindow.Height)/5; NewAboutWindow.Height=titleBarHeight-15+ABOUT_WDW_HEIGHT; /* * Get the screen the about window will appear on (same as the * screen the main window is on). */ NewAboutWindow.Screen = (struct Screen *) screen; /* * Open window */ aboutWdw=(struct Window *)OpenWindow(&NewAboutWindow); if(aboutWdw==NULL) return; /* * Print window text */ PrintIText(aboutWdw->RPort,&IText11,0,titleBarHeight-15); /* * Wait for input close gadget to be pressed, then close window and * return. */ Wait(1<UserPort->mp_SigBit); CloseWindow(aboutWdw); return; } /* * Change scale */ void __regargs changeFSize() { ULONG IDCMPFlags; IDCMPFlags=window_def.IDCMPFlags; ModifyIDCMP(window,INACTIVEWINDOW); for ever { /*Wait for IDCMP event*/ Wait (1L << window -> UserPort -> mp_SigBit); sys_message = GetMsg(window -> UserPort); class = sys_message -> Class; ReplyMsg(sys_message); /* * If another window was clicked, get the horizontal font size of * the current font in that window */ if(class==INACTIVEWINDOW) { if((IntuitionBase->ActiveWindow->RPort->Font->tf_Flags & FPF_PROPORTIONAL) == 0) fsize=IntuitionBase->ActiveWindow->RPort->Font->tf_XSize; else { /*If the window is using a proportional font, print an error*/ SetWindowTitles(window,version,"Can't change scale: window font is proportional."); DisplayBeep(window->WScreen); } ModifyIDCMP(window,IDCMPFlags); return; } } } /* * Change the screen that the window is displayed on. */ void __regargs changeScreen() { for ever { /* * Wait for user to click on another window (hopefully in another * screen). */ ModifyIDCMP(window,INACTIVEWINDOW); Wait (1L << window -> UserPort -> mp_SigBit); sys_message = GetMsg(window -> UserPort); class = sys_message -> Class; ReplyMsg(sys_message); if(class==INACTIVEWINDOW) { /*Get active screen*/ window_def.Screen=screen=IntuitionBase->ActiveScreen; /*Clear menu strip and close window*/ ClearMenuStrip(window); CloseWindow(window); resource_state--; return; } } } /* * Read command line arguments, print help if requested */ void __regargs readArg(int argc, char *argv[], long *fsize, long *w) { int argCounter; BYTE gotSize = FALSE; if(argc > 1 && argv[1][0]=='?') { /* * Print help and exit */ puts(""); puts("Text Ruler V5.00 ©1991 by Thad Floryan, Chad Netzer, and Dave Schreiber."); puts(""); puts("Usage: Ruler5 [-z][-s]"); puts(" - Number of 'ticks'"); puts(" - Width between ruler 'ticks', in pixels."); puts("or: Ruler5 [ []]"); release_resources(); exit(0); } /* * Otherwise, examine each argument */ for(argCounter=1;argCounter < argc ; argCounter++) { if(isdigit(argv[argCounter][0])) /*Check if just a digit*/ if(!gotSize) { gotSize=TRUE; *w=atol(argv[argCounter]); } else *fsize=atol(argv[argCounter]); else { if(argv[argCounter][0] != '-') { puts("I don't understand this argument:"); puts(argv[argCounter]); error_exit(""); } switch(argv[argCounter][1]) { /*Each case checks for to see if there's a space between*/ /*the switch and the argument*/ case 's': /*Scale*/ case 'S': if(argv[argCounter][2]!=NULL) *fsize=atol(&argv[argCounter][2]); else *fsize=atol(&argv[++argCounter][0]); if(*fsize < 5) error_exit("The scale must be at least 5"); if(*fsize > 50) error_exit("The scale must be at most 50"); break; case 'z': /*Size*/ case 'Z': if(argv[argCounter][2]!=NULL) *w=atol(&argv[argCounter][2]); else *w=atol(&argv[++argCounter][0]); if(*w < 12) error_exit("The size must be at least 12"); break; } } } return; }