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

  1. /*
  2.  *  FoodConv.c 
  3.  *
  4.  *  FoodConv - liquid measure converter.
  5.  *
  6.  *  14-Apr-89
  7.  *  Jeff Kunzelman & Joanne Lee
  8.  *
  9.  *  Written because we were tired of converting 6 person recipies 
  10.  *  to 2 person recipies
  11.  *
  12.  *  Compiled with Lattice C 5.0 and blink 5.0.
  13.  *
  14.  *  lc -Lm -cf FoodCalc
  15.  *  (edit result FoodCalc.lnk file to include 'DEFINE __main=__tinymain'
  16.  *   this will remove the extra window when running from the workbench.)
  17.  *  Then relink with blink.
  18.  *
  19.  *
  20.  *  
  21.  *  Converts Cup, ounce, teaspoon, tablespoon liquid units to 
  22.  *  cups, ounces, teaspoon and tablespoon after multipling by
  23.  *  a conversion factor.
  24.  *
  25.  *  All units are specified in fractional form (not decimal) which
  26.  *  makes things very handy since that's the way recipies are written.
  27.  *
  28.  *  To operate enter the conversion factor (eg. 3/4 then CNV).  Then
  29.  *  enter the measure to convert (eg. 1-3/4 TBL) the results in all
  30.  *  units will be displayed next to the associated units buttons.
  31.  *  If the measure is to small, the field will be blanked.
  32.  *
  33.  *  Operates completely from either keyboard or mouse.  
  34.  */
  35.  
  36. #include <hardware/intbits.h>
  37. #include <intuition/intuition.h>
  38.  
  39. #include <proto/all.h>
  40.  
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <stdio.h>
  44.  
  45. #include "general.h"
  46.  
  47. #define    NUM_TYPE    (0)
  48. #define CONV_TYPE    (1 << 8)
  49. #define CNTRL_TYPE    (2 << 8)
  50.  
  51. #define TYPE_MASK    0xff00
  52. #define VAL_MASK    0x00ff
  53.  
  54. enum {
  55.     KEY0_ID = NUM_TYPE, KEY1_ID, KEY2_ID, KEY3_ID,
  56.     KEY4_ID, KEY5_ID, KEY6_ID, KEY7_ID,
  57.     KEY8_ID, KEY9_ID, KEYSLASH_ID, KEYSPACE_ID
  58. };
  59.  
  60. enum {
  61.     KEYCLR_ID = CNTRL_TYPE, KEYCNV_ID
  62. };
  63.  
  64. enum {
  65.     KEYOZ_ID = CONV_TYPE, KEYCUP_ID, KEYTSP_ID, KEYTBL_ID
  66. };
  67.  
  68. /* 
  69.  *  Digit modes
  70.  */
  71. enum {
  72.     IDLE, GET_DIGIT
  73. };
  74.  
  75. #include "keylayout.h"
  76.  
  77. #define MAX_DISPLAY    128
  78. #define MAX_DIGITS  10
  79. #define DISPLAY_W    16
  80.  
  81. #define CHAR_WIDTH        8    
  82.  
  83. #define DISPLAY_X        34
  84. #define DISPLAY_Y        34
  85. #define DISPLAY_UNIT_X    (DISPLAY_X + 10 * CHAR_WIDTH)
  86.  
  87. #define RESULTS_X        200
  88. #define RESULTS_Y        68
  89. #define RESULTS_Y_H        11
  90.  
  91. #define FACTOR_X        200
  92. #define FACTOR_Y        DISPLAY_Y
  93.  
  94. #define OZ_FACTOR        1.0
  95. #define    CUP_FACTOR        8.0
  96. #define TBL_FACTOR        (OZ_FACTOR / 2.0)
  97. #define TSP_FACTOR        (TBL_FACTOR / 3.0)
  98.  
  99. #define BG_PEN        1
  100. #define NORM_PEN    2
  101.  
  102. #define ERROR        1
  103.  
  104. #define    DLIST_END    -1
  105.  
  106. extern struct IntuitionBase *IntuitionBase;
  107. extern struct GfxBase         *GfxBase;
  108.  
  109. struct Window   *w;
  110. struct RastPort *rp;
  111.  
  112. double            cFactor = 1;
  113. double            value;
  114.  
  115. int                mode = IDLE;
  116.  
  117. char            mainDisplay[MAX_DISPLAY + 1];
  118.  
  119. short     cupDList[]     = { 2, 3, 4, 8, DLIST_END};
  120. short    ozDList[]    = { 2, 3, 4, 8, DLIST_END};
  121. short    tspDList[]    = { 2, 4, 8, 16, DLIST_END};
  122. short    tblDList[]    = { 2, 3, 4, DLIST_END};
  123. short    facDList[]    = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 16, DLIST_END};
  124.  
  125.  
  126. int
  127. exitTrap(int exitValue)
  128. {
  129.     if (!IS_NIL(IntuitionBase))
  130.         CloseLibrary(IntuitionBase);
  131.  
  132.     if (!IS_NIL(GfxBase))
  133.         CloseLibrary(GfxBase);
  134.  
  135.     return exitValue;
  136. }
  137.  
  138. void
  139. beep(int error)
  140. {
  141.     DisplayBeep(w->WScreen);
  142. }
  143.  
  144. void
  145. writeDisplay(char *text)
  146. {
  147.     char    buf[MAX_DISPLAY + 1];
  148.     int        length = strlen(text);
  149.  
  150.     strcpy(buf, text);
  151.     for (length = DISPLAY_W - length; length; length--)
  152.         strcat(buf, " ");
  153.     Move(rp, DISPLAY_X, DISPLAY_Y);
  154.     Text(rp, buf, strlen(buf));
  155. }
  156.  
  157. void
  158. clearDisplay(void)
  159. {
  160.     mainDisplay[0] = EOS;
  161.     writeDisplay(mainDisplay);
  162. }
  163.  
  164. void
  165. appendDisplayChar(char newChar)
  166. {
  167.     int        length;
  168.  
  169.     length = strlen(mainDisplay);
  170.     mainDisplay[length] = newChar;
  171.     mainDisplay[length + 1] = EOS;
  172.     writeDisplay(mainDisplay);
  173. }
  174.  
  175.  
  176. void
  177. addDigit(ushort gadID)
  178. {
  179.     if (mode == IDLE)
  180.         clearDisplay();
  181.  
  182.     mode = GET_DIGIT;
  183.  
  184.     switch (gadID) {
  185.         case KEYSPACE_ID:
  186.             appendDisplayChar('-');
  187.             break;
  188.  
  189.         case KEYSLASH_ID:
  190.             appendDisplayChar('/');
  191.             break;
  192.  
  193.         default:
  194.             gadID &= VAL_MASK;
  195.             if (strlen(mainDisplay) >= MAX_DIGITS) {
  196.                 beep(ERROR);
  197.                 break;
  198.             }
  199.             appendDisplayChar((char)(gadID + '0'));
  200.     }
  201. }
  202.  
  203. void
  204. writeText(int x, int y, char *string)
  205. {
  206.     Move(rp, x, y);
  207.     Text(rp, string, strlen(string));
  208. }
  209.  
  210. void 
  211. clearResults(void)
  212. {
  213.     char    *blanks = "        ";
  214.  
  215.     writeText(RESULTS_X, RESULTS_Y, blanks); 
  216.     writeText(RESULTS_X, RESULTS_Y + RESULTS_Y_H, blanks);
  217.     writeText(RESULTS_X, RESULTS_Y + RESULTS_Y_H * 2, blanks); 
  218.     writeText(RESULTS_X, RESULTS_Y + RESULTS_Y_H * 3, blanks);
  219. }
  220.  
  221. int
  222. translate(char *buf, int *whole, int *numerator, int *denominator)
  223. {
  224.     int        retVal = SUCCESS;
  225.  
  226.     if (sscanf(buf, "%d-%d/%d", whole, numerator, denominator) == 3) {
  227.     } else if (sscanf(buf, "%d/%d", numerator, denominator) == 2) {
  228.         *whole = 0;
  229.     } else if (sscanf(buf, "%d", whole) == 1) {
  230.         *numerator = 0;
  231.         *denominator = 1;
  232.     } else {
  233.         beep(ERROR);
  234.         retVal = FAIL;
  235.     }
  236.  
  237.     return retVal;
  238. }
  239.  
  240. void
  241. writeFrac(int x, int y, double value, short *denList)
  242. {
  243.     char     buf[MAX_DISPLAY + 1];
  244.     short    *curDen;
  245.     short     curNom;
  246.     double     frac          = value - (long)value;
  247.     double     bestNom     = 0;
  248.     double     bestDen     = 1;
  249.     double     bestDelta    = frac;
  250.     int         i;
  251.  
  252.     /*
  253.      *  For every possible nominator/denominator combination
  254.      *  search for the closest to the orginal fraction.
  255.      */
  256.     for (curDen = denList; *curDen != DLIST_END; curDen++) {
  257.         for (curNom = 1; curNom < *curDen; curNom++) {
  258.             if (bestDelta >  abs(frac - ((1.0 * curNom) / *curDen))) {
  259.                 bestNom = curNom;
  260.                 bestDen = *curDen;
  261.                 bestDelta = abs(frac - (bestNom / bestDen));
  262.             }
  263.         }
  264.     }
  265.  
  266.     /*
  267.      *  If the closest fraction is worse then rounding up to the
  268.      *  next whole number, round up...
  269.      */
  270.     if (bestDelta > 1 - frac) {
  271.         bestNom = 0;
  272.         value += 1;
  273.     }
  274.  
  275.     /* 
  276.      *  Format output fraction.
  277.      */
  278.     if ((int)(value - frac) == 0 && 
  279.         (bestNom / bestDen > frac || (bestNom == 0 && frac != 0)))
  280.         /*
  281.          *  The output is a fraction only, and is smaller than the
  282.          *  minimum fraction, supress the output.
  283.          */
  284.         buf[0] = EOS;
  285.     else if ((int)bestNom == 0) {
  286.         /*
  287.          *  The fractional part is 0, just print whole number.
  288.          */
  289.         sprintf(buf, "%d", (int)(value - frac));
  290.     } else if ((int)(value - frac) == 0) {
  291.         /* 
  292.          *  The whole number part is 0, just print the fraction.
  293.          */
  294.         sprintf(buf, "%d/%d", (int)bestNom, (int)bestDen);
  295.     } else {
  296.         /*
  297.          *  Print the full whole # and fraction.
  298.          */
  299.         sprintf(buf, "%d-%d/%d", 
  300.                 (int)(value - frac), (int)bestNom, (int)bestDen);
  301.     }
  302.  
  303.     /*
  304.      *  Pad output string with blanks to clear old info.
  305.      */
  306.     if (strlen(buf) > 8)
  307.         /*
  308.          *  The output is to large to fit on the display
  309.          */
  310.         strcpy(buf, "* Lots * ");
  311.     else {
  312.         /*
  313.          *  Pad output string with trailing blanks.
  314.          */
  315.         for (i = strlen(buf); i < 8; i++)
  316.             buf[i] = ' ';
  317.         buf[i] = EOS;
  318.     }
  319.  
  320.     Move(rp, x, y);
  321.     Text(rp, buf, strlen(buf));
  322. }
  323.  
  324.  
  325. void
  326. writeFactor(void)
  327. {
  328.     writeFrac(FACTOR_X, FACTOR_Y, cFactor, facDList);
  329. }
  330.  
  331. void
  332. doControl(ushort gadID)
  333. {
  334.     int        whole;
  335.     int        numerator;
  336.     int        denominator;
  337.  
  338.     switch (gadID) {
  339.         case  KEYCLR_ID:
  340.             mode = IDLE;
  341.             clearDisplay();
  342.             clearResults();
  343.             break;
  344.  
  345.         case KEYCNV_ID:
  346.             if (translate(mainDisplay, &whole, 
  347.                 &numerator, &denominator) != SUCCESS) {
  348.                 beep(ERROR);
  349.                 return;
  350.             } else {
  351.                 mode = IDLE;
  352.                 cFactor = whole + (1.0 * numerator) / denominator;
  353.                 writeFactor();
  354.                 clearResults();
  355.                 clearDisplay();
  356.             }
  357.             break;
  358.     }
  359. }
  360.  
  361. void
  362. writeResults(double value)
  363. {
  364.     value *= cFactor;
  365.  
  366.     writeFrac(RESULTS_X, RESULTS_Y, value / OZ_FACTOR, ozDList);
  367.     writeFrac(RESULTS_X, RESULTS_Y+RESULTS_Y_H, value/TSP_FACTOR, tspDList);
  368.     writeFrac(RESULTS_X, RESULTS_Y+RESULTS_Y_H*2, value/TBL_FACTOR,tblDList);
  369.     writeFrac(RESULTS_X, RESULTS_Y+RESULTS_Y_H*3, value/CUP_FACTOR,cupDList);
  370. }
  371.  
  372. void
  373. doConvert(ushort gadID)
  374. {
  375.     double    factor;
  376.     char   *unit;
  377.     int        whole;
  378.     int        numerator;
  379.     int        denominator;
  380.  
  381.     if (translate(mainDisplay, &whole, &numerator, &denominator) != SUCCESS) {
  382.         beep(ERROR);
  383.         clearResults();
  384.         return;
  385.     }
  386.  
  387.     switch (gadID) {
  388.         case KEYOZ_ID:
  389.             factor = OZ_FACTOR;
  390.             unit   = "Oz  ";
  391.             break;
  392.  
  393.         case KEYCUP_ID:
  394.             factor = CUP_FACTOR;
  395.             unit   = "Cups";
  396.             break;
  397.  
  398.         case KEYTSP_ID:
  399.             factor = TSP_FACTOR;
  400.             unit   = "Tsps";
  401.             break;
  402.  
  403.         case KEYTBL_ID:
  404.             factor = TBL_FACTOR;
  405.             unit   = "Tbls";
  406.             break;
  407.     }
  408.     value = factor * (whole + (1.0 * numerator) / denominator);
  409.     mode = IDLE;
  410.     Move(rp, DISPLAY_UNIT_X, DISPLAY_Y);
  411.     Text(rp, unit, strlen(unit));
  412.     writeResults(value);
  413. }
  414.  
  415. void
  416. doKey(short key)
  417. {
  418.     if (key >= '0' && key <= '9')
  419.         addDigit((ushort)(NUM_TYPE + (key - '0')));
  420.     else switch (key) {
  421.         case ' ':
  422.         case '-':
  423.             addDigit(KEYSPACE_ID);
  424.             break;
  425.  
  426.         case  '/':
  427.             addDigit(KEYSLASH_ID);
  428.             break;
  429.  
  430.         case 'o':
  431.         case 'O':
  432.             doConvert(KEYOZ_ID);
  433.             break;
  434.  
  435.         case 't':
  436.         case 'T':
  437.             doConvert(KEYTSP_ID);
  438.             break;
  439.  
  440.         case 'b':
  441.         case 'B':
  442.             doConvert(KEYTBL_ID);
  443.             break;
  444.  
  445.         case 'c':
  446.         case 'C':
  447.             doConvert(KEYCUP_ID);
  448.             break;
  449.  
  450.         case 'l':
  451.         case 'L':
  452.             doControl(KEYCLR_ID);
  453.             break;
  454.  
  455.         case 'n':
  456.         case 'N':
  457.             doControl(KEYCNV_ID);
  458.             break;
  459.  
  460.         default:
  461.             beep(ERROR);
  462.     }
  463. }
  464.  
  465. void
  466. main(int argc, char **argv)
  467. {
  468.     AR0 struct IntuiMessage *idcmpMsg;
  469.     bool                      pleaseQuit = FALSE;
  470.     ushort                     gadID;
  471.  
  472.     /*
  473.      *  Setup exit() cleanup function.
  474.      */
  475.     if (!onexit(exitTrap))
  476.         exit(1);
  477.  
  478.     /*
  479.      *  Open needed libraries.
  480.      */
  481.     IntuitionBase = OpenLibrary("intuition.library", 0);
  482.     if (IS_NIL(IntuitionBase))
  483.         exit(2);
  484.  
  485.     GfxBase = OpenLibrary("graphics.library", 0);
  486.     if (IS_NIL(GfxBase))
  487.         exit(3);
  488.  
  489.     /*
  490.      *  Setup calculator window.
  491.      */
  492.     w = OpenWindow(&NewWindowStructure1);
  493.     if (IS_NIL(w))
  494.         exit(4);
  495.     rp = w->RPort;
  496.     SetAPen(rp, NORM_PEN);
  497.     SetBPen(rp, BG_PEN);
  498.     SetWindowTitles(w, -1, "Jo & Jeffs' Liquid Measure Converter");
  499.  
  500.     /*
  501.      *  Initialize starting state and display.
  502.      */
  503.     doControl(KEYCLR_ID);
  504.     writeFactor();
  505.  
  506.     /* 
  507.      *  Read IDCMP input and process requests.
  508.      */
  509.     do {
  510.         /*
  511.          *  Read input from IDCMP
  512.          */
  513.         WaitPort(w->UserPort);
  514.  
  515.         while (idcmpMsg = (struct Intuimessage *)GetMsg(w->UserPort)) {
  516.             switch (idcmpMsg->Class) {
  517.                 case CLOSEWINDOW:
  518.                     pleaseQuit = TRUE;
  519.                     break;
  520.  
  521.                 case GADGETUP:
  522.                     gadID = ((struct Gadget *)(idcmpMsg->IAddress))->GadgetID;
  523.                     if ((gadID & TYPE_MASK) == NUM_TYPE) 
  524.                         addDigit(gadID);
  525.                     else if ((gadID & TYPE_MASK) == CNTRL_TYPE)
  526.                         doControl(gadID);
  527.                     else if ((gadID & TYPE_MASK) == CONV_TYPE)
  528.                         doConvert(gadID);
  529.                     break;
  530.  
  531.                 case VANILLAKEY:
  532.                     doKey(idcmpMsg->Code);
  533.                     break;
  534.             }
  535.             ReplyMsg((struct Message *)idcmpMsg);
  536.         }
  537.     } while (!pleaseQuit);
  538.  
  539.     CloseWindow(w);
  540.  
  541.     exit(0);
  542. }
  543.