376 lines
10 KiB
C
376 lines
10 KiB
C
// minicad.c - faithful port of ORCA-C's MiniCAD.cc sample.
|
|
//
|
|
// Mike Westerfield, Byte Works 1989. Original at
|
|
// tools/orca-c/C.Samples/Desktop.Samples/MiniCAD.cc.
|
|
//
|
|
// A simple multi-window CAD: File>New opens a drawing window (up to
|
|
// 4), click+drag inside a window's content rubber-bands a line,
|
|
// release commits it. File>Close closes the front window. Each
|
|
// window's lines are remembered so the WM can repaint on update.
|
|
|
|
#include "iigs/toolbox.h"
|
|
#include "iigs/desktop.h"
|
|
|
|
|
|
#define apple_About 257
|
|
#define file_Quit 256
|
|
#define file_New 258
|
|
#define file_Close 255
|
|
|
|
#define wInMenuBar 3
|
|
#define wInSpecial 25
|
|
#define wInGoAway 17
|
|
#define wInContent 19
|
|
|
|
#define mUpMask 0x0002
|
|
|
|
#define modeCopy 0
|
|
#define modeXOR 2
|
|
|
|
#define topMost ((void *)-1L)
|
|
#define bottomMost ((void *)0)
|
|
|
|
#define maxWindows 4
|
|
#define maxLines 50
|
|
|
|
#define norml 0
|
|
#define stop 1
|
|
#define note 2
|
|
#define caution 3
|
|
#define buttonItem 10
|
|
#define statText 136
|
|
#define itemDisable 0x8000
|
|
|
|
|
|
typedef struct { short v1, h1, v2, h2; } Rect;
|
|
typedef struct { short v, h; } Point;
|
|
typedef struct { Point p1, p2; } LineRec;
|
|
|
|
|
|
typedef struct {
|
|
unsigned short wmWhat;
|
|
unsigned long wmMessage;
|
|
unsigned long wmWhen;
|
|
short wmWhereV, wmWhereH;
|
|
unsigned short wmModifiers;
|
|
unsigned long wmTaskData;
|
|
unsigned long wmTaskMask;
|
|
unsigned long wmLastClickTick;
|
|
unsigned long wmClickCount;
|
|
unsigned long wmTaskData2;
|
|
unsigned long wmTaskData3;
|
|
unsigned long wmTaskData4;
|
|
} WmTaskRec;
|
|
|
|
|
|
typedef struct {
|
|
unsigned short wmWhat;
|
|
unsigned long wmMessage;
|
|
unsigned long wmWhen;
|
|
short wmWhereV, wmWhereH;
|
|
unsigned short wmModifiers;
|
|
} EventRec;
|
|
|
|
|
|
typedef struct {
|
|
unsigned short paramLength;
|
|
unsigned short wFrameBits;
|
|
void *wTitle;
|
|
unsigned long wRefCon;
|
|
Rect wZoom;
|
|
void *wColor;
|
|
short wYOrigin, wXOrigin;
|
|
short wDataH, wDataV;
|
|
short wMaxHeight, wMaxWidth;
|
|
short wScrollVer, wScrollHor;
|
|
short wPageVer, wPageHor;
|
|
unsigned long wInfoRefCon;
|
|
short wInfoHeight;
|
|
void *wFrameDefProc;
|
|
void *wInfoDefProc;
|
|
void *wContDefProc;
|
|
Rect wPosition;
|
|
void *wPlane;
|
|
void *wStorage;
|
|
} NewWindowParm;
|
|
|
|
|
|
typedef struct {
|
|
short itemID;
|
|
short itemRectV1, itemRectH1, itemRectV2, itemRectH2;
|
|
unsigned short itemType;
|
|
void *itemDescr;
|
|
short itemValue;
|
|
short itemFlag;
|
|
void *itemColor;
|
|
} ItemTemplate;
|
|
|
|
typedef struct {
|
|
short atRectV1, atRectH1, atRectV2, atRectH2;
|
|
short atBtnHorz;
|
|
short atBeep0, atBeep1, atBeep2, atBeep3;
|
|
void *atSound;
|
|
void *atResv1;
|
|
void *atResv2;
|
|
void *atItemList[8];
|
|
} AlertTemplate;
|
|
|
|
|
|
typedef struct {
|
|
void *wPtr;
|
|
unsigned char *name;
|
|
unsigned short numLines;
|
|
LineRec lines[maxLines];
|
|
} WindowRecord;
|
|
|
|
|
|
static unsigned char editMenuStr[] = ">> Edit \\N3\r"
|
|
"--Undo\\N250V*Zz\r"
|
|
"--Cut\\N251*Xx\r"
|
|
"--Copy\\N252*Cc\r"
|
|
"--Paste\\N253*Vv\r"
|
|
"--Clear\\N254\r"
|
|
".\r";
|
|
|
|
static unsigned char fileMenuStr[] = ">> File \\N2\r"
|
|
"--New\\N258*Nn\r"
|
|
"--Close\\N255V\r"
|
|
"--Quit\\N256*Qq\r"
|
|
".\r";
|
|
|
|
static unsigned char appleMenuStr[] = ">>@\\XN1\r"
|
|
"--About...\\N257V\r"
|
|
".\r";
|
|
|
|
static unsigned char gAboutMsg[] =
|
|
"\x3d" "Mini-CAD 1.0\r"
|
|
"Copyright 1989\r"
|
|
"Byte Works, Inc.\r\r"
|
|
"By Mike Westerfield";
|
|
|
|
static unsigned char gTitle0[] = "\x07Paint 1";
|
|
static unsigned char gTitle1[] = "\x07Paint 2";
|
|
static unsigned char gTitle2[] = "\x07Paint 3";
|
|
static unsigned char gTitle3[] = "\x07Paint 4";
|
|
|
|
static WindowRecord gWindows[maxWindows] = {
|
|
{ (void *)0, gTitle0, 0, { { {0,0}, {0,0} } } },
|
|
{ (void *)0, gTitle1, 0, { { {0,0}, {0,0} } } },
|
|
{ (void *)0, gTitle2, 0, { { {0,0}, {0,0} } } },
|
|
{ (void *)0, gTitle3, 0, { { {0,0}, {0,0} } } }
|
|
};
|
|
|
|
static WmTaskRec gEvent;
|
|
static volatile unsigned short gDone;
|
|
|
|
|
|
static void doAlert(unsigned short kind, void *msg) {
|
|
static unsigned char okStr[] = "\x02OK";
|
|
static ItemTemplate button = {
|
|
1, 36, 15, 0, 0, buttonItem, okStr, 0, 0, (void *)0
|
|
};
|
|
static ItemTemplate message = {
|
|
100, 5, 100, 90, 280, itemDisable | statText, (void *)0, 0, 0, (void *)0
|
|
};
|
|
static AlertTemplate alertRec = {
|
|
50, 180, 107, 460, 2, 0x80, 0x80, 0x80, 0x80,
|
|
(void *)0, (void *)0, (void *)0,
|
|
{ (void *)0, (void *)0, (void *)0, (void *)0,
|
|
(void *)0, (void *)0, (void *)0, (void *)0 }
|
|
};
|
|
SetForeColor(0);
|
|
SetBackColor(15);
|
|
message.itemDescr = msg;
|
|
alertRec.atItemList[0] = (void *)&button;
|
|
alertRec.atItemList[1] = (void *)&message;
|
|
alertRec.atItemList[2] = (void *)0;
|
|
switch (kind) {
|
|
case norml: (void)Alert(&alertRec, (void *)0); break;
|
|
case stop: (void)StopAlert(&alertRec, (void *)0); break;
|
|
case note: (void)NoteAlert(&alertRec, (void *)0); break;
|
|
case caution: (void)CautionAlert(&alertRec, (void *)0); break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
|
|
// Window-content def-proc. The WM calls this with DBR set to our
|
|
// bank (Loader sets up the JSL chain). We use GetWRefCon on the
|
|
// current port to know which gWindows[] entry to redraw.
|
|
static void drawWindow(void) {
|
|
unsigned long refcon = (unsigned long)GetWRefCon(GetPort());
|
|
unsigned short i = (unsigned short)refcon;
|
|
if (i >= maxWindows) return;
|
|
WindowRecord *wp = &gWindows[i];
|
|
if (wp->numLines == 0) return;
|
|
SetPenMode(modeCopy);
|
|
SetSolidPenPat(0);
|
|
SetPenSize(2, 1);
|
|
for (unsigned short j = 0; j < wp->numLines; j++) {
|
|
LineRec *lp = &wp->lines[j];
|
|
MoveTo(lp->p1.h, lp->p1.v);
|
|
LineTo(lp->p2.h, lp->p2.v);
|
|
}
|
|
}
|
|
|
|
|
|
static void doNew(void) {
|
|
static NewWindowParm wp;
|
|
unsigned short i = 0;
|
|
while (i < maxWindows && gWindows[i].wPtr != (void *)0) i++;
|
|
if (i >= maxWindows) return;
|
|
gWindows[i].numLines = 0;
|
|
|
|
unsigned char *p = (unsigned char *)℘
|
|
for (unsigned short k = 0; k < sizeof wp; k++) p[k] = 0;
|
|
wp.paramLength = (unsigned short)sizeof wp;
|
|
wp.wFrameBits = 0x4007 | 0x0020 | 0x0080 | 0x0400 | 0x4000; // fTitle+fClose+fVis+fMove+fGrow
|
|
wp.wTitle = gWindows[i].name;
|
|
wp.wRefCon = (unsigned long)i;
|
|
wp.wMaxHeight = 188;
|
|
wp.wMaxWidth = 615;
|
|
wp.wPosition.v1 = (short)(25 + i * 10);
|
|
wp.wPosition.h1 = (short)(10 + i * 10);
|
|
wp.wPosition.v2 = (short)(180 + i * 10);
|
|
wp.wPosition.h2 = (short)(600 + i * 10);
|
|
wp.wContDefProc = (void *)&drawWindow;
|
|
wp.wPlane = topMost;
|
|
gWindows[i].wPtr = NewWindow(&wp);
|
|
if (i == maxWindows - 1) {
|
|
DisableMItem(file_New);
|
|
}
|
|
}
|
|
|
|
|
|
static void doClose(void) {
|
|
void *fw = FrontWindow();
|
|
if (!fw) return;
|
|
unsigned short i = (unsigned short)(unsigned long)GetWRefCon(fw);
|
|
if (i >= maxWindows) return;
|
|
CloseWindow(gWindows[i].wPtr);
|
|
gWindows[i].wPtr = (void *)0;
|
|
EnableMItem(file_New);
|
|
}
|
|
|
|
|
|
static void menuAbout(void) {
|
|
doAlert(note, gAboutMsg);
|
|
}
|
|
|
|
|
|
static void sketch(void) {
|
|
void *fw = FrontWindow();
|
|
if (!fw) return;
|
|
unsigned short i = (unsigned short)(unsigned long)GetWRefCon(fw);
|
|
if (i >= maxWindows) return;
|
|
if (gWindows[i].numLines >= maxLines) {
|
|
static unsigned char fullMsg[] =
|
|
"\x3a" "The window is full -\r"
|
|
"more lines cannot be\r"
|
|
"added.";
|
|
doAlert(stop, fullMsg);
|
|
return;
|
|
}
|
|
|
|
StartDrawing(fw);
|
|
SetSolidPenPat(15);
|
|
SetPenSize(2, 1);
|
|
SetPenMode(modeXOR);
|
|
|
|
Point firstPt;
|
|
firstPt.h = gEvent.wmWhereH;
|
|
firstPt.v = gEvent.wmWhereV;
|
|
GlobalToLocal(&firstPt);
|
|
MoveTo(firstPt.h, firstPt.v);
|
|
LineTo(firstPt.h, firstPt.v);
|
|
Point endPt = firstPt;
|
|
|
|
EventRec ev;
|
|
while (!GetNextEvent(mUpMask, &ev)) {
|
|
Point cur;
|
|
cur.h = ev.wmWhereH;
|
|
cur.v = ev.wmWhereV;
|
|
GlobalToLocal(&cur);
|
|
if (cur.h != endPt.h || cur.v != endPt.v) {
|
|
MoveTo(firstPt.h, firstPt.v);
|
|
LineTo(endPt.h, endPt.v);
|
|
MoveTo(firstPt.h, firstPt.v);
|
|
LineTo(cur.h, cur.v);
|
|
endPt = cur;
|
|
}
|
|
}
|
|
|
|
// Erase final XOR line.
|
|
MoveTo(firstPt.h, firstPt.v);
|
|
LineTo(endPt.h, endPt.v);
|
|
|
|
if (firstPt.h != endPt.h || firstPt.v != endPt.v) {
|
|
unsigned short n = gWindows[i].numLines++;
|
|
gWindows[i].lines[n].p1 = firstPt;
|
|
gWindows[i].lines[n].p2 = endPt;
|
|
SetPenMode(modeCopy);
|
|
SetSolidPenPat(0);
|
|
MoveTo(firstPt.h, firstPt.v);
|
|
LineTo(endPt.h, endPt.v);
|
|
}
|
|
}
|
|
|
|
|
|
static void handleMenu(unsigned short menuNum) {
|
|
switch (menuNum) {
|
|
case apple_About: menuAbout(); break;
|
|
case file_Quit: gDone = 1; break;
|
|
case file_New: doNew(); break;
|
|
case file_Close: doClose(); break;
|
|
default: break;
|
|
}
|
|
HiliteMenu(0, (unsigned short)(gEvent.wmTaskData >> 16));
|
|
}
|
|
|
|
|
|
static void initMenus(void) {
|
|
InsertMenu(NewMenu(editMenuStr), 0);
|
|
InsertMenu(NewMenu(fileMenuStr), 0);
|
|
InsertMenu(NewMenu(appleMenuStr), 0);
|
|
FixAppleMenu(1);
|
|
FixMenuBar();
|
|
DrawMenuBar();
|
|
}
|
|
|
|
|
|
int main(void) {
|
|
unsigned short userId = startdesk(640);
|
|
(void)userId;
|
|
|
|
paintDesktopBackdrop();
|
|
initMenus();
|
|
gEvent.wmTaskMask = 0x1FFFL;
|
|
ShowCursor();
|
|
|
|
// Open one window so the demo has visible content immediately.
|
|
doNew();
|
|
|
|
gDone = 0;
|
|
unsigned short watchdog = 0;
|
|
do {
|
|
unsigned short event = TaskMaster(0x076E, &gEvent);
|
|
switch (event) {
|
|
case wInSpecial:
|
|
case wInMenuBar:
|
|
handleMenu((unsigned short)gEvent.wmTaskData);
|
|
break;
|
|
case wInGoAway:
|
|
doClose();
|
|
break;
|
|
case wInContent:
|
|
sketch();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
watchdog++;
|
|
} while (!gDone && watchdog < 4000);
|
|
|
|
*(volatile unsigned char *)0x70 = 0x99;
|
|
return 0;
|
|
}
|