home *** CD-ROM | disk | FTP | other *** search
- /*
- * FoodConv.c
- *
- * FoodConv - liquid measure converter.
- *
- * 14-Apr-89
- * Jeff Kunzelman & Joanne Lee
- *
- * Written because we were tired of converting 6 person recipies
- * to 2 person recipies
- *
- * Compiled with Lattice C 5.0 and blink 5.0.
- *
- * lc -Lm -cf FoodCalc
- * (edit result FoodCalc.lnk file to include 'DEFINE __main=__tinymain'
- * this will remove the extra window when running from the workbench.)
- * Then relink with blink.
- *
- *
- *
- * Converts Cup, ounce, teaspoon, tablespoon liquid units to
- * cups, ounces, teaspoon and tablespoon after multipling by
- * a conversion factor.
- *
- * All units are specified in fractional form (not decimal) which
- * makes things very handy since that's the way recipies are written.
- *
- * To operate enter the conversion factor (eg. 3/4 then CNV). Then
- * enter the measure to convert (eg. 1-3/4 TBL) the results in all
- * units will be displayed next to the associated units buttons.
- * If the measure is to small, the field will be blanked.
- *
- * Operates completely from either keyboard or mouse.
- */
-
- #include <hardware/intbits.h>
- #include <intuition/intuition.h>
-
- #include <proto/all.h>
-
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
-
- #include "general.h"
-
- #define NUM_TYPE (0)
- #define CONV_TYPE (1 << 8)
- #define CNTRL_TYPE (2 << 8)
-
- #define TYPE_MASK 0xff00
- #define VAL_MASK 0x00ff
-
- enum {
- KEY0_ID = NUM_TYPE, KEY1_ID, KEY2_ID, KEY3_ID,
- KEY4_ID, KEY5_ID, KEY6_ID, KEY7_ID,
- KEY8_ID, KEY9_ID, KEYSLASH_ID, KEYSPACE_ID
- };
-
- enum {
- KEYCLR_ID = CNTRL_TYPE, KEYCNV_ID
- };
-
- enum {
- KEYOZ_ID = CONV_TYPE, KEYCUP_ID, KEYTSP_ID, KEYTBL_ID
- };
-
- /*
- * Digit modes
- */
- enum {
- IDLE, GET_DIGIT
- };
-
- #include "keylayout.h"
-
- #define MAX_DISPLAY 128
- #define MAX_DIGITS 10
- #define DISPLAY_W 16
-
- #define CHAR_WIDTH 8
-
- #define DISPLAY_X 34
- #define DISPLAY_Y 34
- #define DISPLAY_UNIT_X (DISPLAY_X + 10 * CHAR_WIDTH)
-
- #define RESULTS_X 200
- #define RESULTS_Y 68
- #define RESULTS_Y_H 11
-
- #define FACTOR_X 200
- #define FACTOR_Y DISPLAY_Y
-
- #define OZ_FACTOR 1.0
- #define CUP_FACTOR 8.0
- #define TBL_FACTOR (OZ_FACTOR / 2.0)
- #define TSP_FACTOR (TBL_FACTOR / 3.0)
-
- #define BG_PEN 1
- #define NORM_PEN 2
-
- #define ERROR 1
-
- #define DLIST_END -1
-
- extern struct IntuitionBase *IntuitionBase;
- extern struct GfxBase *GfxBase;
-
- struct Window *w;
- struct RastPort *rp;
-
- double cFactor = 1;
- double value;
-
- int mode = IDLE;
-
- char mainDisplay[MAX_DISPLAY + 1];
-
- short cupDList[] = { 2, 3, 4, 8, DLIST_END};
- short ozDList[] = { 2, 3, 4, 8, DLIST_END};
- short tspDList[] = { 2, 4, 8, 16, DLIST_END};
- short tblDList[] = { 2, 3, 4, DLIST_END};
- short facDList[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 16, DLIST_END};
-
-
- int
- exitTrap(int exitValue)
- {
- if (!IS_NIL(IntuitionBase))
- CloseLibrary(IntuitionBase);
-
- if (!IS_NIL(GfxBase))
- CloseLibrary(GfxBase);
-
- return exitValue;
- }
-
- void
- beep(int error)
- {
- DisplayBeep(w->WScreen);
- }
-
- void
- writeDisplay(char *text)
- {
- char buf[MAX_DISPLAY + 1];
- int length = strlen(text);
-
- strcpy(buf, text);
- for (length = DISPLAY_W - length; length; length--)
- strcat(buf, " ");
- Move(rp, DISPLAY_X, DISPLAY_Y);
- Text(rp, buf, strlen(buf));
- }
-
- void
- clearDisplay(void)
- {
- mainDisplay[0] = EOS;
- writeDisplay(mainDisplay);
- }
-
- void
- appendDisplayChar(char newChar)
- {
- int length;
-
- length = strlen(mainDisplay);
- mainDisplay[length] = newChar;
- mainDisplay[length + 1] = EOS;
- writeDisplay(mainDisplay);
- }
-
-
- void
- addDigit(ushort gadID)
- {
- if (mode == IDLE)
- clearDisplay();
-
- mode = GET_DIGIT;
-
- switch (gadID) {
- case KEYSPACE_ID:
- appendDisplayChar('-');
- break;
-
- case KEYSLASH_ID:
- appendDisplayChar('/');
- break;
-
- default:
- gadID &= VAL_MASK;
- if (strlen(mainDisplay) >= MAX_DIGITS) {
- beep(ERROR);
- break;
- }
- appendDisplayChar((char)(gadID + '0'));
- }
- }
-
- void
- writeText(int x, int y, char *string)
- {
- Move(rp, x, y);
- Text(rp, string, strlen(string));
- }
-
- void
- clearResults(void)
- {
- char *blanks = " ";
-
- writeText(RESULTS_X, RESULTS_Y, blanks);
- writeText(RESULTS_X, RESULTS_Y + RESULTS_Y_H, blanks);
- writeText(RESULTS_X, RESULTS_Y + RESULTS_Y_H * 2, blanks);
- writeText(RESULTS_X, RESULTS_Y + RESULTS_Y_H * 3, blanks);
- }
-
- int
- translate(char *buf, int *whole, int *numerator, int *denominator)
- {
- int retVal = SUCCESS;
-
- if (sscanf(buf, "%d-%d/%d", whole, numerator, denominator) == 3) {
- } else if (sscanf(buf, "%d/%d", numerator, denominator) == 2) {
- *whole = 0;
- } else if (sscanf(buf, "%d", whole) == 1) {
- *numerator = 0;
- *denominator = 1;
- } else {
- beep(ERROR);
- retVal = FAIL;
- }
-
- return retVal;
- }
-
- void
- writeFrac(int x, int y, double value, short *denList)
- {
- char buf[MAX_DISPLAY + 1];
- short *curDen;
- short curNom;
- double frac = value - (long)value;
- double bestNom = 0;
- double bestDen = 1;
- double bestDelta = frac;
- int i;
-
- /*
- * For every possible nominator/denominator combination
- * search for the closest to the orginal fraction.
- */
- for (curDen = denList; *curDen != DLIST_END; curDen++) {
- for (curNom = 1; curNom < *curDen; curNom++) {
- if (bestDelta > abs(frac - ((1.0 * curNom) / *curDen))) {
- bestNom = curNom;
- bestDen = *curDen;
- bestDelta = abs(frac - (bestNom / bestDen));
- }
- }
- }
-
- /*
- * If the closest fraction is worse then rounding up to the
- * next whole number, round up...
- */
- if (bestDelta > 1 - frac) {
- bestNom = 0;
- value += 1;
- }
-
- /*
- * Format output fraction.
- */
- if ((int)(value - frac) == 0 &&
- (bestNom / bestDen > frac || (bestNom == 0 && frac != 0)))
- /*
- * The output is a fraction only, and is smaller than the
- * minimum fraction, supress the output.
- */
- buf[0] = EOS;
- else if ((int)bestNom == 0) {
- /*
- * The fractional part is 0, just print whole number.
- */
- sprintf(buf, "%d", (int)(value - frac));
- } else if ((int)(value - frac) == 0) {
- /*
- * The whole number part is 0, just print the fraction.
- */
- sprintf(buf, "%d/%d", (int)bestNom, (int)bestDen);
- } else {
- /*
- * Print the full whole # and fraction.
- */
- sprintf(buf, "%d-%d/%d",
- (int)(value - frac), (int)bestNom, (int)bestDen);
- }
-
- /*
- * Pad output string with blanks to clear old info.
- */
- if (strlen(buf) > 8)
- /*
- * The output is to large to fit on the display
- */
- strcpy(buf, "* Lots * ");
- else {
- /*
- * Pad output string with trailing blanks.
- */
- for (i = strlen(buf); i < 8; i++)
- buf[i] = ' ';
- buf[i] = EOS;
- }
-
- Move(rp, x, y);
- Text(rp, buf, strlen(buf));
- }
-
-
- void
- writeFactor(void)
- {
- writeFrac(FACTOR_X, FACTOR_Y, cFactor, facDList);
- }
-
- void
- doControl(ushort gadID)
- {
- int whole;
- int numerator;
- int denominator;
-
- switch (gadID) {
- case KEYCLR_ID:
- mode = IDLE;
- clearDisplay();
- clearResults();
- break;
-
- case KEYCNV_ID:
- if (translate(mainDisplay, &whole,
- &numerator, &denominator) != SUCCESS) {
- beep(ERROR);
- return;
- } else {
- mode = IDLE;
- cFactor = whole + (1.0 * numerator) / denominator;
- writeFactor();
- clearResults();
- clearDisplay();
- }
- break;
- }
- }
-
- void
- writeResults(double value)
- {
- value *= cFactor;
-
- writeFrac(RESULTS_X, RESULTS_Y, value / OZ_FACTOR, ozDList);
- writeFrac(RESULTS_X, RESULTS_Y+RESULTS_Y_H, value/TSP_FACTOR, tspDList);
- writeFrac(RESULTS_X, RESULTS_Y+RESULTS_Y_H*2, value/TBL_FACTOR,tblDList);
- writeFrac(RESULTS_X, RESULTS_Y+RESULTS_Y_H*3, value/CUP_FACTOR,cupDList);
- }
-
- void
- doConvert(ushort gadID)
- {
- double factor;
- char *unit;
- int whole;
- int numerator;
- int denominator;
-
- if (translate(mainDisplay, &whole, &numerator, &denominator) != SUCCESS) {
- beep(ERROR);
- clearResults();
- return;
- }
-
- switch (gadID) {
- case KEYOZ_ID:
- factor = OZ_FACTOR;
- unit = "Oz ";
- break;
-
- case KEYCUP_ID:
- factor = CUP_FACTOR;
- unit = "Cups";
- break;
-
- case KEYTSP_ID:
- factor = TSP_FACTOR;
- unit = "Tsps";
- break;
-
- case KEYTBL_ID:
- factor = TBL_FACTOR;
- unit = "Tbls";
- break;
- }
- value = factor * (whole + (1.0 * numerator) / denominator);
- mode = IDLE;
- Move(rp, DISPLAY_UNIT_X, DISPLAY_Y);
- Text(rp, unit, strlen(unit));
- writeResults(value);
- }
-
- void
- doKey(short key)
- {
- if (key >= '0' && key <= '9')
- addDigit((ushort)(NUM_TYPE + (key - '0')));
- else switch (key) {
- case ' ':
- case '-':
- addDigit(KEYSPACE_ID);
- break;
-
- case '/':
- addDigit(KEYSLASH_ID);
- break;
-
- case 'o':
- case 'O':
- doConvert(KEYOZ_ID);
- break;
-
- case 't':
- case 'T':
- doConvert(KEYTSP_ID);
- break;
-
- case 'b':
- case 'B':
- doConvert(KEYTBL_ID);
- break;
-
- case 'c':
- case 'C':
- doConvert(KEYCUP_ID);
- break;
-
- case 'l':
- case 'L':
- doControl(KEYCLR_ID);
- break;
-
- case 'n':
- case 'N':
- doControl(KEYCNV_ID);
- break;
-
- default:
- beep(ERROR);
- }
- }
-
- void
- main(int argc, char **argv)
- {
- AR0 struct IntuiMessage *idcmpMsg;
- bool pleaseQuit = FALSE;
- ushort gadID;
-
- /*
- * Setup exit() cleanup function.
- */
- if (!onexit(exitTrap))
- exit(1);
-
- /*
- * Open needed libraries.
- */
- IntuitionBase = OpenLibrary("intuition.library", 0);
- if (IS_NIL(IntuitionBase))
- exit(2);
-
- GfxBase = OpenLibrary("graphics.library", 0);
- if (IS_NIL(GfxBase))
- exit(3);
-
- /*
- * Setup calculator window.
- */
- w = OpenWindow(&NewWindowStructure1);
- if (IS_NIL(w))
- exit(4);
- rp = w->RPort;
- SetAPen(rp, NORM_PEN);
- SetBPen(rp, BG_PEN);
- SetWindowTitles(w, -1, "Jo & Jeffs' Liquid Measure Converter");
-
- /*
- * Initialize starting state and display.
- */
- doControl(KEYCLR_ID);
- writeFactor();
-
- /*
- * Read IDCMP input and process requests.
- */
- do {
- /*
- * Read input from IDCMP
- */
- WaitPort(w->UserPort);
-
- while (idcmpMsg = (struct Intuimessage *)GetMsg(w->UserPort)) {
- switch (idcmpMsg->Class) {
- case CLOSEWINDOW:
- pleaseQuit = TRUE;
- break;
-
- case GADGETUP:
- gadID = ((struct Gadget *)(idcmpMsg->IAddress))->GadgetID;
- if ((gadID & TYPE_MASK) == NUM_TYPE)
- addDigit(gadID);
- else if ((gadID & TYPE_MASK) == CNTRL_TYPE)
- doControl(gadID);
- else if ((gadID & TYPE_MASK) == CONV_TYPE)
- doConvert(gadID);
- break;
-
- case VANILLAKEY:
- doKey(idcmpMsg->Code);
- break;
- }
- ReplyMsg((struct Message *)idcmpMsg);
- }
- } while (!pleaseQuit);
-
- CloseWindow(w);
-
- exit(0);
- }
-