home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d502 / cells.lha / CELLS / CELLSSource.lzh / cError.c < prev    next >
C/C++ Source or Header  |  1991-04-20  |  11KB  |  426 lines

  1. /*
  2.  *  CELLS       An Implementation of the WireWorld cellular automata
  3.  *              as described in Scientific American, Jan 1990.
  4.  *
  5.  *              Copyright 1990 by Davide P. Cervone.
  6.  *  You may use this code, provided this copyright notice is kept intact.
  7.  *  See the CELLS.HELP file for complete information on distribution conditions.
  8.  */
  9.  
  10. /*
  11.  *  File:  cError.c         Handles error and info requesters.
  12.  *                          Also handles safe memory allocation.
  13.  */
  14.  
  15.  
  16. #include "Cells.h"
  17. #include "cError.h"
  18. #include "cBoxes.h"
  19. #include <libraries/dosextens.h>
  20.  
  21. extern struct IntuiMessage *GetMsg();
  22. extern int DelayedShift;
  23.  
  24. #define MEM_DANGER      (16*1024)           /* when to really get mad */
  25. #define MEM_WARNING     (32*1024)           /* when to warn about low memory */
  26. #define MEM_OK          (MEM_WARNING+1)     /* memory OK over this amount */
  27. static int ErrorLevel = MEM_OK;             /* current memory warning level */
  28.  
  29. static char *SavedTitle;                    /* saved screen title */
  30. static int InfoReqActive;                   /* TRUE if INFO message up */
  31. static APTR OldPrWindow;                    /* old process window pointer */
  32. static struct Process *ourProcess;          /* the CELLS process */
  33.  
  34.  
  35. /*
  36.  *  The strucutres for the Error, Info, and Question requesters
  37.  */
  38.  
  39. static short PanelBox[]  = FBOX(ER_PANELW,ER_PANELH);
  40. static short FrameBox[]  = FBOX(ER_FRAMEW,ER_FRAMEH);
  41. static short ButtonBox[] = FBOX(ER_BUTTONW,ER_BUTTONH);
  42.  
  43. static struct Border ERBorder[] =
  44. {
  45.       #define NEXTBORDER(n)     &ERBorder[n+2]
  46.       #define BORDERNAME        ERBorder
  47.    OUTBRDR(ERB_PANEL, 0,0, PanelBox),
  48.       #undef  NEXTBORDER
  49.       #define NEXTBORDER(n)     NULL
  50.    INBRDR (ERB_FRAME, ER_FRAMEX,ER_FRAMEY, FrameBox),
  51.    OUTBRDR(ERB_BUTTON, 0,0, ButtonBox)
  52. };
  53.  
  54. static struct IntuiText ERText[] =
  55. {
  56.    ITEXT("OK", 7,3),
  57.    {ERRORPEN,FOREGROUND,JAM2, ER_TITLEX,ER_TITLEY,
  58.       NULL, NULL, &ERText[ERT_MESS1]},
  59.    ITEXT(NULL, 0,ER_MESS1Y),
  60.    ITEXT(NULL, 0,ER_MESS2Y),
  61.    ITEXT("Yes", 3,3),
  62.    ITEXT("No",  7,3),
  63. };
  64.  
  65. static struct Gadget ERGadget[] =
  66. {
  67.    {NULL, ER_BUTTONX,ER_BUTTONY, ER_BUTTONW,ER_BUTTONH, GADGHCOMP,
  68.       RELVERIFY, BOOLGADGET|REQGADGET, (APTR)&ERBorder[ERB_BUTTON],
  69.       NULL, &ERText[ERT_OK], 0, NULL, ER_OK, NULL},
  70.    {&ERGadget[2], ER_BUTTONX,ER_BUTTONY, ER_BUTTONW,ER_BUTTONH, GADGHCOMP,
  71.       RELVERIFY, BOOLGADGET|REQGADGET, (APTR)&ERBorder[ERB_BUTTON],
  72.       NULL, &ERText[ERT_YES], 0, NULL, ER_YES, NULL},
  73.    {NULL, ER_BUTTONX-ER_BUTTONW,ER_BUTTONY, ER_BUTTONW,ER_BUTTONH, GADGHCOMP,
  74.       RELVERIFY, BOOLGADGET|REQGADGET, (APTR)&ERBorder[ERB_BUTTON],
  75.       NULL, &ERText[ERT_NO], 0, NULL, ER_NO, NULL},
  76. };
  77.  
  78. static struct Requester ERRequest =
  79. {
  80.    NULL, (BOARDW-ER_PANELW)/2,(BOARDH-ER_PANELH)/2, ER_PANELW,ER_PANELH,
  81.    0,0, &ERGadget[0], &ERBorder[ERB_PANEL], &ERText[ERT_TITLE], 0, FOREGROUND,
  82.    NULL, NULL, NULL
  83. };
  84.  
  85.  
  86. /*
  87.  *  SetErrorText()
  88.  *
  89.  *  Set the requesters title and message strings.
  90.  *  Break a long message string into two parts (at a space), center the
  91.  *    two parts horizontally and make them look good vertically.
  92.  *  Center single line message properly
  93.  */
  94.  
  95. static void SetErrorText(Title,Message)
  96. char *Title;
  97. char *Message;
  98. {
  99.    register short i;
  100.    short Len = strlen(Message);
  101.  
  102.    ERText[ERT_TITLE].IText = Title;
  103.    ERText[ERT_MESS1].IText = Message;
  104.    if (Len > 30)
  105.    {
  106.       ERText[ERT_MESS1].NextText = &ERText[ERT_MESS2];
  107.       ERText[ERT_MESS1].TopEdge  = ER_MESS1Y;
  108.       ERText[ERT_MESS2].TopEdge  = ER_MESS2Y;
  109.       for (i=30; i>0 && Message[i] != ' '; i--);
  110.       if (i == 0) i = 30;
  111.       Message[i++] = 0;
  112.       ERText[ERT_MESS1].LeftEdge = (ER_PANELW - CHAR_WIDTH*(i-1)) / 2;
  113.       ERText[ERT_MESS2].LeftEdge = (ER_PANELW - CHAR_WIDTH*(Len-i)) / 2;
  114.       ERText[ERT_MESS2].IText = &Message[i];
  115.    } else {
  116.       ERText[ERT_MESS1].LeftEdge = (ER_PANELW - CHAR_WIDTH*Len) / 2;
  117.       ERText[ERT_MESS1].TopEdge  = ER_MESSY;
  118.       ERText[ERT_MESS1].NextText = NULL;
  119.    }
  120. }
  121.  
  122.  
  123. /*
  124.  *  WaitForGadget()
  125.  *
  126.  *  As long as no gadget is pressed
  127.  *    For each message in the window's UserPort,
  128.  *      store the delayed shift,
  129.  *      if the message is a gadget up,
  130.  *        do the Gadget routine with the given gadget
  131.  *      reply to the message
  132.  *    If we are not yet done, wait for additional messages
  133.  */
  134.  
  135. static void WaitForGadget(DoGadget)
  136. int (*DoGadget)();
  137. {
  138.    struct IntuiMessage *theMessage;
  139.    short NotDone = TRUE;
  140.    struct MsgPort *thePort = myWindow->UserPort;
  141.    long SignalMask = (1 << thePort->mp_SigBit);
  142.  
  143.    while (NotDone)
  144.    {
  145.       while (theMessage = GetMsg(thePort))
  146.       {
  147.          DelayedShift = theMessage->Qualifier & SHIFTKEYS;
  148.          if (theMessage->Class == GADGETUP)
  149.             NotDone = (*DoGadget)(theMessage->IAddress,NotDone);
  150.          ReplyMsg(theMessage);
  151.       }
  152.       if (NotDone) Wait(SignalMask);
  153.    }
  154. }
  155.  
  156.  
  157. /*
  158.  *  ClearInfoMessage()
  159.  *
  160.  *  If the Info requester is up, remove the requester and clear the flag.
  161.  */
  162.  
  163. void ClearInfoMessage()
  164. {
  165.    if (InfoReqActive)
  166.    {
  167.       EndRequest(&ERRequest,myWindow);
  168.       InfoReqActive = FALSE;
  169.    }
  170. }
  171.  
  172.  
  173. /*
  174.  *  DoInfoMessage()
  175.  *
  176.  *  Clear any previous info message,
  177.  *  Set the message and title strings, and remove the requester's gadgets
  178.  *  Put up the requester, if possible.
  179.  */
  180.  
  181. void DoInfoMessage(s,x1,x2,x3)
  182. char *s,*x1,*x2,*x3;
  183. {
  184.    static char Message[80];
  185.    
  186.    ClearInfoMessage();
  187.    sprintf(Message,s,x1,x2,x3);
  188.    SetErrorText("Please Be Patient:",Message);
  189.    ERRequest.ReqGadget = NULL;
  190.    if (Request(&ERRequest,myWindow)) InfoReqActive = TRUE;
  191. }
  192.  
  193.  
  194. /*
  195.  *  CheckForOK
  196.  *
  197.  *   If the gadget ID is the OK gadget, then we're done
  198.  */
  199.  
  200. static int CheckForOK(theGadget,NotDone)
  201. struct Gadget *theGadget;
  202. int NotDone;
  203. {
  204.    if (theGadget->GadgetID == ER_OK) NotDone = FALSE;
  205.    return(NotDone);
  206. }
  207.  
  208.  
  209. /*
  210.  *  DoError()
  211.  *
  212.  *  Clear the info requester if it is up
  213.  *  Prepare the error message, and set the requester title and gadgets
  214.  *  Put up the requester, if possible.
  215.  *  If not, try to free HELP information and try again.
  216.  *  If the requester could be openned,
  217.  *    wait for the OK button to be pressed, and then end the requester
  218.  *  Otherwise
  219.  *    Remake the error message in case it was divied into two lines.
  220.  *    put the message into the screen title and save the old title.
  221.  */  
  222.  
  223. void DoError(s,x1,x2,x3)
  224. char *s,*x1,*x2,*x3;
  225. {
  226.    char Message[80];
  227.    int ReqSet;
  228.  
  229.    ClearInfoMessage();
  230.    sprintf(Message,s,x1,x2,x3);
  231.    SetErrorText("Error Report:",Message);
  232.    ERRequest.ReqGadget = &ERGadget[0];
  233.    ReqSet = Request(&ERRequest,myWindow);
  234.    if (!ReqSet)
  235.    {
  236.       if (CanClearHelpLines()) ReqSet = Request(&ERRequest,myWindow);
  237.       if (!ReqSet && CanClearHelpTopics())
  238.          ReqSet = Request(&ERRequest,myWindow);
  239.    }
  240.    if (ReqSet)
  241.    {
  242.       WaitForGadget(&CheckForOK);
  243.       EndRequest(&ERRequest,myWindow);
  244.    } else {
  245.       sprintf(Message,s,x1,x2,x3);
  246.       if (SavedTitle == NULL) SavedTitle = myWindow->ScreenTitle;
  247.       SetWindowTitles(myWindow,-1,Message);
  248.    }
  249. }
  250.  
  251.  
  252. /*
  253.  *  ClearError()
  254.  *
  255.  *  If the message was a mouse button, gadget up or down, or a window
  256.  *  inactivation event, and we had previously saved a window title, 
  257.  *  put back the old title, and clear the saved title.
  258.  */
  259.  
  260. void ClearError(theMessage)
  261. struct IntuiMessage *theMessage;
  262. {
  263.    switch (theMessage->Class)
  264.    {
  265.       case MOUSEBUTTONS:
  266.       case GADGETUP:
  267.       case GADGETDOWN:
  268.       case INACTIVEWINDOW:
  269.          if (SavedTitle) SetWindowTitles(myWindow,-1,SavedTitle);
  270.          SavedTitle = NULL;
  271.          break;
  272.    }
  273. }
  274.  
  275. static int YesOrNo;
  276.  
  277.  
  278. /*
  279.  *  CheckForYesNo()
  280.  *
  281.  *  If either button is pressed, we're done.  Record the correct YesOrNo
  282.  *  value for a YES being pressed.
  283.  */
  284.  
  285. static int CheckForYesNo(theGadget,NotDone)
  286. struct Gadget *theGadget;
  287. int NotDone;
  288. {
  289.    switch(theGadget->GadgetID)
  290.    {
  291.       case ER_YES:
  292.          YesOrNo = TRUE;
  293.       case ER_NO:
  294.          NotDone = FALSE;
  295.          break;
  296.    }
  297.    return(NotDone);
  298. }
  299.  
  300.  
  301. /*
  302.  *  DoQuestion()
  303.  *
  304.  *  Clear the info requester, if any is up.
  305.  *  set the requester title and message strings, and set up the gadget list.
  306.  *  Clear the YesOrNo answer.
  307.  *  Put up the requester, if possible.
  308.  *    If successful, wait for the Yes or No buttons to be pressed
  309.  *    and then remove the requester
  310.  *  return the button that was pressed.
  311.  */
  312.  
  313. int DoQuestion(s,x1,x2,x3)
  314. char *s,*x1,*x2,*x3;
  315. {
  316.    char Message[80];
  317.  
  318.    ClearInfoMessage();
  319.    sprintf(Message,s,x1,x2,x3);
  320.    SetErrorText("Confirmation Requested:",Message);
  321.    ERRequest.ReqGadget = &ERGadget[1];
  322.    YesOrNo = FALSE;
  323.    if (Request(&ERRequest,myWindow))
  324.    {
  325.       WaitForGadget(&CheckForYesNo);
  326.       EndRequest(&ERRequest,myWindow);
  327.    }
  328.    return(YesOrNo);
  329. }
  330.  
  331. #undef AllocMem
  332. static int BufferErrors,ErrorReported;
  333.  
  334.  
  335. /*
  336.  *  myAllocMem()
  337.  *
  338.  *  Attempt to allocate the requested block of memory.
  339.  *  Check the remaining memory available.
  340.  *  If there is little memory left, or if there was not enough to get the
  341.  *      requested chunk,
  342.  *    Try to clear the help text lines that aren't in use, and try
  343.  *      to allocate the memory again, if necessary.
  344.  *    If there's still very little memory,
  345.  *      Try to free the help topics as well, and then try to get the
  346.  *        memory again, if necessary.
  347.  *  If there is a dangerously small amount of memory,
  348.  *    and we haven't already said so, then give a memory warning, and
  349.  *    record that we did so.
  350.  *  Otherwise, if there is little memory left,
  351.  *    and we haven't already mentioned it, do so and record that we did.
  352.  *  Otherwise, note that there is sufficient memory again.
  353.  */
  354.  
  355. APTR myAllocMem(n,Flags)
  356. int n;
  357. ULONG Flags;
  358. {
  359.    long Mem;
  360.    APTR theByte;
  361.    extern APTR AllocMem();
  362.    extern long AvailMem();
  363.    
  364.    theByte = AllocMem(n,Flags);
  365.    Mem = AvailMem(0);
  366.    if (Mem < MEM_WARNING || theByte == NULL)
  367.    {
  368.       if (CanClearHelpLines())
  369.       {
  370.          if (theByte == NULL) theByte = AllocMem(n,Flags);
  371.          Mem = AvailMem(0);
  372.       }
  373.       if (Mem < MEM_DANGER || theByte == NULL)
  374.       {
  375.          if (CanClearHelpTopics())
  376.          {
  377.             if (theByte == NULL) theByte = AllocMem(n,Flags);
  378.             Mem = AvailMem(0);
  379.          }
  380.       }
  381.    }
  382.    if (Mem < MEM_DANGER)
  383.    {
  384.       if (ErrorLevel > MEM_DANGER)
  385.          DoError("Danger: Only %dK Memory Free!",Mem/1024);
  386.       ErrorLevel = MEM_DANGER;
  387.    } else if (Mem < MEM_WARNING) {
  388.       if (ErrorLevel > MEM_WARNING)
  389.          DoError("Low On Memory: %dK Remaining",Mem/1024);
  390.       ErrorLevel = MEM_WARNING;
  391.    } else {
  392.       ErrorLevel = MEM_OK;
  393.    }
  394.    return(theByte);
  395. }
  396.  
  397.  
  398. /*
  399.  *  SetErrorWindow()
  400.  *
  401.  *  Set the process error screen to be the CELLS screen, but record the
  402.  *  old window pointer so we can replace it later.
  403.  */
  404.  
  405. void SetErrorWindow(theWindow)
  406. APTR theWindow;
  407. {
  408.    extern struct Process *FindTask();
  409.    
  410.    ourProcess = FindTask(NULL);
  411.    OldPrWindow = ourProcess->pr_WindowPtr;
  412.    ourProcess->pr_WindowPtr = theWindow;
  413. }
  414.  
  415.  
  416. /*
  417.  *  ResetErrorWindow()
  418.  *
  419.  *  Put back the old process error screen pointer, if we changed it above.
  420.  */
  421.  
  422. void ResetErrorWindow()
  423. {
  424.    if (ourProcess) ourProcess->pr_WindowPtr = OldPrWindow;
  425. }
  426.