|
|
Microsoft OS/2 SDK PM 08-08-1988
/*--------------------------------------
LIFE.C -- John Conway's Game of Life
--------------------------------------*/
#define INCL_WIN
#define INCL_GPI
#include <os2.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "life.h"
#define ID_TIMER 1
MRESULT EXPENTRY ClientWndProc (HWND, USHORT, MPARAM, MPARAM) ;
CHAR szClientClass [] = "Life" ;
HAB hab ;
int main (void)
{
HMQ hmq ;
HWND hwndClient, hwndFrame ;
QMSG qmsg ;
ULONG flFrameFlags = FCF_STANDARD ;
ULONG flFrameStyle = WS_VISIBLE | FS_ICON ;
hab = WinInitialize (0) ;
hmq = WinCreateMsgQueue (hab, 0) ;
WinRegisterClass (hab, szClientClass, ClientWndProc, CS_SIZEREDRAW, 0) ;
hwndFrame = WinCreateStdWindow (HWND_DESKTOP, flFrameStyle,
&flFrameFlags, szClientClass,
szClientClass,
0L, NULL, ID_RESOURCE, &hwndClient) ;
while (WinGetMsg (hab, &qmsg, NULL, 0, 0))
WinDispatchMsg (hab, &qmsg) ;
WinDestroyWindow (hwndFrame) ;
WinDestroyMsgQueue (hmq) ;
WinTerminate (hab) ;
return 0 ;
}
VOID EnableMenuItem (HWND hwndMenu, SHORT idMenuItem, BOOL fEnable)
{
WinSendMsg (hwndMenu, MM_SETITEMATTR,
MPFROM2SHORT (idMenuItem, TRUE),
MPFROM2SHORT (MIA_DISABLED, fEnable ? 0 : MIA_DISABLED)) ;
}
VOID ErrorMsg (HWND hwnd, CHAR *szMessage)
{
WinMessageBox (HWND_DESKTOP, hwnd, szMessage, szClientClass, 0,
MB_OK | MB_ICONEXCLAMATION) ;
}
VOID DrawCell (HPS hps, SHORT x, SHORT y, SHORT cxCell, SHORT cyCell,
CHAR cCell)
{
RECTL rcl ;
rcl.xLeft = x * cxCell ;
rcl.yBottom = y * cyCell ;
rcl.xRight = rcl.xLeft + cxCell - 1 ;
rcl.yTop = rcl.yBottom + cyCell - 1 ;
WinFillRect (hps, &rcl, cCell & 1 ? CLR_NEUTRAL : CLR_BACKGROUND) ;
}
VOID DoGeneration (HPS hps, PUCHAR lpcGrid, SHORT xNumCells, SHORT yNumCells,
SHORT cxCell, SHORT cyCell)
{
SHORT x, y, sSum ;
for (y = 0 ; y < yNumCells - 1 ; y++)
for (x = 0 ; x < xNumCells ; x++)
{
if (x == 0 || x == xNumCells - 1 || y == 0)
*lpcGrid |= *lpcGrid << 4 ;
else
{
sSum = (*(lpcGrid - 1) + /* Left */
*(lpcGrid - xNumCells - 1) + /* Lower Left */
*(lpcGrid - xNumCells ) + /* Lower */
*(lpcGrid - xNumCells + 1)) /* Lower Right */
>> 4 ;
sSum += *(lpcGrid + 1) + /* Right */
*(lpcGrid + xNumCells + 1) + /* Upper Right */
*(lpcGrid + xNumCells ) + /* Upper */
*(lpcGrid + xNumCells - 1) ; /* Upper Left */
sSum = (sSum | *lpcGrid) & 0x0F ;
*lpcGrid <<= 4 ;
if (sSum == 3)
*lpcGrid |= 1 ;
if ((*lpcGrid & 1) != *lpcGrid >> 4)
DrawCell (hps, x, y, cxCell, cyCell, *lpcGrid) ;
}
lpcGrid++ ;
}
}
VOID DisplayGenerationNum (HPS hps, SHORT xGen, SHORT yGen, LONG lGeneration)
{
static CHAR szBuffer [24] = "Generation " ;
POINTL ptl ;
ptl.x = xGen ;
ptl.y = yGen ;
ltoa (lGeneration, szBuffer + 11, 10) ;
GpiSavePS (hps) ;
GpiSetBackMix (hps, BM_OVERPAINT) ;
GpiCharStringAt (hps, &ptl, (LONG) strlen (szBuffer), szBuffer) ;
GpiRestorePS (hps, -1L) ;
}
MRESULT EXPENTRY ClientWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
{
static BOOL fTimerGoing ;
static HWND hwndMenu ;
static LONG lGeneration ;
static SEL selGrid ;
static SHORT cxChar, cyChar, cyDesc, cxClient, cyClient, xGenNum, yGenNum,
cxCell, cyCell, xNumCells, yNumCells, sCellScale = 1 ;
FONTMETRICS fm ;
HPS hps ;
POINTL ptl ;
PUCHAR lpcGrid ;
SHORT x, y ;
switch (msg)
{
case WM_CREATE:
hps = WinGetPS (hwnd) ;
GpiQueryFontMetrics (hps, (LONG) sizeof fm, &fm) ;
cxChar = (SHORT) fm.lAveCharWidth ;
cyChar = (SHORT) fm.lMaxBaselineExt ;
cyDesc = (SHORT) fm.lMaxDescender ;
WinReleasePS (hps) ;
return 0 ;
case WM_SIZE:
if (hwndMenu == NULL)
hwndMenu = WinWindowFromID (
WinQueryWindow (hwnd, QW_PARENT, FALSE),
FID_MENU) ;
if (selGrid)
{
DosFreeSeg (selGrid) ;
selGrid = 0 ;
}
if (fTimerGoing)
{
WinStopTimer (hab, hwnd, ID_TIMER) ;
fTimerGoing = FALSE ;
}
cxClient = SHORT1FROMMP (mp2) ;
cyClient = SHORT2FROMMP (mp2) ;
xGenNum = cxChar ;
yGenNum = cyClient - cyChar + cyDesc ;
cxCell = cxChar * 2 / sCellScale ;
cyCell = cyChar / sCellScale ;
xNumCells = cxClient / cxCell ;
yNumCells = (cyClient - cyChar) / cyCell ;
if (xNumCells <= 0 || yNumCells <= 0)
{
ErrorMsg (hwnd, "Not enough room for even one cell.") ;
}
else if ((LONG) xNumCells * yNumCells > 65536L)
{
ErrorMsg (hwnd, "More than 64K cells not supported.") ;
}
else if (DosAllocSeg (xNumCells * yNumCells, &selGrid, 0))
{
ErrorMsg (hwnd, "Not enough memory for this many cells.") ;
selGrid = 0 ;
}
else
{
lpcGrid = MAKEP (selGrid, 0) ;
for (y = 0 ; y < yNumCells ; y++)
for (x = 0 ; x < xNumCells ; x++)
*lpcGrid++ = 0 ;
}
EnableMenuItem (hwndMenu, IDM_SIZE, TRUE) ;
EnableMenuItem (hwndMenu, IDM_START, selGrid != 0) ;
EnableMenuItem (hwndMenu, IDM_STOP, FALSE) ;
EnableMenuItem (hwndMenu, IDM_STEP, selGrid != 0) ;
EnableMenuItem (hwndMenu, IDM_CLEAR, selGrid != 0) ;
lGeneration = 0 ;
return 0 ;
case WM_BUTTON1DOWN:
x = MOUSEMSG(&msg)->x / cxCell ;
y = MOUSEMSG(&msg)->y / cyCell ;
if (selGrid && !fTimerGoing && x < xNumCells && y < yNumCells)
{
lpcGrid = MAKEP (selGrid, 0) ;
hps = WinGetPS (hwnd) ;
DrawCell (hps, x, y, cxCell, cyCell,
*(lpcGrid + y * xNumCells + x) ^= 1) ;
WinReleasePS (hps) ;
}
else
WinAlarm (HWND_DESKTOP, WA_WARNING) ;
return 1 ;
case WM_COMMAND:
switch (COMMANDMSG(&msg)->cmd)
{
case IDM_LARGE:
case IDM_SMALL:
case IDM_TINY:
WinSendMsg (hwndMenu, MM_SETITEMATTR,
MPFROM2SHORT (sCellScale, TRUE),
MPFROM2SHORT (MIA_CHECKED, 0)) ;
sCellScale = COMMANDMSG(&msg)->cmd ;
WinSendMsg (hwndMenu, MM_SETITEMATTR,
MPFROM2SHORT (sCellScale, TRUE),
MPFROM2SHORT (MIA_CHECKED, MIA_CHECKED)) ;
WinSendMsg (hwnd, WM_SIZE, NULL,
MPFROM2SHORT (cxClient, cyClient)) ;
WinInvalidateRect (hwnd, NULL, FALSE) ;
return 0 ;
case IDM_START:
if (!WinStartTimer (hab, hwnd, ID_TIMER, 1))
{
ErrorMsg (hwnd, "Too many clocks or timers.") ;
}
else
{
fTimerGoing = TRUE ;
EnableMenuItem (hwndMenu, IDM_SIZE, FALSE) ;
EnableMenuItem (hwndMenu, IDM_START, FALSE) ;
EnableMenuItem (hwndMenu, IDM_STOP, TRUE) ;
EnableMenuItem (hwndMenu, IDM_STEP, FALSE) ;
EnableMenuItem (hwndMenu, IDM_CLEAR, FALSE) ;
}
return 0 ;
case IDM_STOP:
WinStopTimer (hab, hwnd, ID_TIMER) ;
fTimerGoing = FALSE ;
EnableMenuItem (hwndMenu, IDM_SIZE, TRUE) ;
EnableMenuItem (hwndMenu, IDM_START, TRUE) ;
EnableMenuItem (hwndMenu, IDM_STOP, FALSE) ;
EnableMenuItem (hwndMenu, IDM_STEP, TRUE) ;
EnableMenuItem (hwndMenu, IDM_CLEAR, TRUE) ;
return 0 ;
case IDM_STEP:
WinSendMsg (hwnd, WM_TIMER, NULL, NULL) ;
return 0 ;
case IDM_CLEAR:
lGeneration = 0L ;
lpcGrid = MAKEP (selGrid, 0) ;
for (y = 0 ; y < yNumCells ; y++)
for (x = 0 ; x < xNumCells ; x++)
*lpcGrid++ = 0 ;
WinInvalidateRect (hwnd, NULL, FALSE) ;
return 0 ;
}
break ;
case WM_TIMER:
hps = WinGetPS (hwnd) ;
DisplayGenerationNum (hps, xGenNum, yGenNum, ++lGeneration) ;
lpcGrid = MAKEP (selGrid, 0) ;
DoGeneration (hps, lpcGrid, xNumCells, yNumCells, cxCell, cyCell);
WinReleasePS (hps) ;
return 0 ;
case WM_PAINT:
hps = WinBeginPaint (hwnd, NULL, NULL) ;
GpiErase (hps) ;
if (selGrid)
{
for (x = 1 ; x <= xNumCells ; x++)
{
ptl.x = cxCell * x - 1 ;
ptl.y = 0 ;
GpiMove (hps, &ptl) ;
ptl.y = cyCell * yNumCells - 1 ;
GpiLine (hps, &ptl) ;
}
for (y = 1 ; y <= yNumCells ; y++)
{
ptl.x = 0 ;
ptl.y = cyCell * y - 1 ;
GpiMove (hps, &ptl) ;
ptl.x = cxCell * xNumCells - 1 ;
GpiLine (hps, &ptl) ;
}
lpcGrid = MAKEP (selGrid, 0) ;
for (y = 0 ; y < yNumCells ; y++)
for (x = 0 ; x < xNumCells ; x++)
if (*lpcGrid++)
DrawCell (hps, x, y, cxCell, cyCell,
*(lpcGrid - 1)) ;
DisplayGenerationNum (hps, xGenNum, yGenNum, lGeneration) ;
}
WinEndPaint (hps) ;
return 0 ;
case WM_DESTROY:
if (fTimerGoing)
WinStopTimer (hab, hwnd, ID_TIMER) ;
if (selGrid)
DosFreeSeg (selGrid) ;
return 0 ;
}
return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.