home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************
- *
- * HyperSimple.c
- *
- * Simple XCmd for Hypercard 2.0 that demonstrates the use
- * of the external windows extensions. This will compile
- * with MPW or THINK (at least 4.0.4).
- *
- * These calls are actually fairly easy to use. There are,
- * naturally, some holes in the documentation. For instance,
- * while you as the XCMD writer *do* own the window's refCon,
- * you *do not* own the windowKind field, which is used by
- * Hypercard to keep track of the windows.
- *
- * Here's the MPW build stuff:
-
- HyperSimple ƒƒ HyperSimple.c.o HyperXLib.o
- Link -w -t rsrc -c RSED -rt XCMD=1000 -m MAIN -sg HyperSimple -sym on -mf ∂
- HyperSimple.c.o HyperXLib.o ∂
- "{CLibraries}"StdClib.o ∂
- "{CLibraries}"CInterface.o ∂
- "{CLibraries}"CRuntime.o ∂
- "{Libraries}"Interface.o ∂
- -o HyperSimple
-
- HyperSimple.c.o ƒ HyperSimple.c
- C -sym on -b -r HyperSimple.c
-
- * The THINK C project format is:
- *
- * Name: HyperSimple
- * Type: XCMD
- * ID: 1000
- * Attrs: 20 (purgeable)
- *
- * Use <MacHeaders>
- *
- * Libraries included:
- * MacTraps
- * HyperXLib.π
- * ANSI-A4 (for strlen)
- *
- * This is sample code, so I hope that you learn from it.
- * Please note, however, that it is:
- *
- * Copyright © 1990 Bill Hofmann, All rights reserved
- *
- * Any comments or questions are welcome, and can be addressed to:
- *
- * Bill Hofmann
- * PO Box 460904
- * San Francisco CA 94146
- *
- * Internet: wdh@well.sf.ca.us
- * AppleLink: D6082
- *
- * Enjoy!
- *
- * Edit history
- *
- * 10/30/90 wdh created
- * 12/22/90 wdh revised and documented
- *
- ****************************************************************/
-
- #include "MPWandTHINK.h"
-
- #ifdef THINK_C
- #include <string.h>
- #else /* MPW */
- #include <Memory.h>
- #include <ToolUtils.h>
- #include <String.h>
- #endif THINK_C
- #include "HyperXCmd.h"
-
- #ifndef NIL
- #define NIL ((void *) 0)
- #endif NIL
-
- /****************************************************************/
- /******** Defines *********/
- /****************************************************************/
-
- #define msgUsage "HyperSimple <title> [, <bounds rect> ]]"
- #define msgVersion "HyperSimple v1.0 12/22/90 © Bill Hofmann"
- #define msgBadDiameter "Error: Diameter must be greater than zero."
- #define msgBadWindowSize "Error: New window size must be greater than \"32, 32\"."
- #define msgParmErr "Parameter error."
-
- #define supportedProperties \
- "loc, visible, properties, diameter, size"
-
- #define strDefaultTitle "\pUntitled"
-
- #define kDefaultDiameter 20
-
- /****************************************************************/
- /******** typedefs *********/
- /****************************************************************/
-
- typedef struct {
- Point center;
- long color;
- } windoid_object;
-
- typedef struct {
- short diameter;
- short numObjects;
- windoid_object obj[100];
- } wobj, ** wobjhdl;
-
- /****************************************************************/
- /******** Prototypes *********/
- /****************************************************************/
-
- void CreateWindoid(const XCmdPtr paramPtr);
- void HandleEvent(const XCmdPtr paramPtr, const XWEventInfoPtr event);
- void do_circle(const wobjhdl wobjh, const windoid_object what);
- void do_activate(const XCmdPtr paramPtr, const WindowPtr wp, const short modifiers);
- void do_update(const WindowPtr wp);
- void do_click(const XCmdPtr paramPtr, const EventRecord * evnt, WindowPtr wp);
- void do_key(const XCmdPtr paramPtr, const EventRecord * evnt, const WindowPtr wp);
- void doCloseEvt(const XCmdPtr paramPtr, const XWEventInfoPtr evnt);
- OSType GetFirstFourLwr(const StringPtr what);
- void doSetPropEvt(const XCmdPtr paramPtr, const XWEventInfoPtr evnt);
- void doGetPropEvt(const XCmdPtr paramPtr, const XWEventInfoPtr evnt);
- void doCursorWithin(const XCmdPtr paramPtr, const XWEventInfoPtr evnt);
- void do_content_click(const WindowPtr wp, Point where);
- void do_mfevent(const XCmdPtr paramPtr, const WindowPtr wp, const long message);
- void LocalToGlobalRect(const Rect * rectP);
- Handle strToParam(const char * str);
-
- /****************************************************************/
- /******** Code *********/
- /****************************************************************/
-
- pascal void
- main(const XCmdPtr paramPtr)
- {
- XWEventInfoPtr event;
-
- paramPtr->returnValue = NIL;
- paramPtr->passFlag = false;
-
- /* If paramCount is less than zero, the first params entry is a pointer to a
- * XWEventInfo record-Hypercard is passing us control to handle an event
- * for a window we've created.
- */
- if (paramPtr->paramCount < 0)
- {
- event = (XWEventInfoPtr)paramPtr->params[0];
- HandleEvent(paramPtr,event);
- }
- /* Otherwise, the user has invoked the XCMD */
- else if (paramPtr->paramCount >= 1)
- {
- /* Apple now recommends that all XCMDs and XFCNs support the following two
- * commands: <name> ! and <name> ?, no matter how many parameters they
- * normally get.
- */
- if (paramPtr->paramCount == 1)
- {
- if (**(paramPtr->params[0]) == '!')
- {
- paramPtr->returnValue = strToParam(msgVersion);
- return;
- }
- else if (**(paramPtr->params[0]) == '?')
- {
- paramPtr->returnValue = strToParam(msgUsage);
- return;
- }
- }
- /* This particular XCMD creates a window, with the user optionally specifying
- * a few arguments.
- */
- CreateWindoid(paramPtr);
- }
- else
- paramPtr->returnValue = strToParam(msgUsage);
- return;
- }
-
- /*
- * Handle an event, either a system event or a Hypercard event.
- */
-
- void
- HandleEvent(const XCmdPtr paramPtr, const XWEventInfoPtr evnt)
- {
- WindowPtr wp;
- GrafPtr savePort;
-
- wp = evnt->eventWindow;
-
- GetPort(&savePort);
- SetPort(wp);
-
- switch (evnt->event.what)
- {
- /* These are system events */
- case mouseDown:
- do_click(paramPtr, &evnt->event, wp);
- break;
- case keyDown:
- case autoKey:
- do_key(paramPtr, &evnt->event, wp);
- break;
- case updateEvt:
- do_update(wp);
- break;
- case activateEvt:
- do_activate(paramPtr, wp, evnt->event.modifiers);
- break;
- case nullEvent:
- break;
- case app4Evt:
- do_mfevent(paramPtr, wp, evnt->event.message);
- break;
-
- /* These are Hypercard events */
- case xOpenEvt:
- /* Hypercard gives us this event just after it creates a window for us.
- * We should do initialization stuff here that isn't done when we
- * create the window
- */
- break;
- case xCloseEvt:
- doCloseEvt(paramPtr, evnt);
- break;
-
- case xHidePalettesEvt:
- case xShowPalettesEvt:
- ShowHide(evnt->eventWindow, (evnt->event.what == xShowPalettesEvt));
- break;
-
- /* A user (or another XCMD) can send a message to one of our windows */
- case xSendEvt:
- break;
-
- /* "get the … of window …" or set the … of window … to …" */
- case xSetPropEvt:
- doSetPropEvt(paramPtr, evnt);
- break;
- case xGetPropEvt:
- doGetPropEvt(paramPtr, evnt);
- break;
-
- /* This is the Hypercard equivalent of a mouse-moved event */
- case xCursorWithin:
- doCursorWithin(paramPtr, evnt);
- break;
-
- /* Not playing a sound, so ignore this */
- case xGiveUpSoundEvt:
- break;
-
- /* We never claim edit, so ignore these */
- case xGiveUpEditEvt:
- case xEditUndo:
- case xEditCut:
- case xEditCopy:
- case xEditPaste:
- case xEditClear:
- break;
-
- /* We have no menus, so ignore these */
- case xMenuEvt:
- case xMBarClickedEvt:
- break;
-
- /* We're not writing a debugger or script editor, so ignore these */
- case xShowWatchInfoEvt:
- case xScriptErrorEvt:
- case xDebugErrorEvt:
- case xDebugStepEvt:
- case xDebugTraceEvt:
- case xDebugFinishedEvt:
- break;
- }
- SetPort(savePort);
- return;
- }
-
- /*
- * Create a simple window that will allow the user to draw circles,
- * with some optional parameters possible
- */
- void
- CreateWindoid(const XCmdPtr paramPtr)
- {
- wobjhdl wobjh;
- WindowPtr wp;
- WindowPtr frontDoc;
- Str255 title;
- Byte boundsStr[64];
- Rect bounds;
- short paramCount;
- short index = 0;
-
- paramCount = paramPtr->paramCount;
-
- /* The first argument is the window title */
- if (--paramCount >= 0)
- ZeroToPas(paramPtr, *paramPtr->params[index++], title);
- else
- BlockMove(strDefaultTitle, title, strlen(strDefaultTitle) + 1);
-
- /* The second default argument is the bounding rectangle of the
- * window, relative to the front document window, which is
- * presumably the stack which called us.
- */
- if (--paramCount >= 0)
- {
- ZeroToPas(paramPtr, *paramPtr->params[index++], boundsStr);
- StrToRect(paramPtr, boundsStr, &bounds);
- if (paramPtr->result != xresSucc)
- SetRect(&bounds,20,20,270,270);
- }
- else
- SetRect(&bounds,20,20,270,270);
- frontDoc = FrontDocWindow(paramPtr);
- SetPort(frontDoc);
- LocalToGlobalRect(&bounds);
-
- if (wp = NewXWindow(paramPtr,&bounds,title,true,noGrowDocProc,true,false))
- {
- wobjh = (wobjhdl)NewHandleClear(sizeof(wobj));
- if (wobjh != NIL)
- {
- (*wobjh)->diameter = kDefaultDiameter;
- (*wobjh)->numObjects = 0;
- }
- SetWRefCon(wp,(long)wobjh);
- SelectWindow(wp);
- }
- }
-
- /*
- * These are the system event handling routines
- */
-
- void
- do_click(const XCmdPtr paramPtr, const EventRecord * evnt, WindowPtr wp)
- {
- GrafPtr wMgrPort;
- wobjhdl wobjh;
- short part;
-
- switch (part = FindWindow(evnt->where,&wp))
- {
- case inContent:
- wobjh = (wobjhdl) GetWRefCon(wp);
- if (wobjh)
- {
- /* Register to receive keystrokes whenever the user clicks in
- * our window. We're not doing a whole lot with them,
- * but this is the place to register.
- */
- BeginXWEdit(paramPtr, wp);
- if (FrontDocWindow(paramPtr) != wp)
- SelectWindow(wp);
- else
- do_content_click(wp, evnt->where);
- }
- break;
- case inDrag:
- /* We can't get the QD globals easily, look at the Window Manager port.
- * This is equivalent to screenBits.bounds.
- */
- GetWMgrPort(&wMgrPort);
- DragWindow(wp,evnt->where,&wMgrPort->portRect);
- break;
- case inGoAway:
- if (TrackGoAway(wp,evnt->where))
- CloseXWindow(paramPtr,wp);
- break;
- default: /* inGrow, inZoomIn, inZoomOut */
- break;
- }
- return;
- }
-
- void
- do_content_click(const WindowPtr wp, Point where)
- {
- wobjhdl wobjh;
- short i;
- long color;
-
- /* The port is already set */
- GlobalToLocal(&where);
- if (wobjh = (wobjhdl)GetWRefCon(wp))
- {
- if ((*wobjh)->numObjects < 100)
- {
- i = (Random() / 8192) + 4;
- switch (i)
- {
- case 0:
- case 1:
- color = redColor;
- break;
- case 2:
- color = greenColor;
- break;
- case 3:
- color = blueColor;
- break;
- case 4:
- color = cyanColor;
- break;
- case 5:
- color = magentaColor;
- break;
- case 6:
- color = yellowColor;
- break;
- case 7:
- color = blackColor;
- break;
- }
- (*wobjh)->obj[(*wobjh)->numObjects].center = where;
- (*wobjh)->obj[(*wobjh)->numObjects].color = color;
- do_circle(wobjh, (*wobjh)->obj[(*wobjh)->numObjects]);
- (*wobjh)->numObjects++;
- }
- }
- return;
- }
-
- void
- do_key(const XCmdPtr paramPtr, const EventRecord * evnt, WindowPtr wp)
- {
- #pragma unused(paramPtr)
- wobjhdl wobjh = (wobjhdl) GetWRefCon(wp);
- long color;
- Point where;
-
- /* This is a fairly lame thing to do, but the begin and end edit stuff
- * isn't entirely intuitive, so I put it in.
- */
- if (wobjh && ((*wobjh)->numObjects < 100))
- {
- switch (evnt->message & charCodeMask)
- {
- case 'r':
- case 'R':
- color = redColor;
- break;
- case 'g':
- case 'G':
- color = greenColor;
- break;
- case 'b':
- case 'B':
- color = blueColor;
- break;
- case 'c':
- case 'C':
- color = cyanColor;
- break;
- case 'm':
- case 'M':
- color = magentaColor;
- break;
- case 'y':
- case 'Y':
- color = yellowColor;
- break;
- default:
- SysBeep(1);
- return;
- }
- /* Pick some random location, normalized between 0..max window size */
- where.h = (Random() / (65536L / wp->portRect.right)) + (wp->portRect.right >> 1);
- where.v = (Random() / (65536L / wp->portRect.bottom)) + (wp->portRect.bottom >> 1);
- (*wobjh)->obj[(*wobjh)->numObjects].center = where;
- (*wobjh)->obj[(*wobjh)->numObjects].color = color;
- do_circle(wobjh, (*wobjh)->obj[(*wobjh)->numObjects]);
- (*wobjh)->numObjects++;
- }
- return;
- }
-
- void
- do_activate(const XCmdPtr paramPtr, const WindowPtr wp, const short modifiers)
- {
- /* Here's where we'd show or hide controls and call DrawGrowIcon */
- if (modifiers & activeFlag)
- BeginXWEdit(paramPtr, wp);
- else
- EndXWEdit(paramPtr, wp);
- return;
- }
-
- void
- do_mfevent(const XCmdPtr paramPtr, const WindowPtr wp, const long message)
- {
- #pragma unused(paramPtr)
-
- if (((message&osEvtMessageMask) >> 24) == suspendResumeMessage)
- do_activate(paramPtr, wp, (short)message);
- return;
- }
-
- void
- do_update(const WindowPtr wp)
- {
- wobjhdl wobjh;
- short i;
-
- /* Port is already set */
- BeginUpdate(wp);
- EraseRect(&wp->portRect);
- if (wobjh = (wobjhdl)GetWRefCon(wp))
- {
- for (i = 0; i < (*wobjh)->numObjects; i++)
- do_circle(wobjh, (*wobjh)->obj[i]);
- }
- EndUpdate(wp);
- }
-
- void
- do_circle(const wobjhdl wobjh, const windoid_object what)
- {
- Rect bounds;
- Point where = what.center;
- short radius = (*wobjh)->diameter / 2;
-
- /* Port is already set */
- ForeColor(what.color);
- SetRect(&bounds,where.h - radius, where.v - radius,
- where.h + radius, where.v + radius);
- PaintOval(&bounds);
- ForeColor(blackColor);
- return;
- }
-
- /*
- * These are the routines to support Hypercard events.
- */
-
- void
- doCloseEvt(XCmdPtr paramPtr, XWEventInfoPtr evnt)
- {
- wobjhdl wobjh;
-
- EndXWEdit(paramPtr, evnt->eventWindow);
- if (wobjh = (wobjhdl)GetWRefCon(evnt->eventWindow))
- DisposHandle((Handle)wobjh);
- /* If we don't set passFlag to true, Hypercard gets all confused */
- paramPtr->passFlag = true;
- return;
- }
-
- void
- doSetPropEvt(const XCmdPtr paramPtr, const XWEventInfoPtr evnt)
- {
- WindowPtr wp;
- StringPtr property;
- Str255 value;
- long propCode;
- long diameter;
- Point newSize;
- wobjhdl wobjh;
- OSErr err = noErr;
- Boolean passIt = false;
-
- property = (StringPtr)evnt->eventParams[0]; /* pstring */
- ReturnToPas(paramPtr,*(Handle)evnt->eventParams[1],value);
- wp = evnt->eventWindow;
- wobjh = (wobjhdl)GetWRefCon(wp);
-
- propCode = GetFirstFourLwr(property);
- if (property[0] >= 1 &&
- StringMatch(paramPtr, property, supportedProperties) != NIL)
- {
- switch (propCode)
- {
- case 'diam':
- diameter = StrToNum(paramPtr, value);
- if (paramPtr->result != xresSucc || diameter <= 0)
- {
- err = 1;
- paramPtr->returnValue = strToParam(msgBadDiameter);
- break;
- }
- (*wobjh)->diameter = diameter;
- InvalRect(&wp->portRect);
- break;
- case 'size':
- StrToPoint(paramPtr, value, &newSize);
- if (paramPtr->result != xresSucc ||
- newSize.h <= 32 || newSize.v <= 32)
- {
- err = 1;
- paramPtr->returnValue = strToParam(msgBadWindowSize);
- break;
- }
- SizeWindow(wp, newSize.h, newSize.v, true);
- break;
- }
- }
- else /* Haven't a clue. Pass it on. */
- passIt = true;
-
- /* All done. Check err. If != noErr, complain */
- if (err > 0) /* internal error */
- paramPtr->result = xresFail;
- paramPtr->passFlag = passIt; /* pass the event */
- return;
- }
-
- void
- doGetPropEvt(const XCmdPtr paramPtr, const XWEventInfoPtr evnt)
- {
- WindowPtr wp;
- StringPtr property;
- Str255 value;
- long propCode;
- Point curSize;
- wobjhdl wobjh;
- Boolean passIt = false;
-
- property = (StringPtr)evnt->eventParams[0];
- wp = evnt->eventWindow;
- wobjh = (wobjhdl)GetWRefCon(wp);
-
- /* return the value in the eventResult field */
- propCode = GetFirstFourLwr(property);
- evnt->eventResult = NIL;
-
- propCode = GetFirstFourLwr(property);
- if (property[0] >= 1 &&
- StringMatch(paramPtr, property, supportedProperties) != NIL)
- {
- switch (propCode)
- {
- case 'diam':
- NumToStr(paramPtr, (*wobjh)->diameter, value);
- evnt->eventResult = PasToZero(paramPtr, value);
- break;
- case 'size':
- curSize.h = wp->portRect.right - wp->portRect.left;
- curSize.v = wp->portRect.bottom - wp->portRect.top;
- PointToStr(paramPtr, curSize, value);
- evnt->eventResult = PasToZero(paramPtr, value);
- break;
- case 'prop':
- evnt->eventResult = strToParam(supportedProperties);
- break;
- default:
- passIt = true;
- break;
- }
- }
- else /* Haven't a clue. Pass it on. */
- passIt = true;
- paramPtr->passFlag = passIt; /* pass the event */
- return;
- }
-
- void
- doCursorWithin(const XCmdPtr paramPtr, const XWEventInfoPtr evnt)
- {
- WindowPtr wp = evnt->eventWindow;
- Point where;
- CursHandle crossHair;
- SignedByte state;
-
- /* The port is set to our window */
- GetMouse(&where);
- if (PtInRgn(where, wp->visRgn))
- {
- if (crossHair = GetCursor(crossCursor))
- {
- state = HGetState((Handle)crossHair);
- HLock((Handle)crossHair);
- SetCursor(*crossHair);
- HSetState((Handle)crossHair, state);
- return; /* leave passFlag false */
- }
- }
- paramPtr->passFlag = true; /* this sets cursor to arrow */
- return;
- }
-
- /****************************************************************/
- /******** Utils *********/
- /****************************************************************/
-
- void
- LocalToGlobalRect(const Rect * rectP)
- {
- LocalToGlobal(&(((Point *) rectP)[0]));
- LocalToGlobal(&(((Point *) rectP)[1]));
- return;
- }
-
- Handle
- strToParam(const char * str)
- {
- Handle out = NIL;
- long len;
-
- if ((len = strlen(str)) && (out = NewHandle(len + 1)))
- BlockMove(str, *out, len + 1);
- return(out);
- }
-
- OSType
- GetFirstFourLwr(const StringPtr what)
- {
- long firstfour;
-
- firstfour = ' '; /* four spaces */
- BlockMove(&what[1],(Ptr)&firstfour,(what[0] < 4) ? what[0] : 4);
- LwrText((Ptr)&firstfour,4);
- return(firstfour);
- }
-
- /*******
- * end *
- *******/
-