home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
244.lha
/
FoodConverter
/
FoodConv.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-04-29
|
10KB
|
543 lines
/*
* 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);
}