home *** CD-ROM | disk | FTP | other *** search
- /* File Example.c Copyright (C) 1996 by John R. Montbriand. All Rights Reserved. */
-
- /* File Example.c
-
- Copyright (C) 1996 by John Montbriand. All Rights Reserved.
-
- Distribute freely in areas where the laws of copyright apply.
-
- Use at your own risk.
-
- Do not distribute modified copies.
-
- These various BitMap libraries and examples are for free!
-
- See the accompanying file BitMap.txt for details.
-
- */
-
- /* written in Geneva 9, tabs at 4 */
-
- /* •••••••••••••••••••••• INCLUDES •••••••••••••••••••••• */
-
- #include <Types.h>
- #include <QuickDraw.h>
- #include <Fonts.h>
- #include <Windows.h>
- #include <Menus.h>
- #include <TextEdit.h>
- #include <Dialogs.h>
- #include <AppleEvents.h>
- #include <TextUtils.h>
- #include <OSUtils.h>
- #include <ToolUtils.h>
- #include <Desk.h>
- #include <Memory.h>
- #include <Errors.h>
- #include <Gestalt.h>
- #include <Resources.h>
- #include <Traps.h>
- #include <SegLoad.h>
-
- #include "BitMap.h"
-
- /* •••••••••••••••••••••• CONSTANTS •••••••••••••••••••••• */
-
- #define kAboutBoxID 128
- #define kErrorBoxID 129
- #define kMainWindID 128
- #define kMenuBarID 128
-
- #define mApple 128
- #define iAbout 1
- #define iAccessoryOne 3
-
- #define mFile 129
- #define iQuit 1
-
- #define mEdit 130
- #define iUndo 1
- #define iCut 3
- #define iCopy 4
- #define iPaste 5
- #define iClear 6
-
- /* •••••••••••••••••••••• GLOBALS •••••••••••••••••••••• */
-
- Boolean PROGRAM_RUNNING = true;
- Boolean PROGRAM_FRONT = true;
- Boolean HAS_APPLEEVENTS = false;
- Boolean HAS_WAITNEXTEVENT = false;
-
- QDGlobals qd;
-
- DialogPtr gABOUTBOX = NULL;
- WindowPtr gMAIN_WINDOW = NULL;
-
-
- /* •••••••••••••••••••••• ERROR HANDLER •••••••••••••••••••••• */
-
- /* Terminate, displays an error box containing the error number and then terminates
- the application. */
- void Terminate(OSErr err) {
- Str255 s;
- NumToString(err, s);
- ParamText(s, NULL, NULL, NULL);
- Alert(kErrorBoxID, NULL);
- ExitToShell();
- }
-
- /* •••••••••••••••••••••• THE EXAMPLE PART •••••••••••••••••••••• */
- /* NOTE: all of the example code to do with bitmaps is included in this part of the
- program. The rest of the program has to do with the usual things that go into
- applications. */
-
- BitMap *adjacencies, *graphimage;
- long **path, start, finish, vertcount;
- Rect gBounds, *vertices;
-
- /*DrawWindowContents is called in response to every update event for the main
- window. this is the part where we do drawing in the bitmaps */
- void DrawWindowContents(WindowPtr wp) {
- BitMap *drawn_bits;
- long i, n, the_vertex;
- BitMapPort* bmp;
-
- /* make a copy of the image for drawing */
- drawn_bits = DuplicateBitMap(graphimage);
- if (drawn_bits == NULL) return;
-
- /* hilite the vertices in the current path */
- n = GetHandleSize((Handle) path) / sizeof(long);
- WithBitMap(drawn_bits, bmp) {
- for (i=0; i<n; i++) {
- the_vertex = (*path)[i];
- InvertRect(vertices + the_vertex);
- }
- }
-
- /* put it on the screen */
- PlotBitMap(drawn_bits, 5, 5, srcCopy);
-
- KillBitMap(drawn_bits);
- }
-
-
- /* herein we use an iterative deepening method for searching the graph
- for paths between two vertices. in other words, this is a depth
- first algorithm that looks only so far and it looks a little further
- every time it's called until it has exhaused every possibility. */
- long *gVisited, gNVertices, **gThePath;
- BitMap *gDiGraph;
-
- Boolean IterativePathSearch(long a, long b, short max_depth) {
- long i, n;
- if (max_depth <= 0) return false;
- if (a == b) {
- if (PtrToXHand(&a, (Handle) gThePath, sizeof(long)) != noErr)
- Terminate(memFullErr);
- return true;
- } else {
- gVisited[a] = 1;
- for (i=0; i<gNVertices; i++)
- if (!gVisited[i] && BitMapTest(gDiGraph, a, i))
- if (IterativePathSearch(i, b, max_depth - 1)) {
- if (PtrAndHand(&a, (Handle) gThePath, sizeof(long)) != noErr)
- Terminate(memFullErr);
- return true;
- }
- gVisited[a] = 0;
- }
- return false;
- }
-
- /* calculates the shortest path from a to b using the adjacency matrix stored in
- the_graph. if a path is found, CalculateNewPath is set to true and the_path
- is set to a list of long integers representing the vertices along the path
- from a to b in reverse order. if no path is found, false is returned and
- the_path is set to a zero length block. */
- Boolean CalculateNewPath(BitMap *the_graph, long** the_path, long a, long b) {
- long i;
- Boolean result;
- result = false;
- gDiGraph = the_graph;
- gThePath = the_path;
- gNVertices = the_graph->bounds.right;
- gVisited = (long*) NewPtrClear(gNVertices*sizeof(long));
- if (gVisited == NULL) Terminate(memFullErr);
- SetHandleSize((Handle) the_path, 0);
- for (i = 1; i < gNVertices; i++)
- if (IterativePathSearch(a, b, i)) {
- result = true;
- break;
- }
- DisposePtr((Ptr) gVisited);
- return result;
- }
-
- /*ClickWindowContents is called every time a mouse down event occurs in the
- main program window allowing for some interaction. */
- void ClickWindowContents(WindowPtr wp, Point where) {
- long i, pathlength, first;
- if (PtInRect(where, &gBounds)) {
- MapPt(&where, &gBounds, &graphimage->bounds);
- pathlength = GetHandleSize((Handle) path)/sizeof(long);
- for ( i=0; i < vertcount; i++) {
- if (PtInRect(where, vertices + i)) {
- if (pathlength != 1) {
- if (PtrToXHand(&i, (Handle) path, sizeof(long)) != noErr)
- Terminate(memFullErr);
- } else {
- CalculateNewPath(adjacencies, path, (*path)[0], i);
- }
- DrawWindowContents(wp);
- return;
- }
- }
- }
- }
-
- /* AddBiDirectionalPath adds a path to the matrix indicating that there
- is a path from a to b and from b to a */
- void AddBiDirectionalPath(BitMap *matrix, short a, short b) {
- BitMapSet(matrix, a, b);
- BitMapSet(matrix, b, a);
- }
-
- /* InitExample is called at program startup after the main window has been
- created to allow the example to set itself up. I put it here so all the example
- code would be together in one section. */
- OSErr InitExample(WindowPtr wp) {
- PicHandle pic;
- Handle vertResource;
-
- /* get the vertices rectangles */
- vertResource = GetResource('RECT', 129);
- if (vertResource == NULL) return resNotFound;
- MoveHHi(vertResource);
- HLock(vertResource);
- vertices = (Rect*) (*vertResource);
- vertcount = GetHandleSize(vertResource)/sizeof(Rect);
-
- /* set up the adjacency matrix */
- adjacencies = NewBitMap(vertcount, vertcount);
- if (adjacencies == NULL) return memFullErr;
- AddBiDirectionalPath(adjacencies, 0, 1);
- AddBiDirectionalPath(adjacencies, 1, 2);
- AddBiDirectionalPath(adjacencies, 1, 4);
- AddBiDirectionalPath(adjacencies, 1, 10);
- AddBiDirectionalPath(adjacencies, 2, 3);
- AddBiDirectionalPath(adjacencies, 3, 4);
- AddBiDirectionalPath(adjacencies, 4, 8);
- AddBiDirectionalPath(adjacencies, 4, 11);
- AddBiDirectionalPath(adjacencies, 5, 8);
- AddBiDirectionalPath(adjacencies, 5, 6);
- AddBiDirectionalPath(adjacencies, 5, 9);
- AddBiDirectionalPath(adjacencies, 7, 8);
- AddBiDirectionalPath(adjacencies, 8, 12);
- AddBiDirectionalPath(adjacencies, 9, 13);
- AddBiDirectionalPath(adjacencies, 10, 11);
- AddBiDirectionalPath(adjacencies, 11, 12);
- AddBiDirectionalPath(adjacencies, 11, 17);
- AddBiDirectionalPath(adjacencies, 12, 13);
- AddBiDirectionalPath(adjacencies, 13, 14);
- AddBiDirectionalPath(adjacencies, 13, 19);
- AddBiDirectionalPath(adjacencies, 15, 16);
- AddBiDirectionalPath(adjacencies, 16, 17);
- AddBiDirectionalPath(adjacencies, 16, 21);
- AddBiDirectionalPath(adjacencies, 17, 18);
- AddBiDirectionalPath(adjacencies, 17, 21);
- AddBiDirectionalPath(adjacencies, 18, 20);
- AddBiDirectionalPath(adjacencies, 19, 20);
- AddBiDirectionalPath(adjacencies, 20, 22);
- AddBiDirectionalPath(adjacencies, 21, 22);
- AddBiDirectionalPath(adjacencies, 22, 23);
-
- /* get the graph image */
- pic = GetPicture(129);
- if (pic == NULL) return resNotFound;
- graphimage = PICTToBitMap(pic);
- if (graphimage == NULL) return memFullErr;
-
- /* set up the graph variables */
- start = finish = -1;
- path = (long**) NewHandle(0);
- if (path == NULL) return memFullErr;
-
- /* adjust the window size */
- SizeWindow(wp, graphimage->bounds.right+10, graphimage->bounds.bottom+10, true);
- gBounds = graphimage->bounds;
- OffsetRect(&gBounds, 5, 5);
-
- /* done */
- return noErr;
- }
-
-
- /* •••••••••••••••••••••• MENU COMMANDS •••••••••••••••••••••• */
-
- /* HandleMenuCommand is called after MenuKey or MenuSelect to handle the processing
- of menu commands. Here there aren't too many, just the standard ones */
- void HandleMenuCommand(short menu, short item) {
- if (menu == mApple) {
- if (item == iAbout) {
- if (gABOUTBOX != NULL)
- SelectWindow(gABOUTBOX);
- else gABOUTBOX = GetNewDialog(kAboutBoxID, NULL, (WindowPtr) (-1));
- } else if (item >= iAccessoryOne) {
- Str255 itemString;
- GetItem(GetMHandle(menu), item, itemString);
- OpenDeskAcc(itemString);
- }
- } else if (menu == mFile) {
- switch (item) {
- case iQuit:
- PROGRAM_RUNNING = false;
- break;
- }
- } else if (menu == mEdit) {
- SystemEdit(item-1);
- }
- HiliteMenu(0);
- }
-
- /* MenuPreflightCheck is called immediately before MenuKey or MenuSelect. In your
- application you would use this routine to appropriately enable or disable different
- commands depending on what can be done at the time of the mouse click or key
- command. */
- void MenuPreflightCheck(void) {
- /* none here*/
- }
-
-
- /* •••••••••••••••••••••• EVENT HANDLING •••••••••••••••••••••• */
-
- /* HandleMouseDownEvent is called to process mouse down events */
- void HandleMouseDownEvent(EventRecord *ev) {
- WindowPtr target;
- switch ( FindWindow(ev->where, &target) ) {
- case inDesk:
- break;
- case inSysWindow:
- SystemClick(ev, target);
- break;
- case inContent:
- if (target != FrontWindow())
- SelectWindow(target);
- else if (target == gMAIN_WINDOW) {
- Point where;
- where = ev->where;
- SetPort(target);
- GlobalToLocal(&where);
- ClickWindowContents(target, where);
- }
- break;
- case inDrag:
- { Rect r = qd.screenBits.bounds;
- if (target != FrontWindow()) SelectWindow(target);
- SetPort(target);
- InsetRect(&r, 4, 4);
- r.top += 20;
- DragWindow(target, ev->where, &r);
- }
- break;
- case inGoAway:
- if (TrackGoAway(target, ev->where)) {
- if (target == gABOUTBOX) {
- DisposeDialog(gABOUTBOX);
- gABOUTBOX = NULL;
- } else PROGRAM_RUNNING = false;
- }
- break;
- case inMenuBar:
- { long mnRes;
- MenuPreflightCheck();
- if (HiWord(mnRes = MenuSelect(ev->where)) != 0)
- HandleMenuCommand(HiWord(mnRes), LoWord(mnRes));
- }
- break;
- }
- }
-
- /* SystemSwapTask can be called from anywhere in your application. basically it collects
- events and gives the system time to do its thing. */
- void SystemSwapTask(void) {
- EventRecord ev;
-
- /* get the next event */
- if (HAS_WAITNEXTEVENT) {
- if (!WaitNextEvent(everyEvent, &ev, 0, NULL)) ev.what = nullEvent;
- } else {
- if (!GetNextEvent(everyEvent, &ev)) ev.what = nullEvent;
- SystemTask();
- }
-
- if ((ev.what == keyDown || ev.what == autoKey) && (ev.modifiers & cmdKey) != 0) {
- long mnRes;
- MenuPreflightCheck();
- if (HiWord(mnRes = MenuKey((char) (ev.message & charCodeMask))) != 0)
- HandleMenuCommand(HiWord(mnRes), LoWord(mnRes));
- } else if (IsDialogEvent(&ev)) {
- DialogPtr theDialog;
- short itemHit;
- DialogSelect(&ev, &theDialog, &itemHit);
- } else if (ev.what == mouseDown) {
- HandleMouseDownEvent(&ev);
- } else if (ev.what == updateEvt) {
- WindowPtr wp;
- wp = (WindowPtr) ev.message;
- SetPort(wp);
- BeginUpdate(wp);
- DrawWindowContents(wp);
- EndUpdate(wp);
- } else if (ev.what == kHighLevelEvent) {
- if (HAS_APPLEEVENTS)
- AEProcessAppleEvent(&ev);
- } else if (ev.what == osEvt) {
- if (((ev.message >> 24) & 0x0FF) == suspendResumeMessage)
- PROGRAM_FRONT = (ev.message & resumeFlag) != 0;
- }
-
- }
-
-
- /* •••••••••••••••••••••• APPLE EVENTS •••••••••••••••••••••• */
-
- /* QuitEventHandler called for quit apple events. all we do here is set the running
- flag to false */
- pascal OSErr QuitEventHandler(const AppleEvent *appleEvt, AppleEvent* reply, long refcon) {
- DescType retType;
- Size actSize;
- OSErr err;
- err = AEGetAttributePtr(appleEvt, keyMissedKeywordAttr, typeWildCard, &retType, NULL, 0, &actSize);
- if (err == errAEDescNotFound) {
- PROGRAM_RUNNING = false;
- return noErr;
- } else if (err == noErr)
- return errAEEventNotHandled;
- else return err;
- }
-
-
- /* •••••••••••••••••••••• TEST FOR TRAPS •••••••••••••••••••••• */
-
- unsigned short NumToolboxTraps(void) {
- if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
- return 0x0200;
- else return 0x0400;
- }
-
- TrapType FindTrapType(unsigned short theTrap) {
- if (theTrap & 0x0800)
- return ToolTrap;
- else return OSTrap;
- }
-
- Boolean TrapAvailable(unsigned short theTrap) {
- unsigned short localTrap = theTrap;
- TrapType tType = FindTrapType(localTrap);
- if ( tType == ToolTrap ) {
- localTrap &= 0x07FF;
- if ( localTrap >= NumToolboxTraps() )
- localTrap = _Unimplemented;
- }
- return NGetTrapAddress(localTrap, tType) != NGetTrapAddress(_Unimplemented, ToolTrap);
- }
-
-
- /* •••••••••••••••••••••• MAIN PROGRAM •••••••••••••••••••••• */
-
- void main(void) {
- OSErr err;
- long response;
-
- /* determine features of the machine */
- if (Gestalt(gestaltAppleEventsAttr, &response) != noErr) response = 0;
- HAS_APPLEEVENTS = ((response & (1<<gestaltAppleEventsPresent)) != 0);
- HAS_WAITNEXTEVENT = TrapAvailable(_WaitNextEvent);
-
- /* initialize the toolbox, etc.. */
- SetApplLimit( GetApplLimit() - (8*1024) );
- MaxApplZone();
- InitGraf(&qd.thePort);
- InitFonts();
- InitWindows();
- TEInit();
- InitMenus();
- InitDialogs(NULL);
- InitCursor();
- if (HAS_APPLEEVENTS) {
- err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
- NewAEEventHandlerProc(QuitEventHandler), 0, false);
- if (err != noErr) goto bail;
- }
- SetMenuBar(GetNewMBar(kMenuBarID));
- AddResMenu(GetMHandle(mApple), 'DRVR');
- DrawMenuBar();
- gMAIN_WINDOW = GetNewWindow(kMainWindID, NULL, (WindowPtr) (-1));
- SetPort(gMAIN_WINDOW);
- err = InitExample(gMAIN_WINDOW);
-
- /* set up some globals */
- PROGRAM_RUNNING = true;
- PROGRAM_FRONT = true;
-
- /* loop until PROGRAM_RUNNING is false */
- while (PROGRAM_RUNNING)
- SystemSwapTask();
-
- return;
-
- bail:
- Terminate(err);
- }
-
-
- /* end File BitMap.c */
-
-