home *** CD-ROM | disk | FTP | other *** search
- #include <Carbon/Carbon.h>
-
- #define kTreeAppSignature 'tree'
- #define kDrawCommand 'draw'
- #define kTreeResizeCommand 'rsiz'
- #define kDrawContinuousCommand 'cont'
- #define kDepthSliderID 128
- #define kContinuousCheckboxID 129
- #define kTreeOpenAboutWindowCommand 'abut'
- #define kTreeVersionInfoID 132
-
- static const int kInitialSize = 128;
- static Point gStart = {500,500};
- static const UInt32 kControlToTreePadding = 12;
- static UInt32 gDepth = 1;
- static Boolean gContinuousDraw = 1;
- static EventLoopTimerRef gDrawTimer;
- static UInt32 gFlushTicks;
-
- EventTypeSpec gTreeEvents[] = {
- { kEventClassWindow, kEventWindowClose },
- { kEventClassWindow, kEventWindowDrawContent },
- { kEventClassWindow, kEventWindowBoundsChanged },
- { kEventClassWindow, kEventWindowClose},
- { kEventClassCommand, kEventCommandProcess},
- };
- EventTypeSpec closeSpec = {kEventClassWindow, kEventWindowClose};
-
- WindowRef gTreeWindow, gAboutWindow;
-
- pascal OSStatus TreeAboutWindowEventHandler(EventHandlerCallRef handlerRef, EventRef event, void* userData)
- {
- OSStatus result = eventNotHandledErr;
- UInt32 eventKind;
-
- eventKind = GetEventKind(event);
- if (eventKind==kEventWindowClose)
- {
- HideWindow((WindowRef) userData);
- result = noErr;
- }
- return result;
- }
-
- pascal void TreeAboutWindowCommandHandler(WindowRef window)
- {
- CFStringRef text;
- CFBundleRef bundle;
- ControlID versionInfoID = {kTreeAppSignature, kTreeVersionInfoID};
- ControlRef versionControl;
- ControlFontStyleRec controlStyle;
-
- bundle = CFBundleGetMainBundle();
- text = (CFStringRef) CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("CFBundleGetInfoString"));
- if ((text == CFSTR(" ")) || text == NULL)
- text = CFSTR("Nameless Application.");
- GetControlByID(window, &versionInfoID, &versionControl);
- SetControlData(versionControl, kControlLabelPart,
- kControlStaticTextCFStringTag, sizeof(CFStringRef), &text);
- controlStyle.flags = kControlUseJustMask;
- controlStyle.just = teCenter;
- SetControlFontStyle( versionControl, &controlStyle);
- ShowWindow(window);
- SelectWindow(window);
- }
-
- typedef struct BranchVector {
- int x;
- int y;
- } BranchVector;
-
- // Couldn't remember how to spell the Abs function, so I wrote my own...
- static int Abs(int x)
- {
- if (x<0) return -x;
- return x;
- }
-
- static void DoubleVector(BranchVector* v)
- {
- v->x += v->x;
- v->y += v->y;
- }
-
- // This will cause a rounding problem if we ever get odd numbers
- // so powers of two should be used for the initial tree size.
- static void HalfVector(BranchVector* v)
- {
- v->x >>= 1; // shift right one to divide by two fast.
- v->y >>= 1;
- }
-
- // Is a vector "extra long"?
- // We cheat when turning 45 degrees...
- // diagonal vectors are inherently longer
- // than the non diagonals, which automatically
- // scales a vector up or down any time you turn it
- // by an odd multiple of 45 degrees.
- static Boolean LongVector(BranchVector* v)
- {
- return (Abs(v->x) == Abs(v->y));
- }
-
- static void Turn180(BranchVector* v)
- {
- // flip both signs
- v->x = -v->x;
- v->y = -v->y;
- }
-
- #ifdef TurnLeft45TruthTable
- // I used this table to figure out a 45 degree left turn algorithem.
- 0,1 -1,1
- 1,1 0,1
- 1,0 1,1
- 1,-1 1,0
- 0,-1 1,-1
- -1,-1 0,-1
- -1,0 -1,-1
- -1,1 -1,0
- #endif
-
- static void Left45(BranchVector* v)
- {
- // make a first guess, values don't change
- // and just fix the component that is wrong
- if (v->x == v->y) // 1,1 or -1,-1
- v->x = 0;
- else if (Abs(v->x) == Abs(v->y)) // 1,-1 or -1,1
- v->y = 0;
- else if (v->x == 0) // 0,1 or 0,-1
- v->x = -v->y;
- else // 1,0 or -1,0
- v->y = v->x;
- }
-
- #ifdef TurnRight90TruthTable
- // I used this table to figure out a 90 degree right turn algorithem.
- 0,1 1,0
- 1,1 1,-1
- 1,0 0,-1
- 1,-1 -1,-1
- 0,-1 -1,0
- -1,-1 -1,1
- -1,0 0,1
- -1,1 1,1
- #endif
-
- static void Right90(BranchVector* v)
- {
- // flip x and y, switching the x sign, to turn right
- int temp = v->x;
- v->x = v->y;
- v->y = -temp;
- }
-
- static void DrawVector(BranchVector* v)
- {
- Line(v->x, -v->y);
- }
-
- static void Left45Smaller(BranchVector* v)
- {
- Left45(v); // diagonal vectors are inherently longer...
- if (LongVector(v)) // if it got longer, make it smaller
- HalfVector(v); // otherwise it already is smaller than the diagonal original
- }
-
- static void Left45Bigger(BranchVector* v)
- {
- DoubleVector(v);
- Left45Smaller(v);
- }
-
- static void Right135Bigger(BranchVector* v)
- {
- Turn180(v);
- Left45Bigger(v);
- }
-
- static void Right135Smaller(BranchVector* v)
- {
- Turn180(v);
- Left45Smaller(v);
- }
-
- static Rect TreeBounds(WindowRef window)
- {
- Rect bounds;
-
- SetPortWindowPort(window);
- GetWindowPortBounds(window, &bounds);
- bounds.bottom = gStart.v + 1; // leave room for the controls!
- return bounds;
- }
-
- static void FlushWindowNow(WindowRef window)
- {
- Rect bounds = TreeBounds(window);
- RgnHandle boundsRgn = NewRgn();
- RectRgn(boundsRgn,&bounds);
- QDFlushPortBuffer(GetWindowPort(window), boundsRgn);
- gFlushTicks = TickCount();
- }
-
- static void MayFlushWindow(WindowRef window)
- {
- if (TickCount() != gFlushTicks)
- FlushWindowNow(window);
- }
-
- static void SubTree(WindowRef window, BranchVector* v, UInt32 howDeep)
- {
- DrawVector(v); // node left side
- if (howDeep < 1)
- {
- // Leaf node, just square off the node
- Right90(v);
- DrawVector(v);
- Right90(v);
- }
- else
- {
- // branch node, draw two smaller subbranches
- Left45Smaller(v); // turn left and scale down
- SubTree(window, v, howDeep-1); // draw subtree
-
- // draw triangle connector
- DrawVector(v);
- Right135Bigger(v);
- DrawVector(v);
- Right135Smaller(v);
- DrawVector(v);
-
- SubTree(window, v, howDeep-1); // right branch
- Left45Bigger(v);
- }
- DrawVector(v);
- MayFlushWindow(window);
- }
-
- void UpdateTree(WindowRef window)
- {
- BranchVector initialvector = {0, kInitialSize};
- Rect treeBounds = TreeBounds(window);
- EraseRect(&treeBounds);
- FlushWindowNow(window);
-
- MoveTo(gStart.h, gStart.v); // draw base line
- Line(kInitialSize,0);
- MoveTo(gStart.h, gStart.v);
- SubTree(window, &initialvector, gDepth); // draw a tree
- }
-
- static ControlRef DepthSlider(WindowRef window)
- {
- ControlRef depthSlider;
- ControlID depthControlID = {kTreeAppSignature, kDepthSliderID};
-
- GetControlByID (window, &depthControlID, &depthSlider);
- return depthSlider;
- }
-
- static void PositionTree(WindowRef window)
- {
- Rect bounds;
- GetControlBounds(DepthSlider(window), &bounds);
- gStart.h = bounds.left;
- gStart.v = bounds.top - kControlToTreePadding;
- }
-
- static void TreeResizeCommandHandler (WindowRef window)
- {
- gDepth = GetControlValue (DepthSlider(window));
- UpdateTree(window);
- }
-
- static void UpdateTreeTimer(EventLoopTimerRef inTimer, void *inUserData)
- {
- UpdateTree((WindowRef) inUserData);
- }
-
- static OSStatus SetContinuousDrawMode(WindowRef window, Boolean continuous)
- {
- OSStatus status = noErr;
-
- if (continuous)
- {
- status = InstallEventLoopTimer(GetMainEventLoop(),
- 0.1, // initial delay
- 1.0, // time between fires
- NewEventLoopTimerUPP(UpdateTreeTimer),
- window,
- &gDrawTimer);
- }
- else
- {
- status = RemoveEventLoopTimer(gDrawTimer);
- }
- return status;
- }
-
- static OSStatus DrawContinuousCommandHandler (WindowRef window)
- {
- ControlRef checkbox;
- OSStatus status = noErr;
- ControlID contControlID = {kTreeAppSignature, kContinuousCheckboxID};
-
- GetControlByID (window, &contControlID, &checkbox);
- gContinuousDraw = GetControlValue (checkbox);
- if (gContinuousDraw)
- {
- UpdateTree(window);
- status = SetContinuousDrawMode(window, gContinuousDraw);
- }
- return status;
- }
-
- pascal OSStatus TreeWindowEventHandler(EventHandlerCallRef myHandler, EventRef event, void* userData)
- {
- OSStatus result=eventNotHandledErr;
- HICommand command;
-
- if (GetEventKind(event) == kEventWindowDrawContent)
- {
- UpdateTree(gTreeWindow); // should use GetEventData?
- result = noErr;
- }
- else
- {
- GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL,
- sizeof(command), NULL, &command);
- switch(command.commandID)
- {
- case kTreeOpenAboutWindowCommand:
- TreeAboutWindowCommandHandler(gAboutWindow);
- result = noErr;
- break;
-
- case kDrawCommand:
- UpdateTree(gTreeWindow);
- result = noErr;
- break;
-
- case kTreeResizeCommand:
- TreeResizeCommandHandler(gTreeWindow);
- result = noErr;
- break;
-
- case kDrawContinuousCommand:
- result = DrawContinuousCommandHandler(gTreeWindow);
- break;
-
- default:
- printf("unknown command %ld\n", command.commandID);
- break;
- }
- }
- return result;
- }
-
- int main(int argc, char* argv[])
- {
- IBNibRef nibRef;
- OSStatus err;
-
- // Create a Nib reference passing the name of the nib file (without the .nib extension)
- // CreateNibReference only searches into the application bundle.
- err = CreateNibReference(CFSTR("main"), &nibRef);
- require_noerr( err, CantGetNibRef );
-
- // Once the nib reference is created, set the menu bar. "MainMenu" is the name of the menu bar
- // object. This name is set in InterfaceBuilder when the nib is created.
- err = SetMenuBarFromNib(nibRef, CFSTR("MainMenu"));
- require_noerr( err, CantSetMenuBar );
-
- // Then create a window. "MainWindow" is the name of the window object. This name is set in
- // InterfaceBuilder when the nib is created.
- err = CreateWindowFromNib(nibRef, CFSTR("MainWindow"), &gTreeWindow);
- require_noerr( err, CantCreateWindow );
-
- err = CreateWindowFromNib(nibRef, CFSTR("AboutWindow"), &gAboutWindow);
- require_noerr( err, CantCreateWindow );
-
- // set up the geometry
- PositionTree(gTreeWindow);
-
- // We don't need the nib reference anymore.
- DisposeNibReference(nibRef);
-
- {
- UInt32 numSpecs = sizeof(gTreeEvents)/sizeof(EventTypeSpec);
- InstallWindowEventHandler(gTreeWindow, NewEventHandlerUPP(TreeWindowEventHandler),
- numSpecs, gTreeEvents, (void*) gTreeWindow, NULL);
-
- InstallWindowEventHandler(gAboutWindow, NewEventHandlerUPP(TreeAboutWindowEventHandler),
- 1, &closeSpec, (void*) gAboutWindow, NULL);
- }
-
- // The window was created hidden so show it.
- ShowWindow( gTreeWindow );
-
- // Call the event loop
- RunApplicationEventLoop();
-
- CantCreateWindow:
- CantSetMenuBar:
- CantGetNibRef:
- return err;
- }
-
-