// // Periodic table of the elements, for Microsoft Windows 3.0. // Originally written by Gregory A. Jones, uunet!microsoft!gregj. // Extensively modified by Charles L. Perrin as a Windows learning project. // // This program may be freely distributed. // Chemical data culled from reference works, including the // CRC Handbook of Chemistry and Physics. #include #include "element3.h" // // Prototypes for functions. // long FAR PASCAL WndProc(HWND, unsigned, WORD, LONG); BOOL FAR PASCAL BoxProcessor(HWND,unsigned,WORD,LONG); void ElementDisplay(HDC); // // A few global variables. // char szAppName [] = "Element3"; char szMainMenu [] = "mainmenu"; char szAccTable [] = "mainaccel"; char szHint [] = "HINT: Point at an element with the mouse."; char szElement [80]; FARPROC lpBoxHandler; HANDLE ghInstance, hWhiteBrush, hAccTable, hClipboard; LPSTR lpszClipboard; WORD cxBox, cyBox; int i, iElementOld; BOOL fThawing, fFreezing, fFrozen; RECT rect; // // Data stored for each element. Includes name, symbol, atomic weight, // and location in table (where period one is row 0, family 1a is column 0). // Atomic number is implicit, since the table is ordered by it. // typedef struct tagELEMENT { char *pszName; // Name of the element, i.e. "Hydrogen" char *pszSymbol; // Symbol, i.e. "He" char *pszWeight; // Atomic weight, i.e. "(230)" WORD wColumn; // Column number to draw in WORD wRow; // Row number to draw in } ELEMENT; typedef ELEMENT *PELEMENT; // // Width and height of the table, and number of elements defined. // #define NUM_COLUMNS 18 #define NUM_ROWS 10 #define MAX_ELEMENTS 106 // // Titles for the families, by column. Null strings are because "8" // really covers three columns. // char *pszTitles [NUM_COLUMNS] = { "1a", "2a", "3b", "4b", "5b", "6b", "7b", "", "8", "", "1b", "2b", "3a", "4a", "5a", "6a", "7a", "0" }; // // The elements themselves. Add new ones on the end if you discover them. // Also, don't forget to set MAX_ELEMENTS to the new value! // ELEMENT elTable [MAX_ELEMENTS] = { "Hydrogen", "H", "1.0079", 0, 0, "Helium", "He", "4.00260", 17, 0, "Lithium", "Li", "6.94", 0, 1, "Beryllium", "Be", "9.01218", 1, 1, "Boron", "B", "10.81", 12, 1, "Carbon", "C", "12.011", 13, 1, "Nitrogen", "N", "14.0067", 14, 1, "Oxygen", "O", "15.9994", 15, 1, "Fluorine", "F", "18.998403", 16, 1, "Neon", "Ne", "20.17", 17, 1, "Sodium", "Na", "22.98977", 0, 2, "Magnesium", "Mg", "24.305", 1, 2, "Aluminum", "Al", "26.98154", 12, 2, "Silicon", "Si", "28.0855", 13, 2, "Phosphorous", "P", "30.97376", 14, 2, "Sulfur", "S", "32.06", 15, 2, "Chlorine", "Cl", "35.453", 16, 2, "Argon", "Ar", "39.948", 17, 2, "Potassium", "K", "39.0983", 0, 3, "Calcium", "Ca", "40.08", 1, 3, "Scandium", "Sc", "44.9559", 2, 3, "Titanium", "Ti", "47.90", 3, 3, "Vanadium", "V", "50.9415", 4, 3, "Chromium", "Cr", "51.996", 5, 3, "Manganese", "Mn", "54.9380", 6, 3, "Iron", "Fe", "55.847", 7, 3, "Cobalt", "Co", "58.9332", 8, 3, "Nickel", "Ni", "58.71", 9, 3, "Copper", "Cu", "63.546", 10, 3, "Zinc", "Zn", "65.38", 11, 3, "Gallium", "Ga", "69.735", 12, 3, "Germanium", "Ge", "72.59", 13, 3, "Arsenic", "As", "74.9216", 14, 3, "Selenium", "Se", "78.96", 15, 3, "Bromium", "Br", "79.904", 16, 3, "Krypton", "Kr", "83.80", 17, 3, "Rubidium", "Rb", "85.467", 0, 4, "Strontium", "Sr", "87.62", 1, 4, "Yttrium", "Y", "88.9059", 2, 4, "Zirconium", "Zr", "91.22", 3, 4, "Niobium", "Nb", "92.9064", 4, 4, "Molybdenum", "Mo", "95.94", 5, 4, "Technetium", "Tc", "98.9062", 6, 4, "Ruthenium", "Ru", "101.07", 7, 4, "Rhodium", "Rh", "102.9055", 8, 4, "Palladium", "Pd", "106.4", 9, 4, "Silver", "Ag", "107.868", 10, 4, "Cadmium", "Cd", "112.41", 11, 4, "Indium", "In", "114.82", 12, 4, "Tin", "Sn", "118.69", 13, 4, "Antimony", "Sb", "121.75", 14, 4, "Tellurium", "Te", "127.60", 15, 4, "Iodine", "I", "126.9045", 16, 4, "Xenon", "Xe", "131.30", 17, 4, "Cesium", "Cs", "132.9054", 0, 5, "Barium", "Ba", "137.33", 1, 5, "Lanthanum", "La", "138.9055", 2, 5, "Cerium", "Ce", "140.12", 2, 8, "Praeseodymium", "Pr", "140.9077", 3, 8, "Neodymium", "Nd", "144.24", 4, 8, "Promethium", "Pm", "(145)", 5, 8, "Samarium", "Sm", "150.4", 6, 8, "Europium", "Eu", "151.96", 7, 8, "Gadolinium", "Gd", "157.25", 8, 8, "Terbium", "Tb", "158.9254", 9, 8, "Dysprosium", "Dy", "162.50", 10, 8, "Holmium", "Ho", "164.9304", 11, 8, "Erbium", "Er", "167.26", 12, 8, "Thulium", "Tm", "168.9342", 13, 8, "Ytterbium", "Yb", "173.04", 14, 8, "Lutetium", "Lu", "174.96", 15, 8, "Hafnium", "Hf", "178.49", 3, 5, "Tantalum", "Ta", "180.947", 4, 5, "Tungsten", "W", "183.85", 5, 5, "Rhenium", "Re", "186.207", 6, 5, "Osmium", "Os", "190.2", 7, 5, "Iridium", "Ir", "192.22", 8, 5, "Platinum", "Pt", "195.09", 9, 5, "Gold", "Au", "196.9665", 10, 5, "Mercury", "Hg", "200.59", 11, 5, "Thallium", "Tl", "204.37", 12, 5, "Lead", "Pb", "207.2", 13, 5, "Bismuth", "Bi", "208.9804", 14, 5, "Polonium", "Po", "(209)", 15, 5, "Astatine", "At", "(210)", 16, 5, "Radon", "Rn", "(222)", 17, 5, "Francium", "Fr", "(223)", 0, 6, "Radium", "Ra", "226.0254", 1, 6, "Actinium", "Ac", "(227)", 2, 6, "Thorium", "Th", "232.0381", 2, 9, "Protactinium", "Pa", "231.0359", 3, 9, "Uranium", "U", "238.029", 4, 9, "Neptunium", "Np", "237.0482", 5, 9, "Plutonium", "Pu", "(244)", 6, 9, "Americium", "Am", "(243)", 7, 9, "Curium", "Cm", "(247)", 8, 9, "Berkelium", "Bk", "(247)", 9, 9, "Calfornium", "Cf", "(251)", 10, 9, "Einsteinium", "Es", "(254)", 11, 9, "Fermium", "Fm", "(257)", 12, 9, "Mendelevium", "Md", "(258)", 13, 9, "Nobelium", "No", "(259)", 14, 9, "Lawrencium", "Lr", "(260)", 15, 9, "Rutherfordium", "Rf", "(260)", 3, 6, "Hahnium", "Ha", "(260)", 4, 6, "Not Named Yet", "106", "(263)", 5, 6 }; // // Main entry point for this application. // int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { HWND hWnd; MSG msg; int nWidth, nHeight; WNDCLASS wndclass; // // Save handle instance globally. // ghInstance = hInstance; // // Register the window class for this application. // if (!hPrevInstance) { wndclass.style = CS_VREDRAW | CS_HREDRAW | CS_SAVEBITS; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon (hInstance, "mainicon"); wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); wndclass.hbrBackground = GetStockObject (WHITE_BRUSH); wndclass.lpszMenuName = szMainMenu; wndclass.lpszClassName = szAppName; if (!RegisterClass (&wndclass)) return FALSE; } // // Create a white background for future use. // hWhiteBrush = GetStockObject(WHITE_BRUSH); // // Load the keyboard accelerator table. // hAccTable = LoadAccelerators(hInstance,szAccTable); // // Set old element number to cause display on first entry. // Set up initial hint text. // Set flag to indicate element change is not frozen. // iElementOld = MAX_ELEMENTS + 1; lstrcpy(szElement,szHint); fFrozen = FALSE; // // Calculate a width of screen width. // nWidth = GetSystemMetrics(SM_CXSCREEN); // // Calculate a height of screen height less twice icon height. // nHeight = GetSystemMetrics(SM_CYSCREEN) - GetSystemMetrics(SM_CYICON) * 2; // // Create and display the main window. // hWnd = CreateWindow (szAppName, "Periodic Table", WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0, 0, nWidth, nHeight, NULL, NULL, hInstance, NULL); if (!hWnd) return FALSE; ShowWindow (hWnd, nCmdShow); UpdateWindow (hWnd); // // The world-famous Microsoft Windows message loop with accelerators. // By the time you get your first WinApp working, you will be seeing // messages in your sleep! // while (GetMessage (&msg, NULL, 0, 0)) { // // If it's not an accelerator key, translate and dispatch! // if (!TranslateAccelerator(hWnd,hAccTable,&msg)) { TranslateMessage (&msg); DispatchMessage (&msg); } } // // Return control to caller (Windows). // return msg.wParam; } // // This module displays the element text in the proper size and color. // void ElementDisplay(hDC) HDC hDC; { // // Calculate bounding box for the DrawText operation (the area that is // between Hydrogen and Helium with a 1-pixel border). // rect.left = ( elTable[0].wColumn + 1 ) * cxBox + 21; rect.right = elTable[1].wColumn * cxBox + 19; rect.top = elTable[0].wRow * cyBox + 40; rect.bottom = rect.top + cyBox - 1; // // Fill the element text area with the background. // FillRect(hDC,&rect,hWhiteBrush); // // Switch text color to blue if frozen, or red if not frozen. // if (fFrozen) SetTextColor(hDC,RGB(0,0,255)); else SetTextColor(hDC,RGB(255,0,0)); // // Display the element text, clipped, centered. // DrawText(hDC,szElement,-1,&rect,DT_CENTER | DT_VCENTER); // // Switch text color back to black. // SetTextColor(hDC,RGB(0,0,0)); } // // AboutBox and HelpBox (only the box changes) dialog box function. // BOOL FAR PASCAL BoxProcessor(hDlg,message,wParam,lParam) HWND hDlg; unsigned message; WORD wParam; LONG lParam; { // // What type of message was encountered? // switch (message) { // // No steps required to initialize dialog. // However, it must be indicated that the dialog is initialized. // case WM_INITDIALOG: return (TRUE); // // Process command keys germane to the dialog box. // case WM_COMMAND: // // Was the command key "OK" or "Cancel"? // if (wParam == IDOK || wParam ==IDCANCEL) { // // End the dialog and indicate that keys accepted. // EndDialog(hDlg,TRUE); return(TRUE); } // // No processing required for any other function. // } return(FALSE); } // // Main window function. // long FAR PASCAL WndProc (HWND hWnd, unsigned iMessage, WORD wParam, LONG lParam) { static WORD cxClient, cyClient; WORD cyChar, xBox, yBox; PAINTSTRUCT ps; HDC hDC; PELEMENT pel; char buf [10]; RECT rect; // // Clear the "freezing" and "thawing" flags. // fFreezing = FALSE; fThawing = FALSE; switch (iMessage) { // // Accept the four defined messages. // case WM_COMMAND: switch (wParam) { // // Did the user request an Exit? // case ID_EXIT: // // Request Windows to nuke the window. // PostQuitMessage(0); break; // // Did the user request the element data be placed on the clipboard? // case ID_COPY: // // Get a global block of memory for clipboard use. // hClipboard = GlobalAlloc(GHND,(DWORD)128); // // Convert the handle to a pointer. // lpszClipboard = GlobalLock(hClipboard); // // Store the current line in the clipboard block. // wsprintf(lpszClipboard,"%s\n",(LPSTR)szElement); // // Unlock the clipboard memory block by handle. // GlobalUnlock(hClipboard); // // Transfer the clipboard memory block to the clipboard. // OpenClipboard(hWnd); EmptyClipboard(); SetClipboardData(CF_TEXT,hClipboard); CloseClipboard(); // // Clipboard functions complete! // break; // // This logic handles the "Help Screen" function. // case ID_HELP: // // Get the famous "instance thunk" pointing to the BoxProcessor. // lpBoxHandler = MakeProcInstance(BoxProcessor,ghInstance); // // Set up the dialog box. // DialogBox(ghInstance,"HelpBox",hWnd,lpBoxHandler); // // Discard the instance thunk. // FreeProcInstance(lpBoxHandler); // // Help functions complete! // break; // // This logic sequence handles "About Element3...". // case ID_ABOUT: // // Get the famous "instance thunk" pointing to the BoxProcessor. // lpBoxHandler = MakeProcInstance(BoxProcessor,ghInstance); // // Set up the dialog box. // DialogBox(ghInstance,"AboutBox",hWnd,lpBoxHandler); // // Discard the instance thunk. // FreeProcInstance(lpBoxHandler); // // About functions complete! // break; } // // Command functions complete // break; case WM_SIZE: // // When the window changes size, update static variables // containing the window size and size of each box. // cxClient = LOWORD (lParam); cyClient = HIWORD (lParam); cxBox = (cxClient - 40) / NUM_COLUMNS; cyBox = (cyClient - 60) / NUM_ROWS; break; case WM_LBUTTONUP: // // Handle the case when the user released any mouse button. // // // Set flags to indicate freezing or thawing status. // fThawing = fFrozen; fFreezing = !fThawing; case WM_MOUSEMOVE: // // Mouse motion has occurred. Where is that dirty rat? // // // Are we not frozen or thawing out? // if (fThawing || !fFrozen) { // // Set frozen flag if we're in the process of freezing. // fFrozen = fFreezing; // // Convert the mouse location to a corresponding element box. // xBox = (LOWORD (lParam) - 20) / cxBox; yBox = (HIWORD (lParam) - 40) / cyBox; // // Scan the element table to determine which box holds the mouse. // for (i=0; iwColumn * cxBox + 20; rect.right = rect.left + cxBox; rect.top = pel->wRow * cyBox + 40; rect.bottom = rect.top + cyBox; Rectangle (hDC, rect.left, rect.top, rect.right, rect.bottom); wsprintf (buf, "%i", i+1); TextOut (hDC, rect.left+1, rect.top+1, buf, lstrlen (buf)); rect.top += cyChar + 1; DrawText (hDC, pel->pszSymbol, -1, &rect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE); } // // Display the element text. // ElementDisplay(hDC); EndPaint (hWnd, &ps); return 0L; case WM_DESTROY: // // Main window closed. Quit the program. // PostQuitMessage (0); return 0L; } return DefWindowProc (hWnd, iMessage, wParam, lParam); }