home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / windows / element3.zip / ELEMENT3.C < prev    next >
C/C++ Source or Header  |  1991-02-16  |  20KB  |  734 lines

  1. //
  2. // Periodic table of the elements, for Microsoft Windows 3.0.
  3. // Originally written by Gregory A. Jones, uunet!microsoft!gregj.
  4. // Extensively modified by Charles L. Perrin as a Windows learning project. 
  5. //
  6.  
  7. // This program may be freely distributed.
  8.  
  9. // Chemical data culled from reference works, including the
  10. //    CRC Handbook of Chemistry and Physics.
  11.  
  12. #include <windows.h>
  13. #include "element3.h"
  14.  
  15. //
  16. // Prototypes for functions.
  17. //
  18.  
  19. long FAR PASCAL WndProc(HWND, unsigned, WORD, LONG);
  20. BOOL FAR PASCAL BoxProcessor(HWND,unsigned,WORD,LONG);
  21. void ElementDisplay(HDC);
  22.  
  23. //
  24. // A few global variables.
  25. //
  26.  
  27. char szAppName [] = "Element3";
  28. char szMainMenu [] = "mainmenu";
  29. char szAccTable [] = "mainaccel";
  30. char szHint [] = "HINT:  Point at an element with the mouse.";
  31. char szElement [80];
  32. FARPROC lpBoxHandler;
  33. HANDLE ghInstance, hWhiteBrush, hAccTable, hClipboard;
  34. LPSTR lpszClipboard;
  35. WORD cxBox, cyBox;
  36. int i, iElementOld;
  37. BOOL fThawing, fFreezing, fFrozen;
  38. RECT rect;
  39.  
  40. //
  41. // Data stored for each element.  Includes name, symbol, atomic weight,
  42. // and location in table (where period one is row 0, family 1a is column 0).
  43. // Atomic number is implicit, since the table is ordered by it.
  44. //
  45.  
  46. typedef struct tagELEMENT {
  47.     char *pszName;      // Name of the element, i.e. "Hydrogen"
  48.     char *pszSymbol;    // Symbol, i.e. "He"
  49.     char *pszWeight;    // Atomic weight, i.e. "(230)"
  50.     WORD wColumn;       // Column number to draw in
  51.     WORD wRow;          // Row number to draw in
  52. } ELEMENT;
  53.  
  54. typedef ELEMENT *PELEMENT;
  55.  
  56. //
  57. // Width and height of the table, and number of elements defined.
  58. //
  59.  
  60. #define NUM_COLUMNS     18
  61. #define NUM_ROWS        10
  62. #define MAX_ELEMENTS    106
  63.  
  64. //
  65. // Titles for the families, by column.  Null strings are because "8"
  66. // really covers three columns.
  67. //
  68.  
  69. char *pszTitles [NUM_COLUMNS] = {
  70. "1a", "2a", "3b", "4b", "5b", "6b", "7b", "", "8", "", "1b", "2b",
  71. "3a", "4a", "5a", "6a", "7a", "0"
  72. };
  73.  
  74. //
  75. // The elements themselves.  Add new ones on the end if you discover them.
  76. // Also, don't forget to set MAX_ELEMENTS to the new value!
  77. //
  78.  
  79. ELEMENT elTable [MAX_ELEMENTS] = {
  80. "Hydrogen", "H", "1.0079", 0, 0,
  81. "Helium", "He", "4.00260", 17, 0,
  82. "Lithium", "Li", "6.94", 0, 1,
  83. "Beryllium", "Be", "9.01218", 1, 1,
  84. "Boron", "B", "10.81", 12, 1,
  85. "Carbon", "C", "12.011", 13, 1,
  86. "Nitrogen", "N", "14.0067", 14, 1,
  87. "Oxygen", "O", "15.9994", 15, 1,
  88. "Fluorine", "F", "18.998403", 16, 1,
  89. "Neon", "Ne", "20.17", 17, 1,
  90. "Sodium", "Na", "22.98977", 0, 2,
  91. "Magnesium", "Mg", "24.305", 1, 2,
  92. "Aluminum", "Al", "26.98154", 12, 2,
  93. "Silicon", "Si", "28.0855", 13, 2,
  94. "Phosphorous", "P", "30.97376", 14, 2,
  95. "Sulfur", "S", "32.06", 15, 2,
  96. "Chlorine", "Cl", "35.453", 16, 2,
  97. "Argon", "Ar", "39.948", 17, 2,
  98. "Potassium", "K", "39.0983", 0, 3,
  99. "Calcium", "Ca", "40.08", 1, 3,
  100. "Scandium", "Sc", "44.9559", 2, 3,
  101. "Titanium", "Ti", "47.90", 3, 3,
  102. "Vanadium", "V", "50.9415", 4, 3,
  103. "Chromium", "Cr", "51.996", 5, 3,
  104. "Manganese", "Mn", "54.9380", 6, 3,
  105. "Iron", "Fe", "55.847", 7, 3,
  106. "Cobalt", "Co", "58.9332", 8, 3,
  107. "Nickel", "Ni", "58.71", 9, 3,
  108. "Copper", "Cu", "63.546", 10, 3,
  109. "Zinc", "Zn", "65.38", 11, 3,
  110. "Gallium", "Ga", "69.735", 12, 3,
  111. "Germanium", "Ge", "72.59", 13, 3,
  112. "Arsenic", "As", "74.9216", 14, 3,
  113. "Selenium", "Se", "78.96", 15, 3,
  114. "Bromium", "Br", "79.904", 16, 3,
  115. "Krypton", "Kr", "83.80", 17, 3,
  116. "Rubidium", "Rb", "85.467", 0, 4,
  117. "Strontium", "Sr", "87.62", 1, 4,
  118. "Yttrium", "Y", "88.9059", 2, 4,
  119. "Zirconium", "Zr", "91.22", 3, 4,
  120. "Niobium", "Nb", "92.9064", 4, 4,
  121. "Molybdenum", "Mo", "95.94", 5, 4,
  122. "Technetium", "Tc", "98.9062", 6, 4,
  123. "Ruthenium", "Ru", "101.07", 7, 4,
  124. "Rhodium", "Rh", "102.9055", 8, 4,
  125. "Palladium", "Pd", "106.4", 9, 4,
  126. "Silver", "Ag", "107.868", 10, 4,
  127. "Cadmium", "Cd", "112.41", 11, 4,
  128. "Indium", "In", "114.82", 12, 4,
  129. "Tin", "Sn", "118.69", 13, 4,
  130. "Antimony", "Sb", "121.75", 14, 4,
  131. "Tellurium", "Te", "127.60", 15, 4,
  132. "Iodine", "I", "126.9045", 16, 4,
  133. "Xenon", "Xe", "131.30", 17, 4,
  134. "Cesium", "Cs", "132.9054", 0, 5,
  135. "Barium", "Ba", "137.33", 1, 5,
  136. "Lanthanum", "La", "138.9055", 2, 5,
  137. "Cerium", "Ce", "140.12", 2, 8,
  138. "Praeseodymium", "Pr", "140.9077", 3, 8,
  139. "Neodymium", "Nd", "144.24", 4, 8,
  140. "Promethium", "Pm", "(145)", 5, 8,
  141. "Samarium", "Sm", "150.4", 6, 8,
  142. "Europium", "Eu", "151.96", 7, 8,
  143. "Gadolinium", "Gd", "157.25", 8, 8,
  144. "Terbium", "Tb", "158.9254", 9, 8,
  145. "Dysprosium", "Dy", "162.50", 10, 8,
  146. "Holmium", "Ho", "164.9304", 11, 8,
  147. "Erbium", "Er", "167.26", 12, 8,
  148. "Thulium", "Tm", "168.9342", 13, 8,
  149. "Ytterbium", "Yb", "173.04", 14, 8,
  150. "Lutetium", "Lu", "174.96", 15, 8,
  151. "Hafnium", "Hf", "178.49", 3, 5,
  152. "Tantalum", "Ta", "180.947", 4, 5,
  153. "Tungsten", "W", "183.85", 5, 5,
  154. "Rhenium", "Re", "186.207", 6, 5,
  155. "Osmium", "Os", "190.2", 7, 5,
  156. "Iridium", "Ir", "192.22", 8, 5,
  157. "Platinum", "Pt", "195.09", 9, 5,
  158. "Gold", "Au", "196.9665", 10, 5,
  159. "Mercury", "Hg", "200.59", 11, 5,
  160. "Thallium", "Tl", "204.37", 12, 5,
  161. "Lead", "Pb", "207.2", 13, 5,
  162. "Bismuth", "Bi", "208.9804", 14, 5,
  163. "Polonium", "Po", "(209)", 15, 5,
  164. "Astatine", "At", "(210)", 16, 5,
  165. "Radon", "Rn", "(222)", 17, 5,
  166. "Francium", "Fr", "(223)", 0, 6,
  167. "Radium", "Ra", "226.0254", 1, 6,
  168. "Actinium", "Ac", "(227)", 2, 6,
  169. "Thorium", "Th", "232.0381", 2, 9,
  170. "Protactinium", "Pa", "231.0359", 3, 9,
  171. "Uranium", "U", "238.029", 4, 9,
  172. "Neptunium", "Np", "237.0482", 5, 9,
  173. "Plutonium", "Pu", "(244)", 6, 9,
  174. "Americium", "Am", "(243)", 7, 9,
  175. "Curium", "Cm", "(247)", 8, 9,
  176. "Berkelium", "Bk", "(247)", 9, 9,
  177. "Calfornium", "Cf", "(251)", 10, 9,
  178. "Einsteinium", "Es", "(254)", 11, 9,
  179. "Fermium", "Fm", "(257)", 12, 9,
  180. "Mendelevium", "Md", "(258)", 13, 9,
  181. "Nobelium", "No", "(259)", 14, 9,
  182. "Lawrencium", "Lr", "(260)", 15, 9,
  183. "Rutherfordium", "Rf", "(260)", 3, 6,
  184. "Hahnium", "Ha", "(260)", 4, 6,
  185. "Not Named Yet", "106", "(263)", 5, 6
  186. };
  187.  
  188. //
  189. // Main entry point for this application.
  190. //
  191.  
  192. int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
  193.                         LPSTR lpszCmdLine, int nCmdShow)
  194. {
  195.     HWND hWnd;
  196.     MSG msg;
  197.     int nWidth, nHeight;
  198.     WNDCLASS wndclass;
  199.  
  200.     //
  201.     // Save handle instance globally.
  202.     //
  203.  
  204.     ghInstance = hInstance;
  205.  
  206.     //
  207.     // Register the window class for this application.
  208.     //
  209.  
  210.     if (!hPrevInstance) {
  211.         wndclass.style = CS_VREDRAW | CS_HREDRAW | CS_SAVEBITS;
  212.         wndclass.lpfnWndProc = WndProc;
  213.         wndclass.cbClsExtra = 0;
  214.         wndclass.cbWndExtra = 0;
  215.         wndclass.hInstance = hInstance;
  216.         wndclass.hIcon = LoadIcon (hInstance, "mainicon");
  217.         wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
  218.         wndclass.hbrBackground = GetStockObject (WHITE_BRUSH);
  219.         wndclass.lpszMenuName = szMainMenu;
  220.         wndclass.lpszClassName = szAppName;
  221.  
  222.         if (!RegisterClass (&wndclass))
  223.             return FALSE;
  224.     }
  225.  
  226.     //
  227.     // Create a white background for future use.
  228.     //
  229.         
  230.     hWhiteBrush = GetStockObject(WHITE_BRUSH);
  231.     
  232.     //
  233.     // Load the keyboard accelerator table.
  234.     //
  235.     
  236.     hAccTable = LoadAccelerators(hInstance,szAccTable);
  237.         
  238.     //
  239.     // Set old element number to cause display on first entry.
  240.     // Set up initial hint text.
  241.     // Set flag to indicate element change is not frozen.
  242.     //
  243.         
  244.     iElementOld = MAX_ELEMENTS + 1;
  245.     lstrcpy(szElement,szHint);
  246.     fFrozen = FALSE;
  247.     
  248.     //
  249.     // Calculate a width of screen width.
  250.     //
  251.     
  252.     nWidth = GetSystemMetrics(SM_CXSCREEN);
  253.     
  254.     //
  255.     // Calculate a height of screen height less twice icon height.
  256.     //
  257.     
  258.     nHeight = GetSystemMetrics(SM_CYSCREEN) - GetSystemMetrics(SM_CYICON) * 2;
  259.         
  260.     //
  261.     // Create and display the main window.
  262.     //
  263.  
  264.     hWnd = CreateWindow (szAppName, "Periodic Table", WS_OVERLAPPED |
  265.                         WS_CAPTION | WS_THICKFRAME | WS_SYSMENU |
  266.                         WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
  267.                         0, 0, nWidth, nHeight, NULL, NULL,
  268.                         hInstance, NULL);
  269.     if (!hWnd) return FALSE;
  270.  
  271.     ShowWindow (hWnd, nCmdShow);
  272.     UpdateWindow (hWnd);
  273.  
  274.     //
  275.     // The world-famous Microsoft Windows message loop with accelerators.
  276.     // By the time you get your first WinApp working, you will be seeing
  277.     // messages in your sleep!
  278.     //
  279.  
  280.     while (GetMessage (&msg, NULL, 0, 0)) {
  281.     
  282.     //
  283.     // If it's not an accelerator key, translate and dispatch!
  284.     //
  285.     
  286.         if (!TranslateAccelerator(hWnd,hAccTable,&msg))
  287.         {
  288.           TranslateMessage (&msg);
  289.           DispatchMessage (&msg);
  290.         }
  291.     }
  292.  
  293.     //
  294.     // Return control to caller (Windows).
  295.     //
  296.  
  297.     return msg.wParam;
  298. }
  299.  
  300. //
  301. // This module displays the element text in the proper size and color.
  302. //
  303.  
  304. void ElementDisplay(hDC)
  305. HDC hDC;
  306.  
  307. {
  308.  
  309.     // 
  310.     // Calculate bounding box for the DrawText operation (the area that is
  311.     // between Hydrogen and Helium with a 1-pixel border).
  312.     //
  313.  
  314.     rect.left = ( elTable[0].wColumn + 1 ) * cxBox + 21;
  315.     rect.right = elTable[1].wColumn * cxBox + 19;
  316.     rect.top = elTable[0].wRow  * cyBox + 40;
  317.     rect.bottom = rect.top + cyBox - 1;
  318.  
  319.     //
  320.     // Fill the element text area with the background.
  321.     //
  322.  
  323.     FillRect(hDC,&rect,hWhiteBrush);
  324.  
  325.     // 
  326.     // Switch text color to blue if frozen, or red if not frozen.
  327.     //
  328.         
  329.     if (fFrozen) SetTextColor(hDC,RGB(0,0,255));
  330.             else SetTextColor(hDC,RGB(255,0,0));
  331.     
  332.     //
  333.     // Display the element text, clipped, centered.
  334.     //
  335.         
  336.     DrawText(hDC,szElement,-1,&rect,DT_CENTER | DT_VCENTER);
  337.             
  338.     //  
  339.     // Switch text color back to black.
  340.     //
  341.                 
  342.     SetTextColor(hDC,RGB(0,0,0));
  343.     
  344. }    
  345.  
  346. //
  347. // AboutBox and HelpBox (only the box changes) dialog box function.
  348. //
  349.  
  350. BOOL FAR PASCAL BoxProcessor(hDlg,message,wParam,lParam)
  351. HWND hDlg;
  352. unsigned message;
  353. WORD wParam;
  354. LONG lParam;
  355.  
  356. {
  357.  
  358. //
  359. // What type of message was encountered?
  360. //
  361.  
  362.     switch (message) {
  363.     
  364.     // 
  365.     // No steps required to initialize dialog.
  366.     // However, it must be indicated that the dialog is initialized.
  367.     //
  368.     
  369.         case WM_INITDIALOG:
  370.              return (TRUE);
  371.         
  372.     //
  373.     // Process command keys germane to the dialog box.
  374.     //
  375.     
  376.         case WM_COMMAND:
  377.     
  378.     //
  379.     // Was the command key "OK" or "Cancel"?
  380.     //
  381.     
  382.         if (wParam == IDOK || wParam ==IDCANCEL) {
  383.     
  384.         //
  385.         // End the dialog and indicate that keys accepted.
  386.         //
  387.         
  388.             EndDialog(hDlg,TRUE);
  389.             return(TRUE);
  390.             
  391.         }
  392.     
  393.     //
  394.     // No processing required for any other function.    
  395.     //
  396.  
  397.     }
  398.     
  399.     return(FALSE);        
  400.  
  401. }
  402.  
  403. //
  404. // Main window function.
  405. //
  406.  
  407. long FAR PASCAL WndProc (HWND hWnd, unsigned iMessage, WORD wParam, LONG lParam)
  408. {
  409.     static WORD cxClient, cyClient;
  410.     WORD cyChar, xBox, yBox;
  411.     PAINTSTRUCT ps;
  412.     HDC hDC;
  413.     PELEMENT pel;
  414.     char buf [10];
  415.     RECT rect;
  416.     
  417.     // 
  418.     // Clear the "freezing" and "thawing" flags.
  419.     //
  420.     
  421.     fFreezing = FALSE;
  422.     fThawing = FALSE;
  423.     
  424.     switch (iMessage) {
  425.     
  426.             // 
  427.             // Accept the four defined messages.
  428.             //
  429.             
  430.         case WM_COMMAND:
  431.         
  432.             switch (wParam) {
  433.             
  434.                //
  435.                // Did the user request an Exit?
  436.                //
  437.             
  438.                case ID_EXIT:
  439.                
  440.                //
  441.                // Request Windows to nuke the window.
  442.                //
  443.                
  444.                PostQuitMessage(0);
  445.                break;
  446.                
  447.                //
  448.                // Did the user request the element data be placed on the clipboard?
  449.                //
  450.                
  451.                case ID_COPY:
  452.                
  453.                //
  454.                // Get a global block of memory for clipboard use.
  455.                //
  456.                
  457.                hClipboard = GlobalAlloc(GHND,(DWORD)128);
  458.                
  459.                //
  460.                // Convert the handle to a pointer.
  461.                //
  462.                
  463.                lpszClipboard = GlobalLock(hClipboard);
  464.                
  465.                //
  466.                // Store the current line in the clipboard block.
  467.                //
  468.                
  469.                wsprintf(lpszClipboard,"%s\n",(LPSTR)szElement);
  470.                
  471.                //
  472.                // Unlock the clipboard memory block by handle.
  473.                //
  474.                
  475.                GlobalUnlock(hClipboard);
  476.                
  477.                //
  478.                // Transfer the clipboard memory block to the clipboard.
  479.                //
  480.                
  481.                OpenClipboard(hWnd);
  482.                EmptyClipboard();
  483.                SetClipboardData(CF_TEXT,hClipboard);               
  484.                CloseClipboard();
  485.                
  486.                //
  487.                // Clipboard functions complete!
  488.                //               
  489.                
  490.                break; 
  491.                
  492.                //
  493.                // This logic handles the "Help Screen" function.
  494.                //
  495.                
  496.                case ID_HELP:
  497.                
  498.                //
  499.                // Get the famous "instance thunk" pointing to the BoxProcessor.
  500.                //
  501.                
  502.                lpBoxHandler = MakeProcInstance(BoxProcessor,ghInstance);
  503.                
  504.                //
  505.                // Set up the dialog box.
  506.                //
  507.                
  508.                DialogBox(ghInstance,"HelpBox",hWnd,lpBoxHandler);
  509.                
  510.                //
  511.                // Discard the instance thunk.
  512.                //
  513.                
  514.                FreeProcInstance(lpBoxHandler);
  515.                
  516.                //
  517.                // Help functions complete!
  518.                //
  519.                
  520.                break;
  521.                
  522.                //
  523.                // This logic sequence handles "About Element3...".
  524.                //
  525.                
  526.                case ID_ABOUT:    
  527.                
  528.                //
  529.                // Get the famous "instance thunk" pointing to the BoxProcessor.
  530.                //
  531.                
  532.                lpBoxHandler = MakeProcInstance(BoxProcessor,ghInstance);
  533.                
  534.                //
  535.                // Set up the dialog box.
  536.                //
  537.                
  538.                DialogBox(ghInstance,"AboutBox",hWnd,lpBoxHandler);
  539.                
  540.                //
  541.                // Discard the instance thunk.
  542.                //
  543.                
  544.                FreeProcInstance(lpBoxHandler);
  545.                
  546.                //
  547.                // About functions complete!
  548.                //
  549.                
  550.                break;
  551.     
  552.             }
  553.             
  554.             //
  555.             // Command functions complete
  556.             //
  557.             
  558.             break;
  559.     
  560.         case WM_SIZE:
  561.  
  562.             //
  563.             // When the window changes size, update static variables
  564.             // containing the window size and size of each box.
  565.             //
  566.  
  567.             cxClient = LOWORD (lParam);
  568.             cyClient = HIWORD (lParam);
  569.             cxBox = (cxClient - 40) / NUM_COLUMNS;
  570.             cyBox = (cyClient - 60) / NUM_ROWS;
  571.             break;
  572.             
  573.         case WM_LBUTTONUP:
  574.         
  575.             // 
  576.             // Handle the case when the user released any mouse button.
  577.             //
  578.             
  579.             //
  580.             // Set flags to indicate freezing or thawing status.
  581.             //
  582.             
  583.             fThawing = fFrozen;
  584.             fFreezing = !fThawing;
  585.  
  586.         case WM_MOUSEMOVE:
  587.  
  588.             //
  589.             // Mouse motion has occurred.  Where is that dirty rat?
  590.             //
  591.             
  592.             //
  593.             // Are we not frozen or thawing out?
  594.             //
  595.             
  596.             if (fThawing || !fFrozen) {
  597.  
  598.                 //
  599.                 // Set frozen flag if we're in the process of freezing.
  600.                 //
  601.                
  602.                 fFrozen = fFreezing;
  603.         
  604.                 //
  605.                 // Convert the mouse location to a corresponding element box.
  606.                 //
  607.  
  608.                 xBox = (LOWORD (lParam) - 20) / cxBox;
  609.                 yBox = (HIWORD (lParam) - 40) / cyBox;
  610.  
  611.                 //  
  612.                 // Scan the element table to determine which box holds the mouse.
  613.                 //
  614.  
  615.                 for (i=0; i<MAX_ELEMENTS; i++)
  616.                     if (elTable [i].wColumn == xBox &&
  617.                         elTable [i].wRow == yBox)
  618.                         break;
  619.  
  620.                 //
  621.                 // Did the element number or status change?
  622.                 //
  623.  
  624.                 if ((i != iElementOld) | fFreezing | fThawing) {
  625.  
  626.                 //
  627.                 // Save the old element number.
  628.                 //
  629.         
  630.                 iElementOld = i;
  631.  
  632.                 //
  633.                 // Build a string to indicate which element is selected.
  634.                 //
  635.  
  636.                 if (i < MAX_ELEMENTS)
  637.                     wsprintf(szElement,"Element %u - %s(%s) - Atomic Weight %s",i+1,
  638.                        (LPSTR)elTable[i].pszName,
  639.                        (LPSTR)elTable[i].pszSymbol,
  640.                        (LPSTR)elTable[i].pszWeight);
  641.                 else
  642.                     lstrcpy(szElement,szHint);
  643.                                 
  644.                 //
  645.                 // Get control of the display context.
  646.                 //
  647.             
  648.                 hDC = GetDC(hWnd);
  649.                 
  650.                 //
  651.                 // Display the element data.
  652.                 //
  653.                 
  654.                 ElementDisplay(hDC);
  655.  
  656.                 //
  657.                 // Release display context for other uses.
  658.                 //
  659.  
  660.                 ReleaseDC(hWnd, hDC);
  661.             
  662.                } // Element changed branch exit at this point.
  663.                
  664.             } // Not frozen logic exits at this point.
  665.              
  666.             return 0L;
  667.  
  668.         case WM_PAINT:
  669.  
  670.             //
  671.             // Need to redraw the window from scratch.
  672.             //
  673.  
  674.             hDC = BeginPaint (hWnd, &ps);
  675.             cyChar = HIWORD (GetTextExtent (hDC, "M", 1));
  676.  
  677.             rect.top = cyChar;
  678.             rect.bottom = cyChar * 2 + 2;
  679.  
  680.             //
  681.             // Draw the column titles.
  682.             //
  683.             for (i=0; i<NUM_COLUMNS; i++) {
  684.                 rect.left = i * cxBox + 20;
  685.                 rect.right = rect.left + cxBox;
  686.                 DrawText (hDC, pszTitles [i], -1, &rect, DT_CENTER | DT_VCENTER |
  687.                         DT_NOPREFIX | DT_SINGLELINE);
  688.             }
  689.  
  690.             //
  691.             // Now draw each element.  Each one consists of a rectangle to
  692.             // contain the information, the atomic number in the upper left
  693.             // corner, and the atomic symbol centered.
  694.             //
  695.             for (i=0; i<MAX_ELEMENTS; i++) {
  696.                 pel = &elTable [i];
  697.                 rect.left = pel->wColumn * cxBox + 20;
  698.                 rect.right = rect.left + cxBox;
  699.                 rect.top = pel->wRow * cyBox + 40;
  700.                 rect.bottom = rect.top + cyBox;
  701.                 Rectangle (hDC, rect.left, rect.top, rect.right, rect.bottom);
  702.  
  703.                 wsprintf (buf, "%i", i+1);
  704.                 TextOut (hDC, rect.left+1, rect.top+1, buf, lstrlen (buf));
  705.  
  706.                 rect.top += cyChar + 1;
  707.  
  708.                 DrawText (hDC, pel->pszSymbol, -1, &rect, DT_CENTER | DT_VCENTER |
  709.                         DT_NOPREFIX | DT_SINGLELINE);
  710.             }
  711.             
  712.             //
  713.             // Display the element text.
  714.             //
  715.             
  716.             ElementDisplay(hDC);
  717.  
  718.             EndPaint (hWnd, &ps);
  719.  
  720.             return 0L;
  721.  
  722.         case WM_DESTROY:
  723.  
  724.             //
  725.             // Main window closed.  Quit the program.
  726.             //
  727.  
  728.             PostQuitMessage (0);
  729.             return 0L;
  730.     }
  731.  
  732.     return DefWindowProc (hWnd, iMessage, wParam, lParam);
  733. }
  734.