/*
* TVision example: the classic life example
*
* Written by Sergio Sigala <sergio@sigala.it>
*
* The mouse may be used to edit the patterns within the life window.
* Clicking with the left button inside the life window will cause a dot to
* appear at the cursor location. Clicking with the right mouse button will
* remove the dot. This allows the user to create his/her own patterns.
*
* Modified by Max Okumoto <okumoto@ucsd.edu>
*/
#define Uses_TApplication
#define Uses_TButton
#define Uses_TDeskTop
#define Uses_TDialog
#define Uses_TKeys
#define Uses_TMenuBar
#define Uses_TMenuItem
#define Uses_TParamText
#define Uses_TStatusDef
#define Uses_TStatusItem
#define Uses_TStatusLine
#define Uses_TSubMenu
#define Uses_TWindow
#include <tvision/tv.h>
#include <stdlib.h>
enum
{
cmAbout = 101, //about box
cmCreate, //creates a new life window
cmOneStep, //advance one step
cmUpdate, //issued when idle
cmStartStop, //starts or stops a life window
cmClearBoard, //clears the life board
cmRandom, //randomly fills the life board
cmPat01, cmPat02, cmPat03, cmPat04, cmPat05,
cmPat06, cmPat07, cmPat08, cmPat09, cmPat10,
cmPat11, cmPat12, cmPat13, cmPat14, cmPat15,
cmPat16, cmPat17, cmPat18, cmPat19, cmPat20,
cmPat21, cmPat22, cmPat23, cmPat24, cmPat25,
cmPat26, cmPat27, cmPat28, cmPat29
};
class TLifeInterior: public TView
{
int running;
uchar* board;
public:
TLifeInterior(TRect& bounds);
~TLifeInterior();
void changeBounds(const TRect& bounds);
void clearBoard();
void draw();
void getPattern(int pat);
void handleEvent(TEvent& event);
void handleMouse(TEvent& event);
void iterateBoard();
uchar& map(int x, int y);
uchar& map(int x, int y, uchar* work);
int present(int x, int y);
void randomizeBoard();
void setState(ushort aState, Boolean enable);
};
class TLifeWindow: public TWindow
{
TLifeInterior* life;
public:
static const int minW = 28;
static const int minH = 11;
TLifeWindow(TRect& bounds, char* str, int num);
void sizeLimits(TPoint& min, TPoint& max);
};
class TMyApp: public TApplication
{
TCommandSet windowCommands;
public:
TMyApp();
static TMenuBar* initMenuBar(TRect r);
static TStatusLine* initStatusLine(TRect r);
void aboutBox();
void createLifeWindow();
TCommandSet getCommands();
void handleEvent(TEvent& event);
void idle();
};
/****************************************************************************
*
* Patterns for tvlife. Adapted from xlock; original copyright notice below.
*
* Copyright (c) 1988-91 by Patrick J. Naughton.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* This file is provided AS IS with no warranties of any kind. The author
* shall have no liability with respect to the infringement of copyrights,
* trade secrets or any patents by this file or any part thereof. In no
* event will the author be liable for any lost revenue or profits or
* other special, indirect and consequential damages.
*****************************************************************************/
#define NUMPTS 63
/* Patterns have < NUMPTS pts (and should have a size of <= 32x32,
the Gun is an exception) */
static int patterns[][2 * NUMPTS + 1] =
{
{ /* GLIDER GUN */
6, -4,
5, -3, 6, -3,
-6, -2, -5, -2, 8, -2, 9, -2, 16, -2,
-7, -1, 8, -1, 9, -1, 10, -1, 16, -1, 17, -1,
-18, 0, -17, 0, -8, 0, 8, 0, 9, 1,
-17, 1, -8, 1, 5, 1, 6, 1,
-8, 2, 6, 2,
-7, 3,
-6, 4, -5, 4,
127
},
{ /* FIGURE EIGHT */
-3, -3, -2, -3, -1, -3,
-3, -2, -2, -2, -1, -2,
-3, -1, -2, -1, -1, -1,
0, 0, 1, 0, 2, 0,
0, 1, 1, 1, 2, 1,
0, 2, 1, 2, 2, 2,
127
},
{ /* PULSAR */
-2, -1, -1, -1, 0, -1, 1, -1, 2, -1,
-2, 0, 2, 0,
127
},
{ /* BARBER POLE P2 */
-6, -6, -5, -6,
-6, -5, -4, -5,
-4, -3, -2, -3,
-2, -1, 0, -1,
0, 1, 2, 1,
2, 3, 4, 3,
5, 4,
4, 5, 5, 5,
127
},
{ /* ACHIM P5 */
-6, -6, -5, -6,
-6, -5,
-4, -4,
-4, -3, -2, -3,
-2, -1, 0, -1,
0, 1, 2, 1,
2, 3, 3, 3,
5, 4,
4, 5, 5, 5,
127
},
{ /* HERTZ P4 */
-2, -5, -1, -5,
-2, -4, -1, -4,
-7, -2, -6, -2, -2, -2, -1, -2, 0, -2, 1, -2, 5, -2, 6, -2,
-7, -1, -5, -1, -3, -1, 2, -1, 4, -1, 6, -1,
-5, 0, -3, 0, -2, 0, 2, 0, 4, 0,
-7, 1, -5, 1, -3, 1, 2, 1, 4, 1, 6, 1,
-7, 2, -6, 2, -2, 2, -1, 2, 0, 2, 1, 2, 5, 2, 6, 2,
-2, 4, -1, 4,
-2, 5, -1, 5,
127
},
{ /* TUMBLER */
-2, -3, -1, -3, 1, -3, 2, -3,
-2, -2, -1, -2, 1, -2, 2, -2,
-1, -1, 1, -1,
-3, 0, -1, 0, 1, 0, 3, 0,
-3, 1, -1, 1, 1, 1, 3, 1,
-3, 2, -2, 2, 2, 2, 3, 2,
127
},
{ /* PULSE1 P4 */
0, -3, 1, -3,
-2, -2, 0, -2,
-3, -1, 3, -1,
-2, 0, 2, 0, 3, 0,
0, 2, 2, 2,
1, 3,
127
},
{ /* SHINING FLOWER P5 */
-1, -4, 0, -4,
-2, -3, 1, -3,
-3, -2, 2, -2,
-4, -1, 3, -1,
-4, 0, 3, 0,
-3, 1, 2, 1,
-2, 2, 1, 2,
-1, 3, 0, 3,
127
},
{ /* PULSE2 P6 */
0, -4, 1, -4,
-4, -3, -3, -3, -1, -3,
-4, -2, -3, -2, 0, -2, 3, -2,
1, -1, 3, -1,
2, 0,
1, 2, 2, 2,
1, 3, 2, 3,
127
},
{ /* PINWHEEL, CLOCK P4 */
-2, -6, -1, -6,
-2, -5, -1, -5,
-2, -3, -1, -3, 0, -3, 1, -3,
-3, -2, -1, -2, 2, -2, 4, -2, 5, -2,
-3, -1, 1, -1, 2, -1, 4, -1, 5, -1,
-6, 0, -5, 0, -3, 0, 0, 0, 2, 0,
-6, 1, -5, 1, -3, 1, 2, 1,
-2, 2, -1, 2, 0, 2, 1, 2,
0, 4, 1, 4,
0, 5, 1, 5,
127
},
{ /* PENTADECATHOLON */
-5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0,
127
},
{ /* PISTON */
1, -3, 2, -3,
0, -2,
-10, -1, -1, -1,
-11, 0, -10, 0, -1, 0, 9, 0, 10, 0,
-1, 1, 9, 1,
0, 2,
1, 3, 2, 3,
127
},
{ /* PISTON2 */
-3, -5,
-14, -4, -13, -4, -4, -4, -3, -4, 13, -4, 14, -4,
-14, -3, -13, -3, -5, -3, -4, -3, 13, -3, 14, -3,
-4, -2, -3, -2, 0, -2, 1, -2,
-4, 2, -3, 2, 0, 2, 1, 2,
-14, 3, -13, 3, -5, 3, -4, 3, 13, 3, 14, 3,
-14, 4, -13, 4, -4, 4, -3, 4, 13, 4, 14, 4,
-3, 5,
127
},
{ /* SWITCH ENGINE */
-12, -3, -10, -3,
-13, -2,
-12, -1, -9, -1,
-10, 0, -9, 0, -8, 0,
13, 2, 14, 2,
13, 3,
127
},
{ /* GEARS (gear, flywheel, blinker) */
-1, -4,
-1, -3, 1, -3,
-3, -2,
2, -1, 3, -1,
-4, 0, -3, 0,
2, 1,
-2, 2, 0, 2,
0, 3,
5, 3,
3, 4, 4, 4,
5, 5, 6, 5,
4, 6,
8, 0,
8, 1,
8, 2,
127
},
{ /* TURBINE8 */
-4, -4, -3, -4, -2, -4, -1, -4, 0, -4, 1, -4, 3, -4, 4, -4,
-4, -3, -3, -3, -2, -3, -1, -3, 0, -3, 1, -3, 3, -3, 4, -3,
3, -2, 4, -2,
-4, -1, -3, -1, 3, -1, 4, -1,
-4, 0, -3, 0, 3, 0, 4, 0,
-4, 1, -3, 1, 3, 1, 4, 1,
-4, 2, -3, 2,
-4, 3, -3, 3, -1, 3, 0, 3, 1, 3, 2, 3, 3, 3, 4, 3,
-4, 4, -3, 4, -1, 4, 0, 4, 1, 4, 2, 4, 3, 4, 4, 4,
127
},
{ /* P16 */
-3, -6, 1, -6, 2, -6,
-3, -5, 0, -5, 3, -5,
3, -4,
-5, -3, -4, -3, 1, -3, 2, -3, 5, -3, 6, -3,
-6, -2, -3, -2,
-6, -1, -3, -1,
-5, 0, 5, 0,
3, 1, 6, 1,
3, 2, 6, 2,
-6, 3, -5, 3, -2, 3, -1, 3, 4, 3, 5, 3,
-3, 4,
-3, 5, 0, 5, 3, 5,
-2, 6, -1, 6, 3, 6,
127
},
{ /* PUFFER */
1, -9,
2, -8,
-2, -7, 2, -7,
-1, -6, 0, -6, 1, -6, 2, -6,
-2, -2,
-1, -1, 0, -1,
0, 0,
0, 1,
-1, 2,
1, 5,
2, 6,
-2, 7, 2, 7,
-1, 8, 0, 8, 1, 8, 2, 8,
127
},
{ /* ESCORT */
3, -8,
4, -7,
-2, -6, 4, -6,
-1, -5, 0, -5, 1, -5, 2, -5, 3, -5, 4, -5,
-5, -1, -4, -1, -3, -1, -2, -1, -1, -1, 0, -1,
1, -1, 2, -1, 3, -1, 4, -1, 5, -1, 6, -1,
-6, 0, 6, 0,
6, 1,
5, 2,
3, 4,
4, 5,
-2, 6, 4, 6,
-1, 7, 0, 7, 1, 7, 2, 7, 3, 7, 4, 7,
127
},
{ /* DART SPEED 1/3 */
3, -7,
2, -6, 4, -6,
1, -5, 2, -5,
4, -4,
0, -3, 4, -3,
-3, -2, 0, -2,
-4, -1, -2, -1, 1, -1, 2, -1, 3, -1, 4, -1,
-5, 0, -2, 0,
-4, 1, -2, 1, 1, 1, 2, 1, 3, 1, 4, 1,
-3, 2, 0, 2,
0, 3, 4, 3,
4, 4,
1, 5, 2, 5,
2, 6, 4, 6,
3, 7,
127
},
{ /* PERIOD 4 SPEED 1/2 */
-3, -5,
-4, -4, -3, -4, -2, -4, -1, -4, 0, -4,
-5, -3, -4, -3, 0, -3, 1, -3, 3, -3,
-4, -2, 4, -2,
-3, -1, -2, -1, 1, -1, 3, -1,
-3, 1, -2, 1, 1, 1, 3, 1,
-4, 2, 4, 2,
-5, 3, -4, 3, 0, 3, 1, 3, 3, 3,
-4, 4, -3, 4, -2, 4, -1, 4, 0, 4,
-3, 5,
127
},
{ /* ANOTHER PERIOD 4 SPEED 1/2 */
-4, -7, -3, -7, -1, -7, 0, -7, 1, -7, 2, -7, 3, -7, 4, -7,
-5, -6, -4, -6, -3, -6, -2, -6, 5, -6,
-6, -5, -5, -5,
-5, -4, 5, -4,
-4, -3, -3, -3, -2, -3, 0, -3,
-2, -2,
-2, -1,
-1, 0,
-2, 1,
-2, 2,
-4, 3, -3, 3, -2, 3, 0, 3,
-5, 4, 5, 4,
-6, 5, -5, 5,
-5, 6, -4, 6, -3, 6, -2, 6, 5, 6,
-4, 7, -3, 7, -1, 7, 0, 7, 1, 7, 2, 7, 3, 7, 4, 7,
127
},
{ /* SMALLEST KNOWN PERIOD 3 SPACESHIP SPEED 1/3 */
0, -8,
-1, -7, 1, -7,
-1, -6, 1, -6,
-1, -5,
-2, -3, -1, -3,
-1, -2, 1, -2,
-2, -1, 0, -1,
-2, 0, -1, 0, 0, 0,
-1, 2, 1, 2,
-1, 3, 0, 3,
0, 4,
0, 5, 2, 5,
0, 6, 2, 6,
1, 7,
127
},
{ /* TURTLE SPEED 1/3 */
-4, -5, -3, -5, -2, -5, 6, -5,
-4, -4, -3, -4, 0, -4, 2, -4, 3, -4, 5, -4, 6, -4,
-2, -3, -1, -3, 0, -3, 5, -3,
-4, -2, -1, -2, 1, -2, 5, -2,
-5, -1, 0, -1, 5, -1,
-5, 0, 0, 0, 5, 0,
-4, 1, -1, 1, 1, 1, 5, 1,
-2, 2, -1, 2, 0, 2, 5, 2,
-4, 3, -3, 3, 0, 3, 2, 3, 3, 3, 5, 3, 6, 3,
-4, 4, -3, 4, -2, 4, 6, 4,
127
},
{ /* SMALLEST KNOWN PERIOD 5 SPEED 2/5 */
1, -7, 3, -7,
-2, -6, 3, -6,
-3, -5, -2, -5, -1, -5, 4, -5,
-4, -4, -2, -4,
-5, -3, -4, -3, -1, -3, 0, -3, 5, -3,
-4, -2, -3, -2, 0, -2, 1, -2, 2, -2, 3, -2, 4, -2,
-4, 2, -3, 2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2,
-5, 3, -4, 3, -1, 3, 0, 3, 5, 3,
-4, 4, -2, 4,
-3, 5, -2, 5, -1, 5, 4, 5,
-2, 6, 3, 6,
1, 7, 3, 7,
127
},
{ /* SYM PUFFER */
1, -4, 2, -4, 3, -4, 4, -4,
0, -3, 4, -3,
4, -2,
-4, -1, -3, -1, 0, -1, 3, -1,
-4, 0, -3, 0, -2, 0,
-4, 1, -3, 1, 0, 1, 3, 1,
4, 2,
0, 3, 4, 3,
1, 4, 2, 4, 3, 4, 4, 4,
127
},
{ /* ], NEAR SHIP, PI HEPTOMINO */
-2, -1, -1, -1, 0, -1,
1, 0,
-2, 1, -1, 1, 0, 1,
127
},
{ /* R PENTOMINO */
0, -1, 1, -1,
-1, 0, 0, 0,
0, 1,
127
}
};
#define NPATS (sizeof patterns / sizeof patterns[0])
TLifeInterior::TLifeInterior(TRect& bounds)
: TView(bounds), running(0), board(NULL)
{
eventMask = evMouseDown | evKeyDown | evCommand | evBroadcast;
growMode = gfGrowHiX | gfGrowHiY;
options |= ofSelectable;
board = new uchar[size.x * size.y]; //get memory
getPattern(0);
}
TLifeInterior::~TLifeInterior()
{
if (board != 0) delete[] board; //release memory
}
void TLifeInterior::changeBounds(const TRect& bounds)
{
if (board == 0) return; //exit if no board
TPoint oldSize = size; //calculate sizes
TPoint newSize = bounds.b - bounds.a;
uchar* work = new uchar[newSize.x * newSize.y]; //get memory
if (work == 0) return;
//clear board
for (int i = 0; i < newSize.x * newSize.y; i++)
work[i] = 0;
//copy
for (int y = 0; y < min(oldSize.y, newSize.y); y++)
for (int x = 0; x < min(oldSize.x, newSize.x); x++)
{
uchar *from = &board[oldSize.x * y + x];
uchar *to = &work[newSize.x * y + x ];
*to = *from; //copy a cell
}
uchar* old = board; //swap buffers
board = work;
delete[] old;
TView::changeBounds(bounds); //update size and redraw
}
void TLifeInterior::clearBoard()
{
if (board == 0) return; //exit if no board
//clear board
for (int i = 0; i < size.x * size.y; i++)
board[i] = 0;
}
void TLifeInterior::draw()
{
uchar color = running ? 0x4f : 0x1f;
uchar* from = board;
#if 1
int i = size.x * size.y;
ushort *buf = new ushort[i];
ushort *to = buf;
while (i-- > 0)
{
*to = (*from++ != 0) ? '*' : ' ';
*to |= (color << 8);
to++;
}
writeBuf(0, 0, size.x, size.y, buf);
delete[] buf;
#else
TDrawBuffer b;
b.moveChar(0, ' ', color, size.x);
for (int i = 0; i < size.y; i++)
{
TDrawBuffer d = b;
if (from != 0)
{
for (int j = 0; j < size.x; j++)
{
if (*from != 0) d.putChar(j, '*');
from++;
}
}
writeLine(0, i, size.x, 1, d);
}
#endif
}
void TLifeInterior::getPattern(int pat)
{
if (board == 0) return; //exit if no board
clearBoard();
int i = pat % NPATS;
int *patptr = &patterns[i][0];
int col;
while ((col = *patptr++) != 127)
{
int row = *patptr++;
col += size.x / 2;
row += size.y / 2;
map(col, row) = 1;
}
drawView();
}
void TLifeInterior::handleEvent(TEvent& event)
{
TView::handleEvent(event);
switch (event.what)
{
case evBroadcast:
if (event.message.command == cmUpdate && running)
{
iterateBoard();
drawView();
}
break;
case evCommand:
if (event.message.command >= cmPat01 &&
event.message.command < cmPat01 + NPATS)
{
getPattern(event.message.command - cmPat01);
}
else switch (event.message.command)
{
case cmOneStep:
iterateBoard();
drawView();
break;
case cmClearBoard:
clearBoard();
drawView();
break;
case cmRandom:
randomizeBoard();
drawView();
break;
case cmStartStop:
running = 1 - running;
drawView();
break;
default:
return;
}
clearEvent(event);
break;
case evMouseDown:
handleMouse(event);
}
}
void TLifeInterior::handleMouse(TEvent& event)
{
TRect clickRect = getExtent();
do
{
TPoint mouse = makeLocal(event.mouse.where);
if (clickRect.contains(mouse))
{
if ((event.mouse.buttons & mbLeftButton) != 0)
map(mouse.x, mouse.y) = 1;
if ((event.mouse.buttons & mbRightButton) != 0)
map(mouse.x, mouse.y) = 0;
drawView();
}
}
while (mouseEvent(event, evMouseMove));
clearEvent(event);
}
void TLifeInterior::iterateBoard()
{
if (board == 0) return; //exit if no board
uchar* work = new uchar[size.x * size.y]; //get memory
if (work == 0) return;
//clear board
for (int i = 0; i < size.x * size.y; i++)
work[i] = 0;
int differences = 0;
//iterate
for (int y = 0; y < size.y; y++)
for (int x = 0; x < size.x; x++)
{
//find number of neighbors
int n = present(x-1, y-1) + present(x, y-1) +
present(x+1, y-1) + present(x-1, y) +
present(x+1, y) + present(x-1, y+1) +
present(x, y+1) + present(x+1, y+1);
if (map(x, y) == 1)
{
if (n == 2 || n == 3) map(x, y, work) = 1;
}
if (map(x, y) == 0)
{
if (n == 3) map(x, y, work) = 1;
}
if (map(x, y) != map(x, y, work)) differences++;
}
uchar* old = board; //swap buffers
board = work;
delete[] old;
if (differences == 0) running = 0;
}
uchar& TLifeInterior::map(int x, int y)
{
return board[size.x * y + x];
}
uchar& TLifeInterior::map(int x, int y, uchar* work)
{
return work[size.x * y + x];
}
int TLifeInterior::present(int x, int y)
{
//exit if the position is outside the rectangle
if (x < 0 || x >= size.x || y < 0 || y >= size.y) return 0;
if (board[size.x * y + x] == 0) return 0;
return 1;
}
inline int range(int test, int min, int max)
{
return test < min ? min : test > max ? max : test;
}
void TLifeInterior::randomizeBoard()
{
if (board == 0) return; //exit if no board
clearBoard();
//insert random cells
int howMany = size.x * size.y / 5;
for (int i = 0; i < howMany; i++)
{
int x, y;
do
{
x = (int) (((double) rand() * size.x) / RAND_MAX);
y = (int) (((double) rand() * size.y) / RAND_MAX);
x = range(0, x, size.x - 1);
y = range(0, y, size.y - 1);
}
while (map(x, y) != 0);
map(x, y) = 1;
}
}
void TLifeInterior::setState(ushort aState, Boolean enable)
{
TView::setState(aState, enable);
/* TCommandSet windowCommands;
if ((aState & sfFocused) != 0)
{
if (running) windowCommands += cmStop;
else windowCommands += cmStart;
if (enable != False) enableCommands(windowCommands);
else disableCommands(windowCommands);
}*/
}
TLifeWindow::TLifeWindow(TRect& bounds, char* str, int num):
TWindow(bounds, str, num), TWindowInit(&TLifeWindow::initFrame)
{
options |= ofFirstClick | ofTileable;
TRect r = getClipRect();
r.grow(-1, -1);
insert(life = new TLifeInterior(r));
}
void TLifeWindow::sizeLimits(TPoint &min, TPoint &max)
{
TView::sizeLimits(min, max);
min.x = minW;
min.y = minH;
}
TMyApp::TMyApp(): TProgInit(&TMyApp::initStatusLine, &TMyApp::initMenuBar,
&TMyApp::initDeskTop), windowCommands(getCommands())
{
}
void TMyApp::aboutBox()
{
TDialog *box = new TDialog(TRect(0, 0, 32, 10), "About");
box->insert(new TStaticText(TRect(1, 2, 1+30, 2+5),
"\003TVLIFE\n"
"\003The classic life example\n\n"
"\003Written by Sergio Sigala"));
box->insert(new TButton(TRect(11, 7, 11+10, 9), "O~K~", cmOK,
bfDefault));
box->options |= ofCentered;
executeDialog(box);
}
void TMyApp::createLifeWindow()
{
// TRect r(0, 0, TLifeWindow::minW, TLifeWindow::minH);
// r.move(random() % 53, random() % 16); //randomly move around screen
TRect r;
r = deskTop->getExtent();
r.grow(-1, -1);
TView *w = validView(new TLifeWindow(r, "Life", 0));
if (w != 0) deskTop->insert(w);
}
TCommandSet TMyApp::getCommands()
{
TCommandSet wc;
wc += cmCascade; //add window commands
wc += cmClearBoard;
wc += cmOneStep;
wc += cmRandom;
wc += cmStartStop;
wc += cmTile;
for (uint i = 0; i < NPATS; i++) //scan pattern commands
{
wc += cmPat01 + i; //add pattern commands
}
return wc;
}
void TMyApp::handleEvent(TEvent &event)
{
TApplication::handleEvent(event);
if (event.what == evCommand)
{
switch (event.message.command)
{
case cmAbout:
aboutBox();
break;
case cmCascade:
deskTop->cascade(deskTop->getExtent());
break;
case cmCreate:
createLifeWindow();
break;
case cmTile:
deskTop->tile(deskTop->getExtent());
break;
default:
return;
}
clearEvent(event);
}
}
static Boolean isTileable(TView *p, void *)
{
if ((p->options & ofTileable) != 0) return True;
else return False;
}
void TMyApp::idle()
{
TApplication::idle();
if (deskTop->firstThat(isTileable, 0) != 0)
enableCommands(windowCommands);
else disableCommands(windowCommands);
message(deskTop, evBroadcast, cmUpdate, 0);
}
#define ITEM(name, comm) *new TMenuItem(name, comm, kbNoKey, hcNoContext)
TMenuBar* TMyApp::initMenuBar(TRect r)
{
TSubMenu& sub1 = *new TSubMenu("~\360~", 0, hcNoContext) +
*new TMenuItem("~A~bout...", cmAbout, kbNoKey, hcNoContext);
TSubMenu& sub2 = *new TSubMenu("~F~ile", 0) +
*new TMenuItem("~L~ife window", cmCreate, kbF9, hcNoContext, "F9") +
newLine() +
*new TMenuItem("E~x~it", cmQuit, kbAltX, hcNoContext, "Alt-X");
TSubMenu& sub3 = *new TSubMenu("~A~ction", 0) +
*new TMenuItem("~C~lear", cmClearBoard, kbNoKey, hcNoContext) +
*new TMenuItem("~O~ne step", cmOneStep, kbNoKey, hcNoContext) +
*new TMenuItem("~R~andomize", cmRandom, kbNoKey, hcNoContext) +
*new TMenuItem("~S~tart/Stop", cmStartStop, kbNoKey, hcNoContext);
TSubMenu& sub4 = *new TSubMenu("~W~indow", 0) +
*new TMenuItem("~S~ize/move", cmResize, kbCtrlF5, hcNoContext, "Ctrl-F5") +
*new TMenuItem("~Z~oom", cmZoom, kbF5, hcNoContext, "F5") +
*new TMenuItem("~N~ext", cmNext, kbF6, hcNoContext, "F6") +
*new TMenuItem("~P~revious", cmPrev, kbShiftF6, hcNoContext, "Shift-F6") +
*new TMenuItem("~C~lose", cmClose, kbAltF3, hcNoContext, "Alt-F3") +
newLine() +
*new TMenuItem("~T~ile", cmTile, kbNoKey, hcNoContext) +
*new TMenuItem("C~a~scade", cmCascade, kbNoKey, hcNoContext);
TSubMenu& sub5 = *new TSubMenu("Patterns ~1~", 0) +
ITEM("Glider Gun", cmPat01) +
ITEM("Figure Eight", cmPat02) +
ITEM("Pulsar", cmPat03) +
ITEM("Barber Pole P2", cmPat04) +
ITEM("Achim P5", cmPat05) +
ITEM("Hertz P4", cmPat06) +
ITEM("Tumbler", cmPat07) +
ITEM("Pulse1 P4", cmPat08) +
ITEM("Shining Flower P5", cmPat09) +
ITEM("Pulse2 P6", cmPat10) +
ITEM("Pinwheel, Clock P4", cmPat11) +
ITEM("Pentadecatholon", cmPat12) +
ITEM("Piston", cmPat13) +
ITEM("Piston2", cmPat14) +
ITEM("Switch Engine", cmPat15);
TSubMenu& sub6 = *new TSubMenu("Patterns ~2~", 0) +
ITEM("Gears (Gear, Flywheel, Blinker)", cmPat16) +
ITEM("Turbine8", cmPat17) +
ITEM("P16", cmPat18) +
ITEM("Puffer", cmPat19) +
ITEM("Escort", cmPat20) +
ITEM("Dart Speed 1/3", cmPat21) +
ITEM("Period 4 Speed 1/2", cmPat22) +
ITEM("Another Period 4 Speed 1/2", cmPat23) +
ITEM("Smallest Known Period 3 Spaceship Speed 1/3", cmPat24) +
ITEM("Turtle Speed 1/3", cmPat25) +
ITEM("Smallest Known Period 5 Speed 2/5", cmPat26) +
ITEM("Sym Puffer", cmPat27) +
ITEM("], Near Ship, Pi Heptomino", cmPat28) +
ITEM("R Pentomino", cmPat29);
r.b.y = r.a.y + 1;
return new TMenuBar(r, sub1 + sub2 + sub3 + sub4 + sub5 + sub6);
}
TStatusLine* TMyApp::initStatusLine(TRect r)
{
r.a.y = r.b.y - 1;
return new TStatusLine(r,
*new TStatusDef(0, 50) +
*new TStatusItem("~Alt-X~ Exit", kbAltX, cmQuit) +
*new TStatusItem("~F9~ Life Window", kbF9, cmCreate) +
*new TStatusItem("~Alt-F3~ Close", kbAltF3, cmClose) +
*new TStatusItem("One step", kbNoKey, cmOneStep) +
*new TStatusItem("Randomize", kbNoKey, cmRandom) +
*new TStatusItem("Start/Stop", kbNoKey, cmStartStop) +
*new TStatusItem(0, kbF10, cmMenu) +
*new TStatusItem(0, kbF5, cmZoom) +
*new TStatusItem(0, kbCtrlF5, cmResize));
}
int main()
{
TMyApp a;
a.run();
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1