void doRotatedEllipses(CGContextRef context) { int i, totreps = 144; float tint = 1.0, tintIncrement = 1.0/totreps; // Create a new transform consisting of a 45 degrees rotation. CGAffineTransform theTransform = CGAffineTransformMakeRotation(M_PI/4); // Apply a scale to the transform just created. theTransform = CGAffineTransformScale(theTransform, 1, 2); // Place the first ellipse at a good location. CGContextTranslateCTM(context, 100., 100.); for(i=0 ; i < totreps ; i++){ // Make a snapshot the coordinate system. CGContextSaveGState(context); // Set up the coordinate system for the rotated ellipse. CGContextConcatCTM(context, theTransform); CGContextBeginPath(context); CGContextAddArc(context, 0., 0., 45., 0., 2*M_PI, 0); // Set the fill color for this instance of the ellipse. CGContextSetRGBFillColor(context, tint, 0., 0., 1.0); CGContextDrawPath(context, kCGPathFill); // Restore the coordinate system to that of the snapshot. CGContextRestoreGState(context); // Compute the next tint color. tint -= tintIncrement; // Move over by 1 unit in x for the next ellipse. CGContextTranslateCTM(context, 1.0, 0.0); } }
CGPoint CGPointRotateAround(CGPoint point, CGPoint pivot, CGFloat angle) { CGPoint result = CGPointApplyAffineTransform(CGPointSubtract(point, pivot), CGAffineTransformMakeRotation(angle)); result = CGPointAdd(result, pivot); return result; }
CGPoint CGPointRotatedAroundPoint(CGPoint point, CGPoint pivot, CGFloat degrees) { CGAffineTransform translation, rotation; translation = CGAffineTransformMakeTranslation(-pivot.x, -pivot.y); point = CGPointApplyAffineTransform(point, translation); rotation = CGAffineTransformMakeRotation(degrees * M_PI/180.0); point = CGPointApplyAffineTransform(point, rotation); translation = CGAffineTransformMakeTranslation(pivot.x, pivot.y); point = CGPointApplyAffineTransform(point, translation); return point; }
void doRotatedEllipsesWithCGPath(CGContextRef context) { int i, totreps = 144.; CGMutablePathRef path = NULL; float tint = 1., tintIncrement = 1./totreps; // Create a new transform consisting of a 45 degree rotation. CGAffineTransform theTransform = CGAffineTransformMakeRotation(M_PI/4); // Apply a scaling transformation to the transform just created. theTransform = CGAffineTransformScale(theTransform, 1, 2); // Create a mutable CGPath object. path = CGPathCreateMutable(); if(!path){ fprintf(stderr, "Couldn't create path!\n"); return; } // Add a circular arc to the CGPath object, transformed // by an affine transform. CGPathAddArc(path, &theTransform, 0., 0., 45., 0., 2*M_PI, false); // Close the CGPath object. CGPathCloseSubpath(path); // Place the first ellipse at a good location. CGContextTranslateCTM(context, 100., 100.); for (i = 0 ; i < totreps ; i++){ CGContextBeginPath(context); // Add the CGPath object to the current path in the context. CGContextAddPath(context, path); // Set the fill color for this instance of the ellipse. CGContextSetRGBFillColor(context, tint, 0., 0., 1.); // Filling the path implicitly closes it. CGContextFillPath(context); // Compute the next tint color. tint -= tintIncrement; // Move over for the next ellipse. CGContextTranslateCTM(context, 1, 0.); } // Release the path when done with it. CGPathRelease(path); }
CGAffineTransform CGAffineTransformRotate(CGAffineTransform T,CGFloat angle) { return CGAffineTransformConcat(T,CGAffineTransformMakeRotation(angle)); }
/* Event handler for the content view that gets attached to the menu frame. The content view will (eventually) contain the menu view. */ OSStatus ContentViewEventHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void *refcon) { OSStatus retVal = eventNotHandledErr; if(GetEventClass(inEvent) == kEventClassMenu) { return noErr; } else if(GetEventClass(inEvent) == kEventClassControl) { HIViewRef hiSelf = NULL; verify_noerr(GetEventParameter(inEvent, kEventParamDirectObject, typeControlRef, NULL, sizeof(hiSelf), NULL, &hiSelf)); if(hiSelf) { HIRect frame; HIViewGetFrame(hiSelf, &frame); switch(GetEventKind(inEvent)) { case kEventControlAddedSubControl : { HIViewRef subControl; ControlID subControlID; GetEventParameter(inEvent, kEventParamControlSubControl, typeControlRef, NULL, sizeof(subControl), NULL, &subControl ); GetControlID(subControl, &subControlID); // This should be comparing against kHIViewMenuContentID as shown inside the // #if 0. At the time of this writing, however, using that constant causes a // linker error (and a crash if you use ZeroLink). I extracted the signature // and id by determining the value at run-time the value I compare against. #if 0 if( kHIViewMenuContentID.signature == subControlID.signature && kHIViewMenuContentID.id == subControlID.id ) { #else if( 'menu' == subControlID.signature && 0 == subControlID.id ) { #endif // If we have the menu content view then set up some view bindings for it. HIRect bounds; HIViewGetBounds(hiSelf, &bounds); HIViewSetFrame(subControl, &bounds); HILayoutInfo contentLayout = { kHILayoutInfoVersionZero, { { NULL, kHILayoutBindTop }, { NULL, kHILayoutBindLeft }, { NULL, kHILayoutBindBottom }, { NULL, kHILayoutBindRight } }, { { NULL, kHILayoutScaleAbsolute, 0 }, { NULL, kHILayoutScaleAbsolute, 0 } }, { { NULL, kHILayoutPositionTop, 0 }, { NULL, kHILayoutPositionLeft, 0 } } }; verify_noerr(HIViewSetLayoutInfo(subControl, &contentLayout)); } retVal = noErr; } break; case kEventControlGetFrameMetrics : HIViewFrameMetrics metrics; // The offset from the frame view to the content view is // given by the kFrameOffset constant metrics.top = kFrameOffset; metrics.left = kFrameOffset; metrics.right = kFrameOffset; metrics.bottom = kFrameOffset; verify_noerr(SetEventParameter(inEvent, kEventParamControlFrameMetrics, typeControlFrameMetrics, sizeof(metrics), &metrics)); retVal = noErr; break; case kEventControlBoundsChanged : case kEventControlOwningWindowChanged : { // Maintain the QuickDraw port by changing its position to // match that of the content view. CGrafPtr windowPort = NULL; WindowRef window = GetControlOwner(hiSelf); if(window && (windowPort = GetWindowPort(window))) { CGrafPtr savePort; bool swapped = QDSwapPort(windowPort, &savePort); MovePortTo((short) frame.origin.x, (short) frame.origin.y); PortSize((short) frame.size.width, (short) frame.size.height); if(swapped) { QDSwapPort(savePort, NULL); } } retVal = noErr; } break; } // switch } // if (hiSelf) } return retVal; } /* ------------------------------------------ CreatePathForEntireStarMenu */ /* Create a path shape for the star frame. This looks an awful lot like CreatePathForEntireStarMenu in StarMenu.cpp but takes the radius to use as a parameter and then takes into account the kFrameOffest when creating the path. In true Core Foundation style, this is a CreateXXX routine and the caller is responsible for freeing the path that is returned. */ CGPathRef CreatePathForStarFrame(StarFrameData *menuData, float radius) { CGMutablePathRef retVal = CGPathCreateMutable(); MenuItemIndex numItems = CountMenuItems(menuData->menu); if(numItems > 0) { const CGPoint fullRadiusPoint = { radius, 0 }; const CGPoint halfRadiusPoint = { ((radius - kFrameOffset) / 2.0) + kFrameOffset , 0 }; float anglePerItem = 2 * pi / (float)numItems; // in radians naturally float halfAngle = anglePerItem / 2.0; CGPoint startPoint = halfRadiusPoint; CGAffineTransform midRotate = CGAffineTransformMakeRotation(halfAngle); CGPoint midPoint = CGPointApplyAffineTransform(fullRadiusPoint, midRotate); CGAffineTransform rotateToNext = CGAffineTransformMakeRotation(anglePerItem); CGPathMoveToPoint(retVal, NULL, startPoint.x, startPoint.y); CGPathAddLineToPoint(retVal, NULL, midPoint.x, midPoint.y); for(short ctr = 0; ctr < numItems; ctr++) { startPoint = CGPointApplyAffineTransform(startPoint, rotateToNext); midPoint = CGPointApplyAffineTransform(midPoint, rotateToNext); CGPathAddLineToPoint(retVal, NULL, startPoint.x, startPoint.y); CGPathAddLineToPoint(retVal, NULL, midPoint.x, midPoint.y); } CGPathCloseSubpath(retVal); } return retVal; }