home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / atccnr.zip / atccnr.c next >
C/C++ Source or Header  |  1993-10-12  |  28KB  |  868 lines

  1. /*
  2.  
  3.     AIR TRAFFIC CONTROL CONTAINER
  4.  
  5.     This sample demonstrates the following:
  6.  
  7.         Multiple Container views
  8.         Inserting multiple container records
  9.         Explicitly positioning records
  10.         Enumerating container contents
  11.         Using a PM Timer to move the container objects at regular intervals
  12.         Multiple context menus
  13.         Container background owner-drawing
  14.         Bitmaps for screen drawing performance
  15.         Randomly generating aircraft (always good to know)
  16.  
  17.     See online help for more information.
  18.  
  19.     Dave Briccetti              Phone: 510 945-7565
  20.     Dave Briccetti & Assoc.     Fax: 510 945-7436
  21.     P.O. Box 1713               CIS: 74475,1072
  22.     Lafayette, CA 94549-7013    Internet: daveb@netcom.com
  23.  
  24.     Copyright (c) David C. Briccetti, 1993
  25.     All rights reserved.
  26.  
  27.     Dave Briccetti has been developing OS/2 applications on a consulting
  28.     basis since 1987, and specializes in PM user interfaces.
  29.  
  30. */
  31.  
  32. #define INCL_PM
  33. #include <os2.h>
  34.  
  35. #include "atccnr.h"
  36. #include "help.h"
  37.  
  38. #include <assert.h>
  39. #include <malloc.h>
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <time.h>
  44.  
  45.  
  46. /*
  47.  *  AIRCRAFT CONTAINER RECORD STRUCTURE
  48.  */
  49.  
  50. typedef struct _APPCNRREC     // acr
  51. {
  52.     MINIRECORDCORE  recc;
  53.     LONG            iRecord;            // Index of container record
  54.     LONG            Altitude;           // Aircraft attributes
  55.     LONG            Heading;            // ...
  56.     LONG            Speed;
  57.     LONG            AssignedAltitude;
  58.     LONG            AssignedHeading;
  59.     LONG            AssignedSpeed;
  60.     PSZ             pszCallsign;
  61. } APPCNRREC, *PAPPCNRREC;
  62.  
  63.  
  64. /*
  65.  *  APPLICATION WINDOW "INSTANCE" DATA
  66.  */
  67.  
  68. typedef struct _INST     // inst
  69. {
  70.     HAB             hab;                // Anchor block handle for application
  71.     HPS             hpsMemRadar;        // Memory PS where Radar bitmap stored
  72.     HDC             hdcMem;             // Memory DC where Radar bitmap stored
  73.     HBITMAP         hbmRadar;           // Radar screen bitmap
  74.     HWND            hwndCnr;            // Container window handle
  75.     HWND            hwndAircraftMenu;   // Aircraft manipulation menu
  76.     HWND            hwndContainerMenu;  // Container manipulation menu
  77.     PAPPCNRREC      pacrSelected;       // Ptr to selected container record
  78.     LONG            CurrentView;        // Current view (IDMVIEW_ICON, etc.)
  79. }   INST, *PINST;
  80.  
  81.  
  82. /*
  83.  *  FUNCTION DECLARATIONS
  84.  */
  85.  
  86. static FNWP AirTrafficControlDlg;
  87. static INT InsertContainerColumns (PINST pinst);
  88. static INT InsertContainerRecords (PINST pinst);
  89. static PSZ SetRecordText (PAPPCNRREC pacr);
  90. static PFNWP pfnwpCnr;
  91. static FNWP CnrSubclassWndProc;
  92. static MRESULT EXPENTRY ControlInstructionDlg (HWND hwnd, ULONG msg,
  93.     MPARAM mp1, MPARAM mp2);
  94. static BOOL ManeuverAircraft (PAPPCNRREC pacrTraverse);
  95. static HBITMAP CreateBitmap (HPS hpsMem, PRECTL prclTargetWnd);
  96. static INT CreateMemoryPS (PINST pinstMain, HPS hpsTarget,
  97.     PRECTL prclTargetWnd);
  98. static INT
  99. DrawBitmap
  100. (
  101.     PINST           pinstMain,
  102.     HPS             hpsTarget,
  103.     PRECTL          prclTargetWndDraw
  104. );
  105.  
  106.  
  107. /*
  108.  *  CONSTANTS AND MACROS
  109.  */
  110.  
  111. #define IDTIMER_ADJUSTAIRCRAFT              100
  112. #define AIRCRAFT_ADJUST_FREQUENCY           1000    // milliseconds
  113.  
  114. #define FIRST_CNR_ITEM(hwnd) WinSendMsg (hwnd, CM_QUERYRECORD, \
  115.     0, MPFROM2SHORT (CMA_FIRST,CMA_ITEMORDER))
  116.  
  117. #define NEXT_CNR_ITEM(hwnd,prev) WinSendMsg (hwnd, CM_QUERYRECORD, \
  118.     MPFROMP (prev), MPFROM2SHORT (CMA_NEXT,CMA_ITEMORDER))
  119.  
  120.  
  121.  
  122. /*
  123.  *  MAIN FUNCTION
  124.  */
  125.  
  126. int main( void )
  127. {
  128.     HAB     hab;
  129.     HMQ     hmq;
  130.     HWND    hwndHelpInstance;   /* Handle to Help window    */
  131.     HWND    hwndDlg;            // Main dlg window
  132.     static SWCNTRL swctl;
  133.  
  134.  
  135.     freopen ("err", "w", stderr);
  136.  
  137.     assert (hab = WinInitialize (0));
  138.     assert (hmq = WinCreateMsgQueue (hab, 0));
  139.  
  140.     // Load main application dialog
  141.     hwndDlg = WinLoadDlg (HWND_DESKTOP, HWND_DESKTOP,
  142.         AirTrafficControlDlg, 0, IDDLG_CNRSAMP, 0);
  143.  
  144.     swctl.hwnd = hwndDlg;
  145.     strcpy( swctl.szSwtitle, "Air Traffic Control Container" );
  146.     WinAddSwitchEntry( &swctl );
  147.  
  148.     hwndHelpInstance = InitializeHelp (hab, hwndDlg, IDDLG_CNRSAMP,
  149.         (PSZ) "atccnr.HLP", (
  150.         PSZ) "Air Traffic Control Container Help Window", 0);
  151.  
  152.     WinProcessDlg (hwndDlg);
  153.  
  154.     if (hwndHelpInstance)
  155.         WinDestroyHelpInstance (hwndHelpInstance);
  156.  
  157.     WinDestroyWindow (hwndDlg);
  158.  
  159.     WinDestroyMsgQueue (hmq);
  160.     WinTerminate (hab);
  161.  
  162.     return 0;
  163. }
  164.  
  165.  
  166.  
  167. /*
  168.  *  DIALOG PROCEDURE FOR MAIN APPLICATION WINDOW
  169.  */
  170.  
  171. MRESULT EXPENTRY AirTrafficControlDlg (HWND hwnd, ULONG msg,
  172.     MPARAM mp1, MPARAM mp2)
  173. {
  174.     PINST   pinst;
  175.  
  176.     pinst = WinQueryWindowPtr(hwnd,QWL_USER);
  177.  
  178.     switch (msg)
  179.     {
  180.         case WM_INITDLG:
  181.         {
  182.             /*
  183.              *  INITIALIZE APPLICATION
  184.              */
  185.  
  186.             CNRINFO     ccinfo;         // Container info structure
  187.  
  188.             // Initialize instance data
  189.             pinst = calloc (1, sizeof *pinst);
  190.             WinSetWindowPtr(hwnd,QWL_USER,pinst);
  191.             pinst->hwndCnr = WinWindowFromID (hwnd, IDCNR_SAMPLE);
  192.             pinst->hab     = WinQueryAnchorBlock (hwnd);
  193.             pinst->hwndAircraftMenu =               // Load aircraft menu
  194.                 WinLoadMenu( hwnd, 0, IDMENU_AIRCRAFT);
  195.             pinst->hwndContainerMenu =              // Load container menu
  196.                 WinLoadMenu( hwnd, 0, IDMENU_CONTAINER);
  197.             pinst->CurrentView = IDMVIEW_RADAR;
  198.  
  199.             // Set container info to request owner background painting
  200.             memset (&ccinfo, 0, sizeof ccinfo);
  201.             ccinfo.flWindowAttr = CA_OWNERPAINTBACKGROUND;
  202.             WinSendMsg (pinst->hwndCnr, CM_SETCNRINFO, &ccinfo,
  203.                 MPFROMLONG(CMA_FLWINDOWATTR));
  204.  
  205.             // Subclass container window to provide background painting
  206.             pfnwpCnr = WinSubclassWindow (pinst->hwndCnr,
  207.                 CnrSubclassWndProc);
  208.             assert (pfnwpCnr);
  209.  
  210.             // Insert the columns into the container
  211.             InsertContainerColumns (pinst);
  212.  
  213.             // Insert the initial records into the container
  214.             InsertContainerRecords (pinst);
  215.  
  216.             // Start a timer to control aircraft
  217.             WinStartTimer (pinst->hab, hwnd,
  218.                 IDTIMER_ADJUSTAIRCRAFT, AIRCRAFT_ADJUST_FREQUENCY);
  219.  
  220.             // The container is ready for viewing
  221.             WinShowWindow (pinst->hwndCnr, TRUE);
  222.  
  223.             return 0;
  224.         }
  225.  
  226.         case WM_TIMER:
  227.  
  228.             /*
  229.              *  DO TIME-RELATED AIRCRAFT HANDLING
  230.              */
  231.  
  232.             if (SHORT1FROMMP (mp1) == IDTIMER_ADJUSTAIRCRAFT)
  233.             {
  234.                 PAPPCNRREC      pacrTraverse;
  235.  
  236.                 // Loop through all container records
  237.                 for (pacrTraverse = (PAPPCNRREC)
  238.                     FIRST_CNR_ITEM (pinst->hwndCnr);
  239.                     pacrTraverse;
  240.                     pacrTraverse = (PAPPCNRREC)
  241.                     NEXT_CNR_ITEM(pinst->hwndCnr,pacrTraverse))
  242.                 {
  243.                     BOOL        fInvalid = FALSE;
  244.  
  245.                     if (pinst->CurrentView == IDMVIEW_RADAR)
  246.                     {
  247.                         /* Erase the record from previous location. */
  248.                         WinSendMsg (pinst->hwndCnr, CM_ERASERECORD,
  249.                             MPFROMP(pacrTraverse), NULL);
  250.                     }
  251.  
  252.                     // Maneuver the aircraft
  253.                     if (ManeuverAircraft (pacrTraverse))
  254.                     {
  255.                         // Update aircraft text if necessary
  256.                         SetRecordText (pacrTraverse);
  257.                         fInvalid = TRUE;
  258.                     }
  259.  
  260.                     if (fInvalid || pinst->CurrentView == IDMVIEW_RADAR)
  261.                         /* Paint the record in its new position */
  262.                         WinSendMsg (pinst->hwndCnr, CM_INVALIDATERECORD,
  263.                             MPFROMP(&pacrTraverse),
  264.                             MPFROMSHORT(1));
  265.                 }
  266.             }
  267.  
  268.             return 0;
  269.  
  270.  
  271.         case WM_CONTROL:
  272.             if (SHORT1FROMMP (mp1) == IDCNR_SAMPLE)
  273.                 switch (SHORT2FROMMP (mp1))
  274.                 {
  275.                     case CN_CONTEXTMENU:
  276.                     {
  277.                         /*
  278.                          *  MENU HANDLING
  279.                          */
  280.  
  281.                         POINTL  ptlMouse;
  282.                         HWND    hwndMenu;
  283.  
  284.                         WinQueryMsgPos (pinst->hab, &ptlMouse);
  285.  
  286.                         // Save pointer to record mouse is over, if any
  287.                         pinst->pacrSelected = (PAPPCNRREC) mp2;
  288.  
  289.                         hwndMenu = pinst->pacrSelected ?
  290.                             pinst->hwndAircraftMenu :
  291.                             pinst->hwndContainerMenu;
  292.  
  293.                         // Display menu
  294.                         WinPopupMenu (HWND_DESKTOP, hwnd, hwndMenu,
  295.                             ptlMouse.x, ptlMouse.y, 0,
  296.                             PU_HCONSTRAIN | PU_VCONSTRAIN |
  297.                             PU_KEYBOARD | PU_MOUSEBUTTON1 |
  298.                             PU_MOUSEBUTTON2 |
  299.                             PU_MOUSEBUTTON3);
  300.                     }
  301.                 }
  302.             return 0;
  303.  
  304.  
  305.         case WM_COMMAND:
  306.  
  307.             /*
  308.              *  COMMAND HANDLING
  309.              */
  310.  
  311.             switch (SHORT1FROMMP (mp1))
  312.             {
  313.                 case IDMAIRCRAFT_CONTROLINSTRUCT:   // Issue instruction
  314.                 {
  315.                     // Present "Control Aircraft" dialog
  316.                     WinDlgBox (HWND_DESKTOP, hwnd,
  317.                         ControlInstructionDlg, 0,
  318.                         IDDLG_CONTROLAIRCRAFT, pinst);
  319.                     return 0;
  320.                 }
  321.  
  322.                 case IDMVIEW_RADAR:
  323.                 case IDMVIEW_NAME:
  324.                 case IDMVIEW_DETAILS:
  325.                 case IDMVIEW_TEXT:
  326.                 {
  327.                     static const ULONG  aViews [] =
  328.                         { CV_ICON, CV_NAME, CV_DETAIL, CV_TEXT };
  329.  
  330.                     CNRINFO ccinfo;
  331.                     memset (&ccinfo, 0, sizeof ccinfo);
  332.                     ccinfo.flWindowAttr = CA_DETAILSVIEWTITLES |
  333.                         CA_TITLESEPARATOR |
  334.                         CA_OWNERPAINTBACKGROUND |
  335.                         aViews [SHORT1FROMMP (mp1) - IDMVIEW_BASE];
  336.                     WinSendMsg (pinst->hwndCnr, CM_SETCNRINFO, &ccinfo,
  337.                         MPFROMLONG(CMA_FLWINDOWATTR));
  338.                     pinst->CurrentView = SHORT1FROMMP (mp1);
  339.  
  340.                     WinInvalidateRect (pinst->hwndCnr, 0, 0);
  341.                     return 0;
  342.                 }
  343.             }
  344.  
  345.             return WinDefDlgProc (hwnd, msg, mp1, mp2);
  346.  
  347.         default:
  348.             return WinDefDlgProc (hwnd, msg, mp1, mp2);
  349.     }
  350. }
  351.  
  352.  
  353.  
  354.  
  355.  
  356. /*
  357.  *  INSERT COLUMNS INTO CONTAINER
  358.  */
  359.  
  360. static INT InsertContainerColumns (PINST pinst)
  361. {
  362.     PFIELDINFO      pfldinfo;
  363.     PFIELDINFO      pfldinfoFirst;
  364.     FIELDINFOINSERT fiins;
  365.     LONG            iField = 0;
  366.     static const FIELDINFO afldinfo[] =
  367.     {
  368.         {0, CFA_STRING | CFA_FIREADONLY | CFA_HORZSEPARATOR | CFA_LEFT,
  369.          CFA_LEFT | CFA_FITITLEREADONLY, "Call sign",
  370.          FIELDOFFSET(APPCNRREC,pszCallsign), 0, 0, 0},
  371.         {0, CFA_ULONG | CFA_FIREADONLY | CFA_HORZSEPARATOR | CFA_LEFT,
  372.          CFA_LEFT | CFA_FITITLEREADONLY, "Heading",
  373.          FIELDOFFSET(APPCNRREC,Heading), 0, 0, 0},
  374.         {0, CFA_ULONG | CFA_FIREADONLY | CFA_HORZSEPARATOR | CFA_LEFT,
  375.          CFA_LEFT | CFA_FITITLEREADONLY, "Assigned\nHeading",
  376.          FIELDOFFSET(APPCNRREC,AssignedHeading), 0, 0, 0},
  377.         {0, CFA_ULONG | CFA_FIREADONLY | CFA_HORZSEPARATOR | CFA_LEFT,
  378.          CFA_LEFT | CFA_FITITLEREADONLY, "Altitude\n(Hundreds\nof Feet)",
  379.          FIELDOFFSET(APPCNRREC,Altitude), 0, 0, 0},
  380.         {0, CFA_ULONG | CFA_FIREADONLY | CFA_HORZSEPARATOR | CFA_LEFT,
  381.          CFA_LEFT | CFA_FITITLEREADONLY,
  382.          "Assigned\nAltitude\n(Hundreds\nof Feet)",
  383.          FIELDOFFSET(APPCNRREC,AssignedAltitude), 0, 0, 0},
  384.         {0, CFA_ULONG | CFA_FIREADONLY | CFA_HORZSEPARATOR | CFA_LEFT,
  385.          CFA_LEFT | CFA_FITITLEREADONLY, "Speed\n(Tens of\nknots)",
  386.          FIELDOFFSET(APPCNRREC,Speed), 0, 0, 0},
  387.         {0, CFA_ULONG | CFA_FIREADONLY | CFA_HORZSEPARATOR | CFA_LEFT,
  388.          CFA_LEFT | CFA_FITITLEREADONLY, "Assigned\nSpeed\n(Tens of\nknots",
  389.          FIELDOFFSET(APPCNRREC,AssignedSpeed), 0, 0, 0}
  390.     };
  391.     static const INT cFields = sizeof afldinfo / sizeof afldinfo[0];
  392.  
  393.     pfldinfo = pfldinfoFirst = WinSendMsg (pinst->hwndCnr,
  394.         CM_ALLOCDETAILFIELDINFO,
  395.         MPFROMLONG(cFields), NULL);
  396.  
  397.     for (iField = 0; iField < cFields; ++iField)
  398.     {
  399.         pfldinfo->cb         = sizeof(FIELDINFO);
  400.         pfldinfo->flData     = afldinfo [iField].flData;
  401.         pfldinfo->flTitle    = afldinfo [iField].flTitle;
  402.         pfldinfo->pTitleData = afldinfo [iField].pTitleData;
  403.         pfldinfo->offStruct  = afldinfo [iField].offStruct;
  404.         pfldinfo = pfldinfo->pNextFieldInfo;
  405.     }
  406.  
  407.     fiins.cb = sizeof fiins;
  408.     fiins.pFieldInfoOrder = (PFIELDINFO)CMA_FIRST;
  409.     fiins.cFieldInfoInsert = cFields;
  410.     fiins.fInvalidateFieldInfo = TRUE;
  411.  
  412.     /*
  413.      *  INSERT DETAIL VIEW INFORMATION
  414.      */
  415.  
  416.     WinSendMsg (pinst->hwndCnr, CM_INSERTDETAILFIELDINFO,
  417.         MPFROMP(pfldinfoFirst), MPFROMP(&fiins));
  418.  
  419.  
  420.     return 0;
  421. }
  422.  
  423.  
  424.  
  425. /*
  426.  *  INSERT AIRCRAFT INTO RADAR SCREEN CONTAINER
  427.  */
  428.  
  429. static INT InsertContainerRecords (PINST pinst)
  430. {
  431.     PAPPCNRREC      pacrRoot;           // Ptr to root of list of records
  432.     PAPPCNRREC      pacrTraverse;       // Ptr to traverse list of records
  433.     RECORDINSERT    recins;             // Record insertion information
  434.     HPOINTER        hptrIcon;           // Handle of jet icon
  435.     RECTL           rclCnr;             // Container dimensions
  436.     LONG            iRecord = 0;        // Record index
  437.     static const PSZ apszCallSignPrefixes [] =
  438.         { "AA", "DA", "UA", "TW" };
  439.     static const INT cPrefixes = sizeof apszCallSignPrefixes /
  440.         sizeof apszCallSignPrefixes[0];
  441.     CHAR            szBuf [30];
  442.  
  443.     /*
  444.      *  SET UP RECORD INSERT STRUCTURE
  445.      */
  446.  
  447.     memset (&recins, 0, sizeof recins);
  448.     recins.cb                = sizeof recins;
  449.     recins.pRecordOrder      = (PRECORDCORE) CMA_END;
  450.     recins.zOrder            = CMA_TOP;
  451.     recins.cRecordsInsert    = 5;
  452.     recins.fInvalidateRecord = TRUE;
  453.  
  454.  
  455.     /*
  456.      *  ALLOCATE CONTAINER ITEM LINKED LIST
  457.      */
  458.  
  459.     pacrRoot = (PAPPCNRREC) WinSendMsg (
  460.         pinst->hwndCnr, CM_ALLOCRECORD,
  461.         MPFROMLONG(sizeof(APPCNRREC) - sizeof(MINIRECORDCORE)),
  462.         MPFROMLONG(recins.cRecordsInsert));
  463.  
  464.  
  465.     /*
  466.      *  SET UP USER RECORD LINKED LIST
  467.      */
  468.  
  469.     hptrIcon = WinLoadPointer (HWND_DESKTOP, 0, IDICON_JET);
  470.     WinQueryWindowRect (pinst->hwndCnr, &rclCnr);
  471.     srand (clock());
  472.  
  473.  
  474.     for (iRecord = 0, pacrTraverse = pacrRoot;
  475.         iRecord < recins.cRecordsInsert;
  476.         ++iRecord, pacrTraverse = (PAPPCNRREC)
  477.         pacrTraverse->recc.preccNextRecord)
  478.     {
  479.         pacrTraverse->iRecord       = iRecord;
  480.         pacrTraverse->Altitude      =
  481.         pacrTraverse->AssignedAltitude = rand() % 50 + 50;
  482.         pacrTraverse->Heading       =
  483.         pacrTraverse->AssignedHeading  = rand() % 360 + 1;
  484.         pacrTraverse->Speed         =
  485.         pacrTraverse->AssignedSpeed = rand() % 20 + 10;
  486.         sprintf (szBuf, "%s%ld",
  487.             apszCallSignPrefixes [rand() % cPrefixes], rand() % 1000);
  488.         pacrTraverse->pszCallsign   = strdup (szBuf);
  489.  
  490.         SetRecordText (pacrTraverse);
  491.         pacrTraverse->recc.hptrIcon = hptrIcon;
  492.         pacrTraverse->recc.ptlIcon.x = rclCnr.xRight / 10 * (rand() % 9 + 1);
  493.         pacrTraverse->recc.ptlIcon.y = rclCnr.yTop   / 10 * (rand() % 9 + 1);
  494.     }
  495.  
  496.  
  497.     /*
  498.      *  INSERT ALL CONTAINER ITEMS
  499.      */
  500.  
  501.     WinSendMsg (pinst->hwndCnr, CM_INSERTRECORD,
  502.         MPFROMP(pacrRoot), MPFROMP(&recins));
  503.  
  504.     /*
  505.      *  DESELECT FIRST AIRPLANE, WHICH BECOMES SELECTED AUTOMATICALLY
  506.      */
  507.  
  508.     WinSendMsg (pinst->hwndCnr, CM_SETRECORDEMPHASIS,
  509.         MPFROMP(pacrRoot), MPFROM2SHORT(FALSE, CRA_SELECTED));
  510.  
  511.     return 0;
  512. }
  513.  
  514.  
  515.  
  516. /*
  517.  *  GENERATE THE TEXT FOR THE AIRCRAFT'S RADAR DISPLAY, BASED ON ITS
  518.  *  CURRENT ATTRIBUTES
  519.  */
  520.  
  521. static PSZ SetRecordText (PAPPCNRREC pacr)
  522. {
  523.     CHAR    szBuf [40];
  524.  
  525.     if (pacr->recc.pszIcon)
  526.         free (pacr->recc.pszIcon);
  527.  
  528.     sprintf (szBuf, "%s\n%3ld %2ld", pacr->pszCallsign,
  529.         pacr->Altitude, pacr->Speed);
  530.  
  531.     return pacr->recc.pszIcon = strdup (szBuf);
  532. }
  533.  
  534.  
  535.  
  536. /*
  537.  *  DIALOG FOR ISSUING CONTROL INSTRUCTIONS TO AN AIRCRAFT
  538.  */
  539.  
  540. static MRESULT EXPENTRY ControlInstructionDlg (HWND hwnd, ULONG msg,
  541.     MPARAM mp1, MPARAM mp2)
  542. {
  543.     PINST   pinstMain;      // Ptr to main application instance data
  544.  
  545.     pinstMain = WinQueryWindowPtr(hwnd,QWL_USER);
  546.  
  547.     switch (msg)
  548.     {
  549.         case WM_INITDLG:
  550.         {
  551.             // A ptr to main application instance data is passed to
  552.             // this dialog.  Store it in our QWL_USER data.
  553.             pinstMain = PVOIDFROMMP (mp2);
  554.             WinSetWindowPtr(hwnd,QWL_USER,pinstMain);
  555.  
  556.             // Set the limits for the spin controls
  557.             WinSendDlgItemMsg (hwnd, IDSPB_HEADING,
  558.                 SPBM_SETLIMITS, MPFROMLONG (360), MPFROMLONG (1));
  559.             WinSendDlgItemMsg (hwnd, IDSPB_ALTITUDE,
  560.                 SPBM_SETLIMITS, MPFROMLONG (500), MPFROMLONG (10));
  561.             WinSendDlgItemMsg (hwnd, IDSPB_SPEED,
  562.                 SPBM_SETLIMITS, MPFROMLONG (100), MPFROMLONG (5));
  563.  
  564.             // Set current values for the spin controls
  565.             WinSendDlgItemMsg (hwnd, IDSPB_HEADING,
  566.                 SPBM_SETCURRENTVALUE,
  567.                 MPFROMLONG (pinstMain->pacrSelected->Heading), 0);
  568.             WinSendDlgItemMsg (hwnd, IDSPB_ALTITUDE,
  569.                 SPBM_SETCURRENTVALUE,
  570.                 MPFROMLONG (pinstMain->pacrSelected->Altitude), 0);
  571.             WinSendDlgItemMsg (hwnd, IDSPB_SPEED,
  572.                 SPBM_SETCURRENTVALUE,
  573.                 MPFROMLONG (pinstMain->pacrSelected->Speed), 0);
  574.  
  575.             return 0;
  576.         }
  577.  
  578.         case WM_COMMAND:
  579.             switch (SHORT1FROMMP (mp1))
  580.             {
  581.                 case DID_OK:
  582.                 {
  583.                     // Get current values for the spin controls
  584.                     WinSendDlgItemMsg (hwnd, IDSPB_HEADING,
  585.                         SPBM_QUERYVALUE,
  586.                         MPFROMLONG (&pinstMain->pacrSelected->
  587.                             AssignedHeading), 0);
  588.                     WinSendDlgItemMsg (hwnd, IDSPB_ALTITUDE,
  589.                         SPBM_QUERYVALUE,
  590.                         MPFROMLONG (&pinstMain->pacrSelected->
  591.                             AssignedAltitude), 0);
  592.                     WinSendDlgItemMsg (hwnd, IDSPB_SPEED,
  593.                         SPBM_QUERYVALUE,
  594.                         MPFROMLONG (&pinstMain->pacrSelected->
  595.                             AssignedSpeed), 0);
  596.  
  597.                     break;
  598.                 }
  599.             }
  600.  
  601.             return WinDefDlgProc (hwnd, msg, mp1, mp2);
  602.  
  603.         default:
  604.             return WinDefDlgProc (hwnd, msg, mp1, mp2);
  605.     }
  606. }
  607.  
  608.  
  609.  
  610. /*
  611.  *  MAKE THE PLANES FLY!
  612.  */
  613.  
  614. static BOOL ManeuverAircraft (PAPPCNRREC pacrTraverse)
  615. {
  616.     BOOL    fManeuverRequired = FALSE;
  617.  
  618.     if (pacrTraverse->AssignedHeading !=
  619.         pacrTraverse->Heading)
  620.     {
  621.         BOOL    fTurningRight =
  622.             pacrTraverse->AssignedHeading >
  623.             pacrTraverse->Heading;
  624.         pacrTraverse->Heading +=
  625.             (fTurningRight ? 1 : -1);
  626.         fManeuverRequired = TRUE;
  627.     }
  628.  
  629.     if (pacrTraverse->AssignedAltitude !=
  630.         pacrTraverse->Altitude)
  631.     {
  632.         BOOL    fAscending =
  633.             pacrTraverse->AssignedAltitude >
  634.             pacrTraverse->Altitude;
  635.         pacrTraverse->Altitude +=
  636.             (fAscending ? 1 : -1);
  637.         fManeuverRequired = TRUE;
  638.     }
  639.  
  640.     if (pacrTraverse->AssignedSpeed !=
  641.         pacrTraverse->Speed)
  642.     {
  643.         BOOL    fAccelerating =
  644.             pacrTraverse->AssignedSpeed >
  645.             pacrTraverse->Speed;
  646.         pacrTraverse->Speed +=
  647.             (fAccelerating ? 1 : -1);
  648.         fManeuverRequired = TRUE;
  649.     }
  650.  
  651.     if (pacrTraverse->Heading > 45 &&
  652.         pacrTraverse->Heading < 135)
  653.         pacrTraverse->recc.ptlIcon.x++;
  654.     else
  655.         if (pacrTraverse->Heading > 225 &&
  656.             pacrTraverse->Heading < 315)
  657.             pacrTraverse->recc.ptlIcon.x--;
  658.  
  659.     if (pacrTraverse->Heading > 315 &&
  660.         pacrTraverse->Heading < 45)
  661.         pacrTraverse->recc.ptlIcon.y++;
  662.     else
  663.         if (pacrTraverse->Heading > 135 &&
  664.             pacrTraverse->Heading < 225)
  665.             pacrTraverse->recc.ptlIcon.y--;
  666.  
  667.     return fManeuverRequired;
  668. }
  669.  
  670.  
  671.  
  672. /*
  673.  *  DRAW THE RADAR SCREEN (THE CONTAINER BACKGROUND)
  674.  */
  675.  
  676. static MRESULT EXPENTRY CnrSubclassWndProc
  677. (
  678.     HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2
  679. )
  680. {
  681.     if (msg == CM_PAINTBACKGROUND)
  682.     {
  683.         POWNERBACKGROUND    pownbckg = mp1;
  684.         RECTL               rclCnr;
  685.         PINST               pinstMain;
  686.  
  687.         pinstMain = WinQueryWindowPtr
  688.             (WinQueryWindow (hwnd, QW_OWNER), QWL_USER);
  689.  
  690.         if (pinstMain->CurrentView != IDMVIEW_RADAR)
  691.             return FALSE;
  692.  
  693.         WinQueryWindowRect (hwnd, &rclCnr);
  694.  
  695.         /*
  696.          *  The radar screen is drawn once into a bitmap and
  697.          *  subsequently GpiBitBlt'd onto the screen
  698.          */
  699.  
  700.         if (! pinstMain->hbmRadar)
  701.         {
  702.             RECTL               rclRunway;
  703.             LONG                cxRunway;
  704.             LONG                cyRunway;
  705.             ARCPARAMS           arcp;           // arc parameters
  706.             POINTL              ptlScreenMidpoint;
  707.             POINTL              ptlMarkerMidpoint;
  708.             INT                 RadiusMultiplier;
  709.  
  710.             CreateMemoryPS (pinstMain, pownbckg->hps, &rclCnr);
  711.             pinstMain->hbmRadar =
  712.                 CreateBitmap (pinstMain->hpsMemRadar, &rclCnr);
  713.  
  714.             WinFillRect (pinstMain->hpsMemRadar, &rclCnr,
  715.                 CLR_DARKGREEN);
  716.  
  717.             ptlScreenMidpoint.x = rclCnr.xRight / 2;
  718.             ptlScreenMidpoint.y = rclCnr.yTop / 2;
  719.  
  720.  
  721.             /*
  722.              * Draw runway
  723.              */
  724.  
  725.             cxRunway          = rclCnr.xRight / 60;
  726.             cyRunway          = rclCnr.yTop / 10;
  727.             rclRunway.xLeft   = ptlScreenMidpoint.x - cxRunway / 2;
  728.             rclRunway.xRight  = rclRunway.xLeft + cxRunway;
  729.             rclRunway.yBottom = ptlScreenMidpoint.y - cyRunway / 2;
  730.             rclRunway.yTop    = rclRunway.yBottom + cyRunway;
  731.             WinFillRect (pinstMain->hpsMemRadar, &rclRunway, CLR_WHITE);
  732.  
  733.  
  734.             /*
  735.              * Draw approach outer marker (3 elipses)
  736.              */
  737.  
  738.             ptlMarkerMidpoint.x = ptlScreenMidpoint.x;
  739.             ptlMarkerMidpoint.y = ptlScreenMidpoint.y - rclCnr.yTop / 6;
  740.             GpiMove (pinstMain->hpsMemRadar, &ptlMarkerMidpoint);
  741.  
  742.             arcp.lP = rclCnr.xRight / 20;
  743.             arcp.lQ = rclCnr.yTop / 80;
  744.             arcp.lR = arcp.lS = 0L;
  745.             GpiSetArcParams(pinstMain->hpsMemRadar,&arcp);
  746.             GpiSetColor (pinstMain->hpsMemRadar, CLR_WHITE);
  747.             GpiFullArc (pinstMain->hpsMemRadar, DRO_OUTLINE, MAKEFIXED(1,0));
  748.  
  749.             arcp.lP =
  750.             arcp.lQ = rclCnr.yTop / 60;
  751.             arcp.lR = arcp.lS = 0L;
  752.             GpiSetArcParams(pinstMain->hpsMemRadar,&arcp);
  753.             GpiSetColor (pinstMain->hpsMemRadar, CLR_WHITE);
  754.             GpiFullArc (pinstMain->hpsMemRadar, DRO_OUTLINE, MAKEFIXED(1,0));
  755.  
  756.             arcp.lP =
  757.             arcp.lQ = 1;
  758.             arcp.lR = arcp.lS = 0L;
  759.             GpiSetArcParams(pinstMain->hpsMemRadar,&arcp);
  760.             GpiSetColor (pinstMain->hpsMemRadar, CLR_WHITE);
  761.             GpiFullArc (pinstMain->hpsMemRadar, DRO_OUTLINE, MAKEFIXED(1,0));
  762.  
  763.  
  764.             /*
  765.              * Draw distance rings concentric circles
  766.              */
  767.  
  768.             GpiMove (pinstMain->hpsMemRadar, &ptlScreenMidpoint);
  769.             arcp.lP = arcp.lQ = min (rclCnr.xRight, rclCnr.yTop) / 9;
  770.             arcp.lR = arcp.lS = 0L;
  771.             GpiSetArcParams(pinstMain->hpsMemRadar,&arcp);
  772.  
  773.             GpiSetColor (pinstMain->hpsMemRadar, CLR_BLACK);
  774.  
  775.             for (RadiusMultiplier = 1; RadiusMultiplier <= 4; ++RadiusMultiplier)
  776.                 GpiFullArc(pinstMain->hpsMemRadar,DRO_OUTLINE,
  777.                     MAKEFIXED(RadiusMultiplier,0));
  778.         }
  779.  
  780.         DrawBitmap (pinstMain, pownbckg->hps, &pownbckg->rclBackground);
  781.  
  782.         return (MRESULT) TRUE;
  783.     }
  784.     else
  785.         return pfnwpCnr (hwnd, msg, mp1, mp2);
  786. }
  787.  
  788.  
  789.  
  790.  
  791. static INT
  792. DrawBitmap
  793. (
  794.     PINST           pinstMain,
  795.     HPS             hpsTarget,
  796.     PRECTL          prclTargetWndDraw
  797. )
  798. {
  799.     POINTL            ptl[3];                 // point definitions
  800.  
  801.     //
  802.     // Copy the bitmap into the window. Prepare the coordinates and sizes.
  803.     //
  804.     memset (ptl, 0, sizeof ptl);
  805.     ptl[0].x = prclTargetWndDraw->xLeft;
  806.     ptl[0].y = prclTargetWndDraw->yBottom;
  807.     ptl[1].x = prclTargetWndDraw->xRight;
  808.     ptl[1].y = prclTargetWndDraw->yTop;
  809.     ptl[2].x = prclTargetWndDraw->xLeft;
  810.     ptl[2].y = prclTargetWndDraw->yBottom;
  811.  
  812.     GpiBitBlt(hpsTarget,pinstMain->hpsMemRadar,3L,
  813.         ptl,ROP_SRCCOPY,BBO_IGNORE);
  814.  
  815.    return 0;                                        // done ok
  816. }
  817.  
  818.  
  819. static INT CreateMemoryPS (PINST pinstMain, HPS hpsTarget,
  820.     PRECTL prclTargetWnd)
  821. {
  822.     SIZEL   sizl;
  823.     HDC     hdcTarget = GpiQueryDevice(hpsTarget);
  824.  
  825.     pinstMain->hdcMem = DevOpenDC(pinstMain->hab,OD_MEMORY,"*",
  826.         0L,NULL,hdcTarget);
  827.     assert (pinstMain->hdcMem != DEV_ERROR);
  828.  
  829.     //
  830.     // Set the size of the presentation space to be created.
  831.     //
  832.     sizl.cx = prclTargetWnd->xRight;
  833.     sizl.cy = prclTargetWnd->yTop;
  834.  
  835.     //
  836.     // Create the memory presentation space for the bitmap.
  837.     //
  838.     pinstMain->hpsMemRadar = GpiCreatePS(pinstMain->hab,
  839.        pinstMain->hdcMem,&sizl,
  840.        PU_PELS | GPIA_ASSOC | GPIT_MICRO);
  841.     assert (pinstMain->hpsMemRadar != GPI_ERROR);
  842.  
  843.     return 0;
  844. }
  845.  
  846.  
  847. static HBITMAP CreateBitmap (HPS hpsMem, PRECTL prclTargetWnd)
  848. {
  849.     LONG        lFormats[24];              // bitmap data formats
  850.     BITMAPINFOHEADER2 bmp;                       // bitmap info header
  851.     HBITMAP         hbm;
  852.  
  853.     GpiQueryDeviceBitmapFormats( hpsMem, 24L, lFormats );
  854.     memset( &bmp, 0, sizeof bmp);
  855.     bmp.cbFix      = sizeof bmp;          // size of the header
  856.     bmp.cx         = prclTargetWnd->xRight;
  857.     bmp.cy         = prclTargetWnd->yTop;
  858.     bmp.cPlanes    = (USHORT)lFormats[0];  // planes
  859.     bmp.cBitCount  = (USHORT)lFormats[1];  // bit count
  860.  
  861.     hbm = GpiCreateBitmap(hpsMem,&bmp,0,NULL,NULL);
  862.     assert (hbm != GPI_ERROR);
  863.  
  864.     GpiSetBitmap(hpsMem,hbm);
  865.  
  866.     return hbm;
  867. }
  868.