home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / pd / graphics / 3d / icoons / source / intui.c < prev    next >
C/C++ Source or Header  |  1992-11-20  |  36KB  |  1,375 lines

  1. /* :ts=8 */
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <math.h>
  6.  
  7. #include "general.h"
  8. #include "globals.h"
  9. #include "intui.h"
  10. #include "spl_gfx.h"
  11. #include "spl_util.h"
  12. #include "timer.h"
  13. #include "file.h"
  14. #include "windows.h"
  15. #include "commands.h"
  16. #include "config.h"
  17. #include "knotinfo.h"
  18. #include "rotate_p.h"
  19. #include "pan.h"
  20. #include "center.h"
  21. #include "group.h"
  22. #include "scale_g.h"
  23. #include "rotate_g.h"
  24. #include "move.h"
  25. #include "origin.h"
  26. #include "render.h"
  27.  
  28. Window_Info_T    Windows[Max_Nbr_Windows];
  29.  
  30. #ifdef NTSC
  31.  
  32.     /* Positions of the four small views on the screen: */
  33. View_T    Views_Small[4] = {
  34.     341, 108, 633, 196, 0, 0,    /* 0 = V_X : Y - Z */
  35.      25, 108, 317, 196, 0, 0,    /* 1 = V_Y : X - Z */
  36.      25,  12, 317, 104, 0, 0,    /* 2 = V_Z : X - Y */
  37.     341,  12, 633, 104, 0, 0    /* 3 = V_P : Persp */
  38. };
  39.     /* Positions of the four big views on the screen:   */
  40. View_T    Views_Big[4] = {
  41.     21,  12, 633, 196, 0, 0,    /* 0 = V_X : Y - Z */
  42.     21,  12, 633, 196, 0, 0,    /* 1 = V_Y : X - Z */
  43.     21,  12, 633, 196, 0, 0,    /* 2 = V_Z : X - Y */
  44.     21,  12, 633, 196, 0, 0        /* 3 = V_P : Persp */
  45. };
  46.  
  47. #else
  48.  
  49.     /* Positions of the four small views on the screen: */
  50. View_T    Views_Small[4] = {
  51.     341, 131, 633, 247, 0, 0,    /* 0 = V_X : Y - Z */
  52.      25, 131, 317, 247, 0, 0,    /* 1 = V_Y : X - Z */
  53.      25,  12, 317, 128, 0, 0,    /* 2 = V_Z : X - Y */
  54.     341,  12, 633, 128, 0, 0    /* 3 = V_P : Persp */
  55. };
  56.     /* Positions of the four big views on the screen:   */
  57. View_T    Views_Big[4] = {
  58.     21,  12, 633, 247, 0, 0,    /* 0 = V_X : Y - Z */
  59.     21,  12, 633, 247, 0, 0,    /* 1 = V_Y : X - Z */
  60.     21,  12, 633, 247, 0, 0,    /* 2 = V_Z : X - Y */
  61.     21,  12, 633, 247, 0, 0        /* 3 = V_P : Persp */
  62. };
  63.  
  64. #endif
  65.     
  66.     /* The currently used views:    */
  67. View_T             *Views             = Views_Small;
  68. Window_Id_T        Id_Active_Window     = W_Main;
  69.  
  70.     /* Size of IDCMP mouse queue. If this is 0, then redraw    will be    */
  71.     /* done when there's no more messages waiting, otherwise redraw    */
  72.     /* will be done whenever a mouse move event happens.        */
  73.  
  74. unsigned long        MQ_Size_KnotInfo    = 2;
  75. unsigned long        MQ_Size_Rotate_P    = 2;
  76. unsigned long        MQ_Size_Rotate_G    = 2;
  77. unsigned long        MQ_Size_Scale_G        = 2;
  78. unsigned long        MQ_Size_Move_G        = 2;
  79. unsigned long        MQ_Size_Move        = 0;
  80.  
  81.     /* TRUE when redrawing for each mouse move event */
  82. Boolean_T        Redraw_Always;
  83.  
  84. struct MsgPort        *User_Port        = NULL;
  85. static USHORT         *Mouse_Image        = NULL;
  86. static USHORT         *Busy_Image        = NULL;
  87.  
  88. struct IntuitionBase    *IntuitionBase;
  89. struct GfxBase        *GfxBase;
  90. struct Library        *GadToolsBase;
  91. struct Library        *AslBase;
  92.  
  93. #define Mouse_Image_Size    100
  94. #define Busy_Image_Size        200
  95.     
  96.     /* Global text buffer for error messages    */
  97. char    Error_Msg[Buffer_Length+1];
  98.  
  99. /* Window title, this MUST be 80 characters long */
  100. char     Window_Title[] = 
  101. "ICoons                                                                       ";
  102.  
  103. void Set_Window_Title(char *Title)
  104. /************************************************************************/
  105. /*                                                                      */
  106. /* Set the window title (first 40 chars) in the title bar.        */
  107. /* The remaining characters are reserved for messages.            */
  108. /*                                                                      */
  109. /* if 'Title' is NULL, reset the title to 'ICoons'.            */
  110. /*                                                                      */
  111. /************************************************************************/
  112. {
  113.     int     i;
  114.     char *Cp;
  115.     char Buffer[Buffer_Length+1];
  116.  
  117.     if (Title == NULL) {
  118.     if (Select_Spline != NULL) {
  119.             sprintf(Buffer, "ICoons   Id:%d %s %s", 
  120.         Select_Point_Id,
  121.         Group_Mode ? "Group" : "",
  122.         Points_Hidden ? "H" : "");
  123.     } else {
  124.             sprintf(Buffer, "ICoons   Id:NONE %s %s", 
  125.         Group_Mode ? "Group" : "",
  126.         Points_Hidden ? "H" : "");
  127.     }
  128.     Title = Buffer;
  129.     }
  130.  
  131.     for (i = 0, Cp = Title; i < 40 && *Cp != '\0'; i++,Cp++)
  132.                 Window_Title[i] = *Cp;
  133.     while (i < 40) Window_Title[i++] = ' ';
  134.  
  135.     SetWindowTitles(Windows[Id_Active_Window].Window, 
  136.                     Window_Title, (UBYTE *) -1);
  137. } /* Set_Window_Title */
  138.  
  139. void Display_Status(char *Message)
  140. /************************************************************************/
  141. /*                                                                      */
  142. /* Show the text 'Message' in the last 40 characters of the title bar.    */
  143. /* if 'Message' is NULL, then remove any message.            */
  144. /*                                                                      */
  145. /************************************************************************/
  146. {
  147.     int  i;
  148.     char *Cp;
  149.  
  150.     if (Message == NULL) {
  151.  
  152.     for (i = 40; i < 80; i++) Window_Title[i] = ' ';
  153.  
  154.     } else {
  155.  
  156.         for (Cp = Message, i = 40; i < 80 && *Cp != '\0'; i++)
  157.                     Window_Title[i] = *Cp++;
  158.     while (i < 80) Window_Title[i++] = ' ';
  159.  
  160.     }
  161.     SetWindowTitles(Windows[Id_Active_Window].Window, 
  162.                     Window_Title, (UBYTE *) -1);
  163.  
  164. } /* Display_Status */
  165.  
  166. void Display_Message(char *Message)
  167. /************************************************************************/
  168. /*                                                                      */
  169. /* Show the text 'Message' to the user, and wait until he clicks a    */
  170. /* 'Continue' button.                            */
  171. /* 'Message' may contain \n do denote new lines.            */
  172. /*                                                                      */
  173. /************************************************************************/
  174. {
  175.     struct EasyStruct Requester;
  176.  
  177.     Requester.es_StructSize = sizeof(struct EasyStruct);
  178.     Requester.es_Flags        = 0;
  179.     Requester.es_Title        = "ICoons";
  180.     Requester.es_TextFormat    = Message;
  181.     Requester.es_GadgetFormat    = "Continue";
  182.  
  183.     (void) EasyRequest(Windows[Id_Active_Window].Window, &Requester, NULL);
  184.  
  185. } /* Display_Message */
  186.  
  187. void Display_Error_Message(char *Message)
  188. /************************************************************************/
  189. /*                                                                      */
  190. /* Show the text 'Message' to the user in an ALERT, and wait until he     */
  191. /* clicks a button.                            */
  192. /* Only the first 60 characters of the message is shown.        */
  193. /*                                                                      */
  194. /************************************************************************/
  195. {
  196.     UBYTE Buffer[Buffer_Length+1];
  197.     int      Length;
  198.     int      Pos;
  199.  
  200.     Length = strlen(Message);
  201.     if (Length > 60) Length = 60;
  202.  
  203.     Pos = 0;
  204.  
  205.     Buffer[Pos++] = 0x00;
  206.     Buffer[Pos++] = 0x30;    /* 16 bit X coordinate in pixels */
  207.  
  208.     Buffer[Pos++] = 0x14;    /*  8 bit Y coordinate in pixels */
  209.  
  210.     strncpy(&Buffer[Pos], Message, Length); Pos += Length;
  211.  
  212.     Buffer[Pos++] = '\0';    /* End of string  */
  213.  
  214.     Buffer[Pos] = '\0';    /* End of message */
  215.    
  216.     (void) DisplayAlert(RECOVERY_ALERT, Buffer, /* Heigth = */ 42); 
  217.  
  218. } /* Display_Message */
  219.  
  220. int Ask_Question(char *Question, char *Choices)
  221. /************************************************************************/
  222. /*                                                                      */
  223. /* Ask the question 'Question' and let him choose between the choices    */
  224. /* in 'Choices'.                            */
  225. /* 'Question' may contain \n do denote new lines.            */
  226. /* The choices are separated with vertical bars (ex: "Ok|Cancel").    */
  227. /*                                                                      */
  228. /* The function will return a number identifying the response:        */
  229. /* 1 for the leftmost button, 2 for the next button etc. AND        */
  230. /* 0 for the rightmost button (!!!!)                    */
  231. /*                                                                      */
  232. /* Example: Ask_Question("Quit now?", "Yes|Maybe|No")            */
  233. /*     will return 1 for YES 2 for MAYBE and 0 for NO.            */
  234. /*                                                                      */
  235. /************************************************************************/
  236. {
  237.     struct EasyStruct Requester;
  238.     int             Status;
  239.  
  240.     Requester.es_StructSize = sizeof(struct EasyStruct);
  241.     Requester.es_Flags        = 0;
  242.     Requester.es_Title        = "ICoons";
  243.     Requester.es_TextFormat    = Question;
  244.     Requester.es_GadgetFormat    = Choices;
  245.  
  246.     Status = EasyRequest(Windows[Id_Active_Window].Window, &Requester, NULL);
  247.  
  248.     return(Status);
  249.  
  250. } /* Ask_Question */
  251.  
  252. static 
  253. void Windows_Init()
  254. /************************************************************************/
  255. /*                                                                      */
  256. /* Initialize the Windows array.                    */
  257. /*                                                                      */
  258. /************************************************************************/
  259. {
  260.     int            i;
  261.     static Boolean_T    Init_Done = FALSE;
  262.  
  263.     if (Init_Done) return;
  264.  
  265.     Init_Done = TRUE;
  266.  
  267.     for (i = 0; i < Max_Nbr_Windows; i++) {
  268.         Windows[i].Window    = NULL;
  269.         Windows[i].ViewPort  = NULL;
  270.         Windows[i].RastPort  = NULL;
  271.     } /* for */
  272.  
  273.     Views = Views_Small;
  274.  
  275.     for (i = 0; i < 4; i++) {
  276.  
  277.     Views_Small[i].X_Center = (Views_Small[i].X_Min + 
  278.                    Views_Small[i].X_Max) / 2;
  279.     Views_Small[i].Y_Center = (Views_Small[i].Y_Min + 
  280.                    Views_Small[i].Y_Max) / 2;
  281.  
  282.     Views_Big[i].X_Center = (Views_Big[i].X_Min + 
  283.                  Views_Big[i].X_Max) / 2;
  284.     Views_Big[i].Y_Center = (Views_Big[i].Y_Min + 
  285.                  Views_Big[i].Y_Max) / 2;
  286.  
  287.     } /* for */
  288.  
  289. } /* Windows_Init */
  290.  
  291. static 
  292. void Set_Normal_Pointer(Window_Id_T Id)
  293. /************************************************************************/
  294. /*                                                                      */
  295. /* Define a custom pointer for the window defined by Id.        */
  296. /*                                                                      */
  297. /************************************************************************/
  298. {
  299.     USHORT *M;
  300.  
  301.     if (Windows[Id].Window == NULL) return;
  302.  
  303.     if (Mouse_Image == NULL) {
  304.  
  305.         Mouse_Image = (USHORT *) AllocMem(Mouse_Image_Size, MEMF_CHIP);
  306.     if (Mouse_Image == NULL) {
  307.         Display_Error_Message("Couldn't allocate memory");
  308.         CloseStuff();
  309.         exit(1);
  310.     }
  311.  
  312.     M = Mouse_Image;
  313.  
  314.         *M++ = 0x0000, *M++ = 0x0000;
  315.  
  316.     /* plane 1,    plane 2    */
  317.     *M++ = 0x0400; *M++ = 0x0400;    /* Line 1     */
  318.     *M++ = 0x0400; *M++ = 0x0400;    /* Line 2     */
  319.     *M++ = 0x0400; *M++ = 0x0400;    /* Line 3     */
  320.     *M++ = 0x0400; *M++ = 0x0400;    /* Line 4     */
  321.  
  322.           *M++ = 0x0000; *M++ = 0x0000;    /* Line 5     */
  323.     *M++ = 0xf5f0; *M++ = 0xf5f0;    /* Line 6     */
  324.     *M++ = 0x0000; *M++ = 0x0000;    /* Line 7     */
  325.  
  326.     *M++ = 0x0400; *M++ = 0x0400;    /* Line 8     */
  327.     *M++ = 0x0400; *M++ = 0x0400;    /* Line 9     */
  328.     *M++ = 0x0400; *M++ = 0x0400;    /* Line 10     */
  329.     *M++ = 0x0400; *M++ = 0x0400;    /* Line 11     */
  330.  
  331.     *M++ = 0x0000; *M++ = 0x0000;
  332.     }
  333.  
  334.     switch (Id) {
  335.  
  336.         case W_Main:
  337.         case W_ExpandedView:
  338.         SetPointer(Windows[Id].Window, Mouse_Image, 11, 11, -5, -5);
  339.         break;
  340.  
  341.     default:             /* Normal intuition pointer */
  342.         ClearPointer(Windows[Id].Window);
  343.         break;
  344.  
  345.     } /* switch */
  346.  
  347. } /* Set_Normal_Pointer */
  348.  
  349. static 
  350. void Set_Busy_Pointer(Window_Id_T Id)
  351. /************************************************************************/
  352. /*                                                                      */
  353. /* Define a custom pointer for the window defined by Id.        */
  354. /*                                                                      */
  355. /************************************************************************/
  356. {
  357.     USHORT *M;
  358.  
  359.     if (Windows[Id].Window == NULL) return;
  360.  
  361.     if (Busy_Image == NULL) {
  362.  
  363.         Busy_Image = (USHORT *) AllocMem(Busy_Image_Size, MEMF_CHIP);
  364.     if (Busy_Image == NULL) {
  365.         Display_Error_Message("Couldn't allocate memory");
  366.         CloseStuff();
  367.         exit(1);
  368.     }
  369.  
  370.     M = Busy_Image;
  371.  
  372.         *M++ = 0x0000, *M++ = 0x0000;
  373.  
  374.     /* plane 1,    plane 2    */
  375.     *M++ = 0x0400; *M++ = 0x07c0;    /* Line 1     */
  376.     *M++ = 0x0000; *M++ = 0x07c0;    /* Line 2     */
  377.     *M++ = 0x0100; *M++ = 0x0380;    /* Line 3     */
  378.     *M++ = 0x0000; *M++ = 0x07e0;    /* Line 4     */
  379.           *M++ = 0x07c0; *M++ = 0x1ff8;    /* Line 5     */
  380.     *M++ = 0x1ff0; *M++ = 0x3fec;    /* Line 6     */
  381.     *M++ = 0x3ff8; *M++ = 0x7fde;    /* Line 7     */
  382.     *M++ = 0x3ff8; *M++ = 0x7fbe;    /* Line 8     */
  383.     *M++ = 0x7ffc; *M++ = 0xff7f;    /* Line 9     */
  384.     *M++ = 0x7efc; *M++ = 0xffff;    /* Line 10     */
  385.     *M++ = 0x7ffc; *M++ = 0xffff;    /* Line 11     */
  386.     *M++ = 0x3ff8; *M++ = 0x7ffe;    /* Line 12     */
  387.     *M++ = 0x3ff8; *M++ = 0x7ffe;    /* Line 13     */
  388.     *M++ = 0x1ff0; *M++ = 0x3ffc;    /* Line 14     */
  389.     *M++ = 0x07c0; *M++ = 0x1ff8;    /* Line 15     */
  390.     *M++ = 0x0000; *M++ = 0x07e0;    /* Line 16     */
  391.  
  392.     *M++ = 0x0000; *M++ = 0x0000;
  393.     }
  394.  
  395.     SetPointer(Windows[Id].Window, Busy_Image, 16, 16, -6, 0);
  396.  
  397. } /* Set_Busy_Pointer */
  398.  
  399. void Set_Pointer(Boolean_T Busy)
  400. /************************************************************************/
  401. /*                                                                      */
  402. /* Set pointer to busy pointer in all windows if 'Busy' is TRUE, other-    */
  403. /* set default pointer.                            */
  404. /*                                                                      */
  405. /************************************************************************/
  406. {
  407.     if (Busy) {
  408.  
  409.         Set_Busy_Pointer(W_Config);
  410.         Set_Busy_Pointer(W_ExpandedView);
  411.         Set_Busy_Pointer(W_Move_Group);
  412.         Set_Busy_Pointer(W_Rotate_Group);
  413.         Set_Busy_Pointer(W_Scale_Group);
  414.         Set_Busy_Pointer(W_KnotInfo);
  415.         Set_Busy_Pointer(W_Main);
  416.  
  417.     } else {
  418.  
  419.         Set_Normal_Pointer(W_Config);
  420.         Set_Normal_Pointer(W_ExpandedView);
  421.         Set_Normal_Pointer(W_Move_Group);
  422.         Set_Normal_Pointer(W_Rotate_Group);
  423.         Set_Normal_Pointer(W_Scale_Group);
  424.         Set_Normal_Pointer(W_KnotInfo);
  425.         Set_Normal_Pointer(W_Main);
  426.  
  427.     } /* if .. else .. */
  428.  
  429. } /* Set_Pointer */
  430.  
  431. void Set_RMBTrap(Boolean_T On)
  432. /************************************************************************/
  433. /*                                                                      */
  434. /* Activate or deactivate RMBTrap.                    */
  435. /*                                                                      */
  436. /* If RMBTrap is active, then the menu is disabled, and the application    */
  437. /* can receive MENUDOWN and MENUUP events.                */
  438. /*                                                                      */
  439. /************************************************************************/
  440. {
  441.     int i;
  442.  
  443.     Forbid(); /* Disable multitasking while doing this (RKMLib p. 110) */
  444.  
  445.     for (i = 0; i < Max_Nbr_Windows; i++) {
  446.  
  447.     if (Windows[i].Window != NULL) {
  448.  
  449.         if (On) Windows[i].Window->Flags |= WFLG_RMBTRAP;
  450.         else    Windows[i].Window->Flags &= ~WFLG_RMBTRAP;
  451.         
  452.         } /* if */
  453.     } /* for */
  454.  
  455.     Permit();
  456.  
  457.  
  458. } /* Set_RMBTrap */
  459.  
  460. void StripIntuiMessages(struct MsgPort *mp, struct Window *win)
  461. /************************************************************************/
  462. /*                                                                      */
  463. /* Function to remove and reply all IntuiMessages on a port that have    */
  464. /* been sent to a particular window.                    */
  465. /* Taken from RKM:Libraries p. 255                    */
  466. /*                                                                      */
  467. /************************************************************************/
  468. {
  469.     struct IntuiMessage *msg;
  470.     struct Node        *succ;
  471.  
  472.     msg = (struct IntuiMessage *)mp->mp_MsgList.lh_Head;
  473.  
  474.     while (succ = msg->ExecMessage.mn_Node.ln_Succ) {
  475.  
  476.     if (msg->IDCMPWindow == win) {    
  477.  
  478.         /* Intuition is about to free this message
  479.         ** Make sure that we have politely sent it back.
  480.             */
  481.  
  482.         Remove( (struct Node *) msg);
  483.  
  484.         ReplyMsg( (struct Message *) msg);
  485.  
  486.     } /* if */
  487.  
  488.     msg = (struct IntuiMessage *) succ;
  489.     
  490.     } /* while */
  491.   
  492. } /* StripIntuiMessages */
  493.  
  494. void RemovePort(struct Window *win, Boolean_T Do_Free)
  495. /************************************************************************/
  496. /*                                                                      */
  497. /* Remove the userport from the window 'win'.                */
  498. /* If Do_Free is TRUE the port will be deleted.                */
  499. /*                                                                      */
  500. /************************************************************************/
  501. {
  502.     /* We forbid here to keep out of race conditions with Intuition */
  503.  
  504.     Forbid();
  505.  
  506.     /* Send back any messages for this window that have not yet been
  507.     ** processed.
  508.     */
  509.  
  510.     StripIntuiMessages(win->UserPort, win);
  511.  
  512.     /* Clear UserPort so Intuition will not free it */
  513.  
  514.     if (!Do_Free) win->UserPort = NULL;
  515.  
  516.     ModifyIDCMP(win, 0L);
  517.  
  518.     /* Turn multitasking back on */
  519.     Permit();
  520.  
  521. } /* RemovePort */
  522.  
  523. void Window_Close(Window_Id_T Id)
  524. /************************************************************************/
  525. /*                                                                      */
  526. /*                                                                      */
  527. /************************************************************************/
  528. {
  529.  
  530.     if (Windows[Id].Window == NULL) return;
  531.  
  532.     switch (Id) {
  533.  
  534.     case W_Main:
  535.     CloseMainWindow();
  536.     break;
  537.  
  538.     case W_KnotInfo:
  539.     RemovePort(Windows[Id].Window, FALSE);
  540.     ClearMenuStrip(Windows[Id].Window);
  541.     CloseKnotInfoWindow();
  542.     break;
  543.  
  544.     case W_Scale_Group:
  545.     RemovePort(Windows[Id].Window, FALSE);
  546.     ClearMenuStrip(Windows[Id].Window);
  547.     CloseScale_GroupWindow();
  548.     break;
  549.  
  550.     case W_Rotate_Group:
  551.     RemovePort(Windows[Id].Window, FALSE);
  552.     ClearMenuStrip(Windows[Id].Window);
  553.     CloseRotate_GroupWindow();
  554.     break;
  555.  
  556.     case W_Move_Group:
  557.     RemovePort(Windows[Id].Window, FALSE);
  558.     ClearMenuStrip(Windows[Id].Window);
  559.     CloseMove_GroupWindow();
  560.     break;
  561.  
  562.     case W_ExpandedView:
  563.     RemovePort(Windows[Id].Window, FALSE);
  564.     ClearMenuStrip(Windows[Id].Window);
  565.     CloseExpandedViewWindow();
  566.     Id_Active_Window = W_Main;
  567.     break;
  568.  
  569.     case W_Config:
  570.     RemovePort(Windows[Id].Window, FALSE);
  571.     ClearMenuStrip(Windows[Id].Window);
  572.     CloseConfigWindow();
  573.     break;
  574.  
  575.     default: 
  576.         sprintf(Error_Msg, "Unknown window id %d",  Id);
  577.     Display_Error_Message(Error_Msg);
  578.         CloseStuff();
  579.  
  580.     } /* switch */    
  581.  
  582.     Windows[ Id].Window = NULL;
  583.  
  584. } /* Window_Close */
  585.  
  586. void Window_Open(Window_Id_T Id)
  587. /************************************************************************/
  588. /*                                                                      */
  589. /* Open a window. The main window should always be opened first, as     */
  590. /* its UserPort is used for other windows.                */
  591. /*                                                                      */
  592. /************************************************************************/
  593. {
  594.     long    Status;
  595.     ULONG     IDCMP_Flags;
  596.  
  597.     if (Windows[Id].Window != NULL) return;
  598.  
  599.     if (Id == W_Main) {
  600.  
  601.     Status = OpenMainWindow();
  602.         if (Status != NULL) {
  603.         sprintf(Error_Msg, "Couldn't open window %d, Status = %d", 
  604.                          Id, Status);
  605.         Display_Error_Message(Error_Msg);
  606.             CloseStuff();
  607.             exit(1);     
  608.         } 
  609.         Windows[Id].Window = MainWnd;
  610.         User_Port = Windows[Id].Window->UserPort;
  611.  
  612.     } else {
  613.  
  614.         if (Windows[W_Main].Window == NULL) {
  615.         Display_Error_Message("Main window should be opened first.");
  616.             CloseStuff();
  617.             exit(1);     
  618.         } /* if */
  619.  
  620.         switch (Id) {
  621.  
  622.         case W_KnotInfo:
  623.         Status = OpenKnotInfoWindow();
  624.             Windows[Id].Window = KnotInfoWnd;
  625.         break;
  626.  
  627.         case W_Scale_Group:
  628.         Status = OpenScale_GroupWindow();
  629.             Windows[Id].Window = Scale_GroupWnd;
  630.         break;
  631.  
  632.         case W_Rotate_Group:
  633.         Status = OpenRotate_GroupWindow();
  634.             Windows[Id].Window = Rotate_GroupWnd;
  635.         break;
  636.  
  637.         case W_Move_Group:
  638.         Status = OpenMove_GroupWindow();
  639.             Windows[Id].Window = Move_GroupWnd;
  640.         break;
  641.  
  642.         case W_ExpandedView:
  643.         Status = OpenExpandedViewWindow();
  644.             Windows[Id].Window = ExpandedViewWnd;
  645.         break;
  646.  
  647.         case W_Config:
  648.         Status = OpenConfigWindow();
  649.             Windows[Id].Window = ConfigWnd;
  650.         break;
  651.  
  652.         default: 
  653.             sprintf(Error_Msg, "Unknown window id %d",  Id);
  654.         Display_Error_Message(Error_Msg);
  655.             CloseStuff();
  656.         exit(1);
  657.  
  658.         } /* switch */    
  659.  
  660.         if (Status != NULL) {
  661.         sprintf(Error_Msg, "Couldn't open window %d, Status = %d", 
  662.                          Id, Status);
  663.         Display_Error_Message(Error_Msg);
  664.             CloseStuff();
  665.             exit(1);     
  666.  
  667.         } /* if */
  668.  
  669.  
  670.     IDCMP_Flags = Windows[Id].Window->IDCMPFlags;
  671.  
  672.         /* Remove and delete the old port:    */
  673.     RemovePort(Windows[Id].Window, TRUE);
  674.  
  675.         /* User same port as main window:    */
  676.     Windows[Id].Window->UserPort = User_Port;
  677.         if (ModifyIDCMP(Windows[Id].Window, IDCMP_Flags) == NULL) {
  678.  
  679.         Display_Error_Message("Couldn't modify IDCMP port\n");
  680.         CloseStuff();
  681.         exit(1);
  682.  
  683.     } /* if */
  684.  
  685.         /* Use same menu as on the main window for all windows */
  686.     SetMenuStrip(Windows[Id].Window, MainMenus);
  687.  
  688.     } /* if .. else .. */
  689.  
  690.     Windows[Id].RastPort = Windows[Id].Window->RPort;
  691.     Windows[Id].ViewPort = ViewPortAddress(Windows[Id].Window);
  692.  
  693.     Set_Normal_Pointer(Id);
  694.  
  695. } /* Window_Open */
  696.  
  697.  
  698.  
  699. void CloseStuff()
  700. /************************************************************************/
  701. /*                                                                      */
  702. /* Close libraries, windows, screens etc.                */
  703. /*                                                                      */
  704. /* Free allocated memory.                        */
  705. /*                                                                      */
  706. /************************************************************************/
  707. {
  708.     Window_Close(W_Config);
  709.     Window_Close(W_ExpandedView);
  710.     Window_Close(W_Move_Group);
  711.     Window_Close(W_Rotate_Group);
  712.     Window_Close(W_Scale_Group);
  713.     Window_Close(W_KnotInfo);
  714.     Window_Close(W_Main);    /* Should always be closed last! */
  715.  
  716.     if (Mouse_Image != NULL) FreeMem(Mouse_Image, Mouse_Image_Size);
  717.     if (Busy_Image != NULL)  FreeMem(Busy_Image, Busy_Image_Size);
  718.     
  719.     CloseDownScreen();
  720.     if (GfxBase)        CloseLibrary((struct Library *) GfxBase);
  721.     if (AslBase)   CloseLibrary((struct Library *) AslBase);
  722.     if (GadToolsBase)   CloseLibrary((struct Library *) GadToolsBase);
  723.     if (IntuitionBase)  CloseLibrary((struct Library *) IntuitionBase);
  724.  
  725.     Splines_Init();
  726.     Render_Cleanup();
  727.  
  728. } /* CloseStuff */
  729.  
  730. void OpenStuff()
  731. /************************************************************************/
  732. /*                                                                      */
  733. /*                                                                      */
  734. /************************************************************************/
  735. {
  736.     long    Status;
  737.  
  738.     Windows_Init();
  739.  
  740.     IntuitionBase = 
  741.           (struct IntuitionBase*)OpenLibrary("intuition.library",37L);
  742.     if (IntuitionBase == NULL) {
  743.     Display_Error_Message("Couldn't open intuition.library");
  744.         CloseStuff();
  745.         exit(1);     
  746.     } /* if */
  747.  
  748.     GadToolsBase = (struct Library *)OpenLibrary("gadtools.library", 37L);
  749.     if (GadToolsBase == NULL) {
  750.     Display_Error_Message("Couldn't open gadtools.library");
  751.         CloseStuff();
  752.         exit(1);     
  753.     } /* if */
  754.  
  755.     AslBase = (struct Library *)OpenLibrary("asl.library", 37L);
  756.     if (AslBase == NULL) {
  757.     Display_Error_Message("Couldn't open asl.library");
  758.         CloseStuff();
  759.         exit(1);     
  760.     } /* if */
  761.  
  762.     GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L);
  763.     if (GfxBase == NULL) {
  764.     Display_Error_Message("Couldn't open graphics.library");
  765.         CloseStuff();
  766.         exit(1);     
  767.     } /* if */
  768.  
  769.     Status = SetupScreen();
  770.     if (Status != NULL) {
  771.         sprintf(Error_Msg, "Couldn't open screen, Status = %d", Status);
  772.     Display_Error_Message(Error_Msg);
  773.     CloseStuff();
  774.     exit(1);
  775.     }
  776.     ShowTitle(Scr, 0L);        /* Put screen title behind backdrop */
  777.  
  778.     Window_Open(W_Main);    /* Should always be opened first ! */
  779.  
  780.     Id_Active_Window = W_Main;
  781.  
  782. } /* OpenStuff */
  783.  
  784.  
  785. void Finish()
  786. /************************************************************************/
  787. /*                                                                      */
  788. /*                                                                      */
  789. /************************************************************************/
  790. {
  791.     struct IntuiMessage *Msg;
  792.  
  793.     while ((Msg = GT_GetIMsg(User_Port)) != NULL) {
  794.  
  795.       GT_ReplyIMsg(Msg);
  796.  
  797.     } /* while */
  798.  
  799.   CloseStuff();
  800.  
  801. } /* Finish */
  802.  
  803. void Clear_All(long What)
  804. /************************************************************************/
  805. /*                                                                      */
  806. /* Clear the drawing area.                        */
  807. /*                                                                      */
  808. /************************************************************************/
  809. {
  810.     SetAPen(Windows[Id_Active_Window].RastPort, Pen_Background);
  811.     SetDrMd(Windows[Id_Active_Window].RastPort, JAM2);
  812.     Windows[Id_Active_Window].RastPort->Mask    = 0xff;
  813.  
  814.     What &= What_Mask;
  815.     if (What & What_X) { 
  816.       RectFill(Windows[Id_Active_Window].RastPort, 
  817.         Views[V_X].X_Min, Views[V_X].Y_Min,
  818.             Views[V_X].X_Max, Views[V_X].Y_Max);
  819.     }
  820.  
  821.     if (What & What_Y) { 
  822.       RectFill(Windows[Id_Active_Window].RastPort, 
  823.         Views[V_Y].X_Min, Views[V_Y].Y_Min,
  824.             Views[V_Y].X_Max, Views[V_Y].Y_Max);
  825.     }
  826.  
  827.     if (What & What_Z) { 
  828.        RectFill(Windows[Id_Active_Window].RastPort, 
  829.         Views[V_Z].X_Min, Views[V_Z].Y_Min,
  830.             Views[V_Z].X_Max, Views[V_Z].Y_Max);
  831.     }
  832.  
  833.     if (What & What_P) { 
  834.        RectFill(Windows[Id_Active_Window].RastPort, 
  835.         Views[V_P].X_Min, Views[V_P].Y_Min,
  836.             Views[V_P].X_Max, Views[V_P].Y_Max);
  837.     }
  838.  
  839. } /* Clear_All */
  840.  
  841. void Clear_Plane(int Plane, long What)
  842. {
  843.     SetAPen(Windows[Id_Active_Window].RastPort, Pen_Background);
  844.     Windows[Id_Active_Window].RastPort->Mask    = 1 << Plane;
  845.     SetDrMd(Windows[Id_Active_Window].RastPort, JAM2);
  846.  
  847.     What &= What_Mask;
  848.  
  849.     if (What & What_X) { 
  850.       RectFill(Windows[Id_Active_Window].RastPort, 
  851.         Views[V_X].X_Min, Views[V_X].Y_Min,
  852.             Views[V_X].X_Max, Views[V_X].Y_Max);
  853.     }
  854.  
  855.     if (What & What_Y) { 
  856.       RectFill(Windows[Id_Active_Window].RastPort, 
  857.         Views[V_Y].X_Min, Views[V_Y].Y_Min,
  858.             Views[V_Y].X_Max, Views[V_Y].Y_Max);
  859.     }
  860.  
  861.     if (What & What_Z) { 
  862.        RectFill(Windows[Id_Active_Window].RastPort, 
  863.         Views[V_Z].X_Min, Views[V_Z].Y_Min,
  864.             Views[V_Z].X_Max, Views[V_Z].Y_Max);
  865.     }
  866.  
  867.     if (What & What_P) { 
  868.        RectFill(Windows[Id_Active_Window].RastPort, 
  869.         Views[V_P].X_Min, Views[V_P].Y_Min,
  870.             Views[V_P].X_Max, Views[V_P].Y_Max);
  871.     }
  872.  
  873. } /* Clear_Plane */
  874.  
  875.  
  876. void Handle_Gadget_Event(struct IntuiMessage *Msg)
  877. /************************************************************************/
  878. /*                                                                      */
  879. /* Dispatcher for gadget events.                    */
  880. /*                                                                      */
  881. /************************************************************************/
  882. {
  883.     struct Gadget *Gad = (struct Gadget *) Msg->IAddress;
  884.  
  885.     if (Msg->Code == 0x09) {            /* TAB */    
  886.     return;
  887.     }
  888.  
  889.     else if (Msg->Code == 0x5f) {        /* HELP */
  890.     return;
  891.     }
  892.  
  893.     switch (Gad->GadgetID) {
  894.  
  895.     case GD_G_X_Expand:
  896.     Command_X_Expand();
  897.     break;
  898.  
  899.     case GD_G_Y_Expand:
  900.     Command_Y_Expand();
  901.     break;
  902.  
  903.     case GD_G_Z_Expand:
  904.     Command_Z_Expand();
  905.     break;
  906.  
  907.     case GD_G_Persp_Expand:
  908.     Command_Persp_Expand();
  909.     break;
  910.  
  911.     case GD_G_Persp_Rotate:
  912.     case GD_G_Persp_Rotate_E:
  913.       Set_Mode_Rotate_P(); 
  914.     break;
  915.  
  916.     case GD_G_Unexpand:
  917.     Command_Unexpand();
  918.         Window_Close(W_ExpandedView);
  919.     break;
  920.  
  921.     /* KnotInfo window:    */
  922.     case GD_G_Tension:
  923.     Handle_G_Tension();
  924.     break;
  925.  
  926.     case GD_G_Tension_Value:
  927.     Handle_G_Tension_Value();
  928.     break;
  929.  
  930.     case GD_G_Bias:
  931.     Handle_G_Bias();
  932.     break;
  933.  
  934.     case GD_G_Bias_Value:
  935.     Handle_G_Bias_Value();
  936.     break;
  937.  
  938.     case GD_G_Continuity:
  939.     Handle_G_Continuity();
  940.     break;
  941.  
  942.     case GD_G_Continuity_Value:
  943.     Handle_G_Continuity_Value();
  944.     break;
  945.  
  946.     /* Scale_Group window:    */
  947.     case GD_Scale_Group_Factor:
  948.     Handle_Scale_Group_Factor();
  949.     break;
  950.  
  951.     case GD_Scale_Group_Factor_Value:
  952.     Handle_Scale_Group_Factor_Value();
  953.     break;
  954.  
  955.     /* Rotate_Group window:    */
  956.     case GD_Rotate_Group_Axis:
  957.     Handle_Rotate_Group_Axis(Msg->Code);
  958.     break;
  959.  
  960.     case GD_Rotate_Group_Angle:
  961.     Handle_Rotate_Group_Angle();
  962.     break;
  963.  
  964.     case GD_Rotate_Group_Angle_Value:
  965.     Handle_Rotate_Group_Angle_Value();
  966.     break;
  967.  
  968.     /* Move_Group window:    */
  969.     case GD_Move_Group_X_Value:
  970.     Handle_Move_Group_X_Value();
  971.     break;
  972.  
  973.     case GD_Move_Group_Y_Value:
  974.     Handle_Move_Group_Y_Value();
  975.     break;
  976.  
  977.     case GD_Move_Group_Z_Value:
  978.     Handle_Move_Group_Z_Value();
  979.     break;
  980.  
  981.     case GD_Move_Group_Move:
  982.     Handle_Move_Group_Move();
  983.     break;
  984.  
  985.  
  986.     } /* switch */
  987.  
  988. } /* Handle_Gadget_Event */
  989.  
  990.  
  991. void Handle_Menu_Event(struct IntuiMessage *Msg)
  992. /************************************************************************/
  993. /*                                                                      */
  994. /* Dispatcher for menu events.                        */
  995. /*                                                                      */
  996. /************************************************************************/
  997. {
  998.     UWORD MenuNumber;
  999.     UWORD ItemNumber;
  1000.     UWORD SubNumber;
  1001.  
  1002.     if (Msg->Code == MENUNULL) return;
  1003.  
  1004.     MenuNumber = MENUNUM(Msg->Code);
  1005.     ItemNumber = ITEMNUM(Msg->Code);
  1006.     SubNumber  = SUBNUM(Msg->Code);
  1007.  
  1008.     switch (MenuNumber) {
  1009.  
  1010.     case 0:                    /* PROJECT    */
  1011.     switch (ItemNumber) {
  1012.  
  1013.     case 0:                    /* About    */
  1014.           Command_About();
  1015.         break;
  1016.  
  1017.     case 1:                    /* New        */
  1018.           Command_New(); 
  1019.         break;
  1020.  
  1021.     case 2:                    /* Load        */
  1022.         switch (SubNumber) {
  1023.         case 0:                /* Icoons obj.    */
  1024.               Command_Load_Object(); 
  1025.             break;
  1026.         case 1:                /* JMan  obj.    */
  1027.               Command_Load_JMan_Object(); 
  1028.             break;
  1029.         } /* switch (SubNumber) */
  1030.         break;
  1031.  
  1032.     case 3:                    /* Save        */
  1033.           Command_Save_Object(); 
  1034.         break;
  1035.  
  1036.     case 4:                    /* Generate    */
  1037.         switch (SubNumber) { 
  1038.         case 0:                /* TTDDD    */
  1039.               Command_Generate_TTDDD_File(); 
  1040.         break;
  1041.  
  1042.         } /* switch */
  1043.         break;
  1044.  
  1045.     case 5:                    /* Configuration*/
  1046.         switch (SubNumber) {
  1047.  
  1048.         case 0:                /* Load        */
  1049.         Command_Load_Config();
  1050.         break;
  1051.  
  1052.         case 1:                /* Save        */
  1053.         Command_Save_Config();
  1054.         break;
  1055.  
  1056.         case 2:                /* Edit        */
  1057.         Edit_Configuration();
  1058.         break;
  1059.  
  1060.         } /* switch (SubNumber) */
  1061.         break;
  1062.  
  1063.     case 6:                    /* Quit        */
  1064.           Command_Quit(); 
  1065.         break;
  1066.  
  1067.     } /* switch (ItemNumber) */
  1068.     break;
  1069.  
  1070.  
  1071.     case 1:                    /* DISPLAY     */
  1072.     switch (ItemNumber) {
  1073.  
  1074.     case 0:                    /* Zoom in    */
  1075.           Command_ZoomIn(); 
  1076.         break;
  1077.  
  1078.     case 1:                    /* Zoom out    */
  1079.           Command_ZoomOut(); 
  1080.         break;
  1081.  
  1082.     case 2:                    /* Center    */
  1083.           Set_Mode_Center(); 
  1084.         break;
  1085.  
  1086.     case 3:                    /* Rotate P.    */
  1087.           Set_Mode_Rotate_P(); 
  1088.         break;
  1089.  
  1090.     case 4:                    /* Pan        */
  1091.           Set_Mode_Pan(); 
  1092.         break;
  1093.  
  1094.     case 5:                    /* Grid     */
  1095.           Grid_Active = !Grid_Active;
  1096.             Redraw_Mask |= What_All;
  1097.         break;
  1098.  
  1099.     case 6:                    /* Grid snap    */
  1100.           Grid_Snap_Active = !Grid_Snap_Active;
  1101.         break;
  1102.  
  1103.         case 7:                    /* Resolution    */
  1104.         switch (SubNumber) {
  1105.         case 0:                /* Up        */
  1106.         Command_Resolution_Up();
  1107.         break;
  1108.  
  1109.         case 1:                /* Down        */
  1110.         Command_Resolution_Down();
  1111.         break;
  1112.  
  1113.         } /* switch */
  1114.         break;
  1115.  
  1116.     case 8:                    /* Redraw    */
  1117.             Redraw_Mask |= What_All;
  1118.         break;
  1119.  
  1120.     } /* switch (ItemNumber) */
  1121.     break;
  1122.  
  1123.     case 2:                    /* WINDOWS     */
  1124.     switch (ItemNumber) {
  1125.  
  1126.     case 0:                    /* Knot      */
  1127.           Command_Show_KnotInfo(); 
  1128.         break;
  1129.  
  1130.     case 1:                    /* Scale G      */
  1131.           Command_Scale_Group(); 
  1132.         break;
  1133.  
  1134.     case 2:                    /* Rotate G      */
  1135.           Command_Rotate_Group(); 
  1136.         break;
  1137.  
  1138.     case 3:                    /* Move G     */
  1139.           Command_Move_Group(); 
  1140.         break;
  1141.  
  1142.     } /* switch (ItemNumber) */
  1143.     break;
  1144.  
  1145.     case 3:                    /* RENDER    */
  1146.     switch (ItemNumber) {
  1147.  
  1148.     case 0:                    /* Mode        */
  1149.         switch (SubNumber) {
  1150.     
  1151.         case 0:                /* Line        */
  1152.         Rendering_Mode = RM_Line;
  1153.         break;
  1154.  
  1155.         case 1:                /* Flat        */
  1156.         Rendering_Mode = RM_Flat;
  1157.         break;
  1158.  
  1159.         case 2:                /* Gouraud    */
  1160.         Rendering_Mode = RM_Gouraud;
  1161.         break;
  1162.  
  1163.         case 3:                /* Phong    */
  1164.         Rendering_Mode = RM_Phong;
  1165.         break;
  1166.  
  1167.         } /* switch */
  1168.         break;
  1169.  
  1170.     case 1:                    /* Render    */
  1171.         Render_Tesselate_Object();    
  1172.         break;
  1173.  
  1174.     case 2:                    /* Re-render    */
  1175.         Render_Object();    
  1176.         break;
  1177.  
  1178.     } /* switch (ItemNumber) */
  1179.     break;
  1180.  
  1181.     case 4:                    /* Select    */
  1182.     switch (ItemNumber) {
  1183.     case 0:                    /* Toggle Group    */
  1184.         Set_Mode_Group();
  1185.         break;
  1186.  
  1187.     case 1:                    /* Toggle Spline*/
  1188.         Command_Toggle_Select_Spline();
  1189.         break;
  1190.  
  1191.     case 2:                    /* Toggle All    */
  1192.         Command_Toggle_Select_All();
  1193.         break;
  1194.  
  1195.     case 3:                    /* Knot        */
  1196.         if (Select_Point_Id >= 0) {
  1197.         Group_Mode = TRUE;
  1198.         Set_Window_Title(NULL);
  1199.         } /* if */
  1200.         break;
  1201.  
  1202.     case 4:                    /* Next        */
  1203.         Command_Select_Next();
  1204.         break;
  1205.  
  1206.     case 5:                    /* Deselect all    */
  1207.         Command_Deselect_All();
  1208.         break;
  1209.  
  1210.     } /* switch (ItemNumber) */
  1211.     break;
  1212.  
  1213.     case 5:                    /* Commands    */
  1214.     switch (ItemNumber) {
  1215.  
  1216.     case 0:                    /* Add        */
  1217.         Command_Add();
  1218.         break;
  1219.  
  1220.     case 1:                    /* Combine    */
  1221.         Command_Combine();
  1222.         break;
  1223.  
  1224.     case 2:                    /* Cut        */
  1225.         Command_Cut();
  1226.         break;
  1227.  
  1228.     case 3:                    /* Delete    */
  1229.         Command_Delete();
  1230.         break;
  1231.  
  1232.     case 4:                    /* Disconnect    */
  1233.         Command_Disconnect();
  1234.         break;
  1235.  
  1236.     case 5:                    /* Hide        */
  1237.         Command_Hide();
  1238.         break;
  1239.  
  1240.     case 6:                    /* Move origin    */
  1241.         Set_Mode_Origin();
  1242.         break;
  1243.  
  1244.     } /* switch (ItemNumber) */
  1245.     break;
  1246.  
  1247.     } /* switch (MenuNum) */
  1248.  
  1249.  
  1250. } /* Handle_Menu_Event */
  1251.  
  1252. void Check_Event()
  1253. /************************************************************************/
  1254. /*                                                                      */
  1255. /* Check for an event and handle it.                    */
  1256. /*                                                                      */
  1257. /************************************************************************/
  1258. {
  1259.     struct         IntuiMessage *Msg_Ptr;
  1260.     struct         IntuiMessage Msg;
  1261.     struct         Gadget *Gad;
  1262.     Boolean_T        Event_Used;
  1263.  
  1264.     WaitPort(User_Port);
  1265.  
  1266.     while ((Msg_Ptr = GT_GetIMsg(User_Port)) != NULL) {
  1267.  
  1268.     Msg = *Msg_Ptr;
  1269.     
  1270.         GT_ReplyIMsg(Msg_Ptr);
  1271.  
  1272.         switch (Msg.Class) {
  1273.  
  1274.     case IDCMP_INTUITICKS:
  1275.         if (Handle_IntuiTick_Message(&Msg)) State.Timeout();
  1276.         break;
  1277.  
  1278.     case IDCMP_REFRESHWINDOW:
  1279.         GT_BeginRefresh(Msg.IDCMPWindow);
  1280.         if (Msg.IDCMPWindow == Windows[W_Main].Window) MainRender();
  1281.         if (Msg.IDCMPWindow == Windows[W_Config].Window) ConfigRender();
  1282.         GT_EndRefresh(Msg.IDCMPWindow, TRUE);
  1283.         break;
  1284.  
  1285.     case IDCMP_CLOSEWINDOW:
  1286.         if (Msg.IDCMPWindow == Windows[W_Main].Window) {
  1287.  
  1288.         Command_Quit();
  1289.  
  1290.         } else if (Msg.IDCMPWindow == Windows[W_KnotInfo].Window) {
  1291.  
  1292.             Window_Close(W_KnotInfo);
  1293.  
  1294.         } else if (Msg.IDCMPWindow == Windows[W_Scale_Group].Window) {
  1295.  
  1296.             Window_Close(W_Scale_Group);
  1297.  
  1298.         } else if (Msg.IDCMPWindow == Windows[W_Rotate_Group].Window) {
  1299.  
  1300.             Window_Close(W_Rotate_Group);
  1301.  
  1302.         } else if (Msg.IDCMPWindow == Windows[W_Move_Group].Window) {
  1303.  
  1304.             Window_Close(W_Move_Group);
  1305.  
  1306.         } else if (Msg.IDCMPWindow == Windows[W_ExpandedView].Window) {
  1307.         
  1308.         Command_Unexpand();
  1309.             Window_Close(W_ExpandedView);
  1310.  
  1311.         } else if (Msg.IDCMPWindow == Windows[W_Config].Window) {
  1312.         
  1313.             Window_Close(W_Config);
  1314.  
  1315.         } /* if */
  1316.         break;
  1317.  
  1318.     case IDCMP_GADGETUP:
  1319.     case IDCMP_GADGETDOWN:
  1320.         Handle_Gadget_Event(&Msg);
  1321.         break;
  1322.  
  1323.     case IDCMP_MENUPICK:
  1324.         Handle_Menu_Event(&Msg);
  1325.         break;
  1326.  
  1327.     default:
  1328.         Event_Used = State.Handle_Event(&Msg);
  1329.  
  1330.             if (Event_Used) break;
  1331.         if (Msg.Class == IDCMP_MOUSEBUTTONS && 
  1332.             Msg.Code == SELECTUP) Set_Mode_Normal();
  1333.         break;
  1334.  
  1335.     } /* switch */
  1336.  
  1337.     } /* while */
  1338.  
  1339.     if (Redraw_Mask) {
  1340.  
  1341.         State.Redraw(Redraw_Mask);
  1342.         Redraw_Mask = 0;
  1343.  
  1344.     } /* if */
  1345.  
  1346. } /* Check_Event */
  1347.  
  1348. int Wait_For_Key()
  1349. /************************************************************************/
  1350. /*                                                                      */
  1351. /* Wait until the user presses a key, and return it.            */
  1352. /*                                                                      */
  1353. /************************************************************************/
  1354. {
  1355.     struct         IntuiMessage *Msg_Ptr;
  1356.     struct         IntuiMessage Msg;
  1357.  
  1358.     for (;;) {
  1359.  
  1360.         WaitPort(User_Port);
  1361.  
  1362.         while ((Msg_Ptr = GT_GetIMsg(User_Port)) != NULL) {
  1363.  
  1364.         Msg = *Msg_Ptr;
  1365.     
  1366.             GT_ReplyIMsg(Msg_Ptr);
  1367.  
  1368.             if (Msg.Class == IDCMP_VANILLAKEY) return((int) Msg.Code);
  1369.  
  1370.         } /* while */
  1371.  
  1372.     }  /* for (;;) */
  1373.  
  1374. } /* Wait_For_Key */
  1375.