Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
TumblerSource/Tumbler_podium.c
// tumbler_podium.c -- this contains the podium specific routines for the tumbler app |
// |
// |
#ifdef PODIUM_APP |
#include "QD3D.h" |
#include <Drag.h> |
#include <Events.h> |
#include <Controls.h> |
#include <ToolUtils.h> |
#include <Windows.h> |
#include "QD3DView.h" |
#include "QD3DDrawContext.h" |
#include "QD3DDrawContext.h" |
#include "QD3DPick.h" |
#include "QD3DGroup.h" |
#include "QD3DTransform.h" |
#include "QD3DLight.h" |
#include "QD3DMath.h" |
#include <QuickDraw.h> |
#include <QDOffscreen.h> |
#include "tumbler_Document.h" |
#include "tumbler_Camera.h" |
#include "tumbler_podium.h" |
#include "tumbler_offscreen.h" |
#include "tumbler_drag.h" |
static CursHandle objectCursor, zoomInCursor, zoomOutCursor, handCursor; |
static TQ3Object DoHitTest(DocumentPtr theDocument); |
static short PointInRect(Point *point, Rect *rect); |
// Used in Tumber_AEVT.c |
void Podium_UpdateDrawContextFromDropRect( DocumentPtr theDocument ) ; |
//------------------------------------------------------------------------------------ |
void Podium_UpdateDrawContextFromDropRect( DocumentPtr theDocument ) |
{ |
Rect frameRect ; |
frameRect = theDocument->dropArea ; |
// if the drop area for the doc is the same as the GWorld's rect |
// then we don't need to do anything, if they have changes we need |
// to update the drawcontext |
if(!EqualRect(&frameRect,&theDocument->geometriesOffscreen->portRect)) { |
TQ3DrawContextObject theDrawContext ; |
OSErr theErr ; |
if((theErr = UpdateGWorld( &theDocument->geometriesOffscreen, 32, &frameRect, nil, nil, 0L )) == noErr |
// && (theErr = UpdateGWorld( &theDocument->maskOffscreen, 1, &frameRect, nil, nil, 0L )) == noErr |
) { |
theDrawContext = TumblerDocument_NewPixmapDrawContext( theDocument ) ; |
Q3View_SetDrawContext(theDocument->theView, theDrawContext); |
Q3Object_Dispose(theDrawContext); |
AdjustCamera(theDocument, |
theDocument->geometriesOffscreen->portRect.right - theDocument->geometriesOffscreen->portRect.left, |
theDocument->geometriesOffscreen->portRect.bottom - theDocument->geometriesOffscreen->portRect.top); |
} |
} |
} |
static void MouseMoved( |
DocumentPtr theDocument, |
long oldX, |
long oldY, |
long newX, |
long newY) |
{ |
float scaleFactor = 256.0; |
unsigned long winWidth, winHeight; |
TQ3Matrix4x4 tmp; |
TQ3BoundingBox viewBBox; |
TQ3Point3D modelCenter; |
/* |
* Find the bounding box for the group. |
* We'll use the center of the box as the point about which to rotate |
* (the old method always rotated about the world-space origin). |
*/ |
/* |
* Get the width and height of the *current* window. |
* This is done so that mouse motion in a window has an effect |
* relative to the size of the window. |
*/ |
winWidth = theDocument->theWindow->portRect.right - theDocument->theWindow->portRect.left; |
winHeight = theDocument->theWindow->portRect.bottom - theDocument->theWindow->portRect.top; |
GetGroupBBox(theDocument->theView, theDocument->documentGroup, NULL, &viewBBox); |
/* |
* The "to" point is the center of the view bounding box |
*/ |
{ |
float weights[2] = { 0.5, 0.5 }; |
TQ3Point3D points[2]; |
points[0] = viewBBox.min; |
points[1] = viewBBox.max; |
Q3Point3D_AffineComb(points, weights, 2, &modelCenter); |
} |
/* |
* Make a new rotation matrix, rotating about the center of the view |
* bbox. |
*/ |
{ |
float xRot, yRot, zRot; |
xRot = yRot = zRot = 0.0; |
xRot = Q3Math_DegreesToRadians((float)(newY - oldY) / winHeight * scaleFactor); |
yRot = Q3Math_DegreesToRadians((float)(newX - oldX) / winWidth * scaleFactor); |
if ((xRot != 0.0) || (yRot != 0.0)){ |
Q3Matrix4x4_SetRotateAboutPoint(&tmp, &modelCenter, xRot, yRot, zRot); |
Q3Matrix4x4_Multiply(&theDocument->modelRotation, &tmp, &theDocument->modelRotation); |
} |
} |
} |
static short PointInRect(Point *point, Rect *rect) |
{ |
if( point->h > rect->left && point->h < rect->right ) { |
if( point->v > rect->top && point->v < rect->bottom ) { |
return(1); |
} else { |
return(0); |
} |
} else { |
return(0); |
} |
} |
static Boolean PtOnHandles(Point *newMouse, Rect *location, short *whichHandle) |
{ |
Rect handlesRect; |
handlesRect.left = location->left - 4; |
handlesRect.top = location->top - 4; |
handlesRect.right = location->left; |
handlesRect.bottom = location->top; |
if( PointInRect(newMouse, &handlesRect) ) { |
*whichHandle = LeftTopHandle; |
return(true); |
} |
handlesRect.left = location->right; |
handlesRect.right = location->right + 4; |
if( PointInRect(newMouse, &handlesRect) ) { |
*whichHandle = RightTopHandle; |
return(true); |
} |
handlesRect.left = location->right; |
handlesRect.right = location->right + 4; |
handlesRect.top = location->bottom; |
handlesRect.bottom = location->bottom + 4; |
if( PointInRect(newMouse, &handlesRect) ) { |
*whichHandle = RightBottomHandle; |
return(true); |
} |
handlesRect.left = location->left - 4; |
handlesRect.right = location->left; |
if( PointInRect(newMouse, &handlesRect) ) { |
*whichHandle = LeftBottomHandle; |
return(true); |
} |
return(false); |
} |
static void DrawHandles(Rect *location) |
{ |
Rect handlesRect; |
handlesRect.left = location->left - 4; |
handlesRect.top = location->top - 4; |
handlesRect.right = location->left; |
handlesRect.bottom = location->top; |
PaintRect(&handlesRect); |
handlesRect.left = location->right; |
handlesRect.right = location->right + 4; |
PaintRect(&handlesRect); |
handlesRect.left = location->right; |
handlesRect.right = location->right + 4; |
handlesRect.top = location->bottom; |
handlesRect.bottom = location->bottom + 4; |
PaintRect(&handlesRect); |
handlesRect.left = location->left - 4; |
handlesRect.right = location->left; |
PaintRect(&handlesRect); |
PenSize(2,2); |
MoveTo(location->left - 2, location->top - 2); |
LineTo(location->right, location->top - 2); |
LineTo(location->right, location->bottom); |
LineTo(location->left - 2, location->bottom); |
LineTo(location->left - 2, location->top - 2); |
//FrameRect(location); |
} |
/* |
* hit test a click in the document. |
*/ |
static TQ3Object DoHitTest(DocumentPtr theDocument) |
{ |
TQ3WindowPointPickData withData; |
unsigned long numPicked; |
TQ3PickObject pickObject; |
withData.data.sort = kQ3PickSortNone; |
withData.data.numHitsToReturn= 1; |
withData.data.mask = kQ3PickDetailMaskObject; |
withData.point.x = theDocument->mouseLocation.h - theDocument->dropArea.left; |
withData.point.y = theDocument->mouseLocation.v - theDocument->dropArea.top; |
withData.vertexTolerance = withData.edgeTolerance = 3; |
pickObject = Q3WindowPointPick_New(&withData); |
if (pickObject == NULL) { |
return NULL; |
} |
Q3View_StartPicking(theDocument->theView, pickObject ); |
do { |
Q3DisplayGroup_Submit(theDocument->documentGroup, theDocument->theView); |
} while (Q3View_EndPicking(theDocument->theView) == kQ3ViewStatusRetraverse); |
if (Q3Pick_GetNumHits(pickObject, &numPicked) == kQ3Success && (numPicked != 0)) { |
TQ3Object object; |
TQ3PickDetail validMask; |
unsigned long hitIndex = 1; |
object = NULL; |
/* TQ3HitData hitData; |
// used to be: ErPick_GetFirstHit(pickObject, &hitData); |
Q3Pick_GetHitData( pickObject, 1, &hitData ); |
Q3Object_Dispose(pickObject); |
return(hitData.object); |
*/ |
if (Q3Pick_GetPickDetailValidMask(pickObject, hitIndex, &validMask) == kQ3Success) { |
/* Quick check to see if the hit contains an object and shape part */ |
if (validMask & kQ3PickDetailMaskObject) { |
/* Get reference to geometry object hit */ |
Q3Pick_GetPickDetailData( pickObject, |
hitIndex, |
kQ3PickDetailMaskObject, |
&object); |
} |
} |
Q3Object_Dispose(pickObject); |
return(object); |
} else { |
Q3Object_Dispose(pickObject); |
return(NULL); |
} |
} |
/* |
* DoContent handles mouseDown events in the content region of a document window. |
* |
* (1) If the mouseDown is on a control, handle the click by calling TrackControl. |
* |
* (2) If the mouseDown is on a draggable object (the document's hiliteRgn) and a |
* successful drag occurs, no further processing is necessary. |
* |
* (3) If the mouseDown is on a draggable object and the mouse is released without |
* dragging, set the insertion point to the original mouseDown location by calling |
* TEClick with the mouseDown information. |
* |
* (4) If the mouseDown is not on a draggable object and within the viewRect of the |
* TextEdit field, call TEClick to handle the mouseDown. |
*/ |
void Podium_DoContent(DocumentPtr theDocument, EventRecord *theEvent) |
{ |
Point thePoint; |
SetPort(theDocument->theWindow); |
thePoint = theEvent->where; |
if( theDocument->documentGroup ) { |
Point newMouse, offset; |
short whichHandle; |
GetMouse(&newMouse); |
theDocument->mouseLocation = newMouse; |
/* First check for resize */ |
if( theDocument->currentlySelectedObject && PtOnHandles(&newMouse, &theDocument->dropArea, &whichHandle) ) { |
Rect previousRect; |
Rect frameRect; |
Point oldMouse; |
TQ3Boolean needRedraw; |
PenMode(srcXor); |
PenSize(2,2); |
frameRect = previousRect = theDocument->dropArea; |
oldMouse = theDocument->mouseLocation; |
switch( whichHandle ){ |
case LeftTopHandle: |
offset.h = newMouse.h - frameRect.left; |
offset.v = newMouse.v - frameRect.top; |
while (WaitMouseUp()) { |
GetMouse(&newMouse); |
if (newMouse.h >= oldMouse.h + 2 || newMouse.h <= oldMouse.h - 2 || |
newMouse.v >= oldMouse.v + 2 || newMouse.v <= oldMouse.v - 2) { |
needRedraw = kQ3True; |
frameRect.left = newMouse.h - offset.h; |
frameRect.top = newMouse.v - offset.v; |
DrawHandles(&previousRect); |
DrawHandles(&frameRect); |
previousRect = frameRect; |
} |
} |
break; |
case RightTopHandle: |
offset.h = newMouse.h - frameRect.right; |
offset.v = newMouse.v - frameRect.top; |
while (WaitMouseUp()) { |
GetMouse(&newMouse); |
if (newMouse.h >= oldMouse.h + 2 || newMouse.h <= oldMouse.h - 2 || |
newMouse.v >= oldMouse.v + 2 || newMouse.v <= oldMouse.v - 2) { |
needRedraw = kQ3True; |
frameRect.right = newMouse.h - offset.h; |
frameRect.top = newMouse.v - offset.v; |
DrawHandles(&previousRect); |
DrawHandles(&frameRect); |
previousRect = frameRect; |
} |
} |
break; |
case LeftBottomHandle: |
offset.h = newMouse.h - frameRect.left; |
offset.v = newMouse.v - frameRect.bottom; |
while (WaitMouseUp()) { |
GetMouse(&newMouse); |
if (newMouse.h >= oldMouse.h + 2 || newMouse.h <= oldMouse.h - 2 || |
newMouse.v >= oldMouse.v + 2 || newMouse.v <= oldMouse.v - 2) { |
needRedraw = kQ3True; |
frameRect.left = newMouse.h - offset.h; |
frameRect.bottom = newMouse.v - offset.v; |
DrawHandles(&previousRect); |
DrawHandles(&frameRect); |
previousRect = frameRect; |
} |
} |
break; |
case RightBottomHandle: |
offset.h = newMouse.h - frameRect.right; |
offset.v = newMouse.v - frameRect.bottom; |
while (WaitMouseUp()) { |
GetMouse(&newMouse); |
if (newMouse.h >= oldMouse.h + 2 || newMouse.h <= oldMouse.h - 2 || |
newMouse.v >= oldMouse.v + 2 || newMouse.v <= oldMouse.v - 2) { |
needRedraw = kQ3True; |
frameRect.right = newMouse.h - offset.h; |
frameRect.bottom = newMouse.v - offset.v; |
DrawHandles(&previousRect); |
DrawHandles(&frameRect); |
previousRect = frameRect; |
} |
} |
break; |
} |
theDocument->dropArea = frameRect; |
if( needRedraw == kQ3True ) { |
Podium_UpdateDrawContextFromDropRect( theDocument ) ; |
DrawOffscreen(theDocument); |
DrawOnscreen(theDocument); |
} |
PenMode(srcXor); |
PenSize(2,2); |
PenPat(&qd.black); |
DrawHandles(&frameRect); |
/* is it in content */ |
} else if( PtInRect(newMouse, &theDocument->dropArea) ) { |
// TQ3Object newPick; |
// if(( newPick = DoHitTest(theDocument)) != NULL) { |
if( theDocument->selected == kQ3False) { |
PenMode(srcXor); |
PenSize(2,2); |
PenPat(&qd.black); |
DrawHandles(&theDocument->dropArea); |
} |
theDocument->currentlySelectedObject = theDocument->documentGroup ; |
if( theEvent->modifiers & shiftKey ) |
SetCursor(*zoomInCursor); |
else if( theEvent->modifiers & cmdKey ) |
SetCursor(*zoomOutCursor); |
else |
SetCursor(*objectCursor); |
if( theEvent->modifiers & shiftKey ) { |
TQ3Matrix4x4 tmp; |
Q3Matrix4x4_SetScale(&tmp, 1.2, 1.2, 1.2); |
while (WaitMouseUp()) { |
Q3Matrix4x4_Multiply(&tmp, &theDocument->modelRotation, &theDocument->modelRotation); |
DrawOffscreen( theDocument ) ; |
DrawOnscreen( theDocument ) ; |
} |
} else if( theEvent->modifiers & cmdKey ) { |
TQ3Matrix4x4 tmp; |
Q3Matrix4x4_SetScale(&tmp, 0.83333, 0.83333, 0.83333); |
while (WaitMouseUp()) { |
Q3Matrix4x4_Multiply(&tmp, &theDocument->modelRotation, &theDocument->modelRotation); |
DrawOffscreen(theDocument); |
DrawOnscreen( theDocument ) ; |
} |
} else if( theEvent->modifiers & controlKey ) { |
Point newMouse; |
long mouseChanged = 0; |
long dx, dy, oldX, oldY; |
float width, height; |
float xRot, yRot; |
SetCursor(*handCursor); |
GetMouse(&newMouse); // get the mouse in local co-ordinates, |
// local to the current GrafPort |
oldX = newMouse.h; |
oldY = newMouse.v; |
width = theDocument->geometriesOffscreen->portRect.right - theDocument->geometriesOffscreen->portRect.left; |
height = theDocument->geometriesOffscreen->portRect.bottom - theDocument->geometriesOffscreen->portRect.top; |
while (WaitMouseUp()) { |
GetMouse(&newMouse); // get the mouse in local co-ordinates, |
// local to the current GrafPort |
dx = newMouse.v - oldY; |
dy = newMouse.h - oldX; |
if ((dx != 0) || (dy != 0)) { |
TQ3Matrix4x4 tempMatrix; |
xRot = ((float) dx * kQ3Pi) / width; |
yRot = ((float) dy * kQ3Pi) / height; |
if ((xRot != 0.0) || (yRot != 0.0)) { |
Q3Matrix4x4_SetRotate_XYZ(&tempMatrix, xRot, yRot, 0.0); |
Q3Matrix4x4_Multiply(&theDocument->modelRotation, &tempMatrix, &theDocument->modelRotation); |
mouseChanged = 1; |
DrawOffscreen(theDocument); |
DrawOnscreen( theDocument ) ; |
} |
} |
oldX = newMouse.h; oldY = newMouse.v; |
} |
if( mouseChanged ) { |
theDocument->rotationDir.x = xRot; |
theDocument->rotationDir.y = yRot; |
} |
} else { |
Rect previousRect; |
Rect frameRect; |
Point oldMouse; |
TQ3Boolean needRedraw; |
long height, width; |
PenMode(srcXor); |
PenSize(2,2); |
frameRect = previousRect = theDocument->dropArea; |
height = frameRect.bottom - frameRect.top; |
width = frameRect.right - frameRect.left; |
offset.h = newMouse.h - frameRect.left; |
offset.v = newMouse.v - frameRect.top; |
oldMouse = theDocument->mouseLocation; |
while (WaitMouseUp()) { |
GetMouse(&newMouse); |
if (newMouse.h >= oldMouse.h + 2 || newMouse.h <= oldMouse.h - 2 || |
newMouse.v >= oldMouse.v + 2 || newMouse.v <= oldMouse.v - 2) { |
needRedraw = kQ3True; |
frameRect.left = newMouse.h - offset.h; |
frameRect.top = newMouse.v - offset.v; |
frameRect.right = frameRect.left + width; |
frameRect.bottom = frameRect.top + height; |
DrawHandles(&previousRect); |
DrawHandles(&frameRect); |
previousRect = frameRect; |
} |
} |
theDocument->dropArea = frameRect; |
if( needRedraw == kQ3True ) { |
Podium_UpdateDrawContextFromDropRect( theDocument ) ; |
DrawOffscreen(theDocument); |
DrawOnscreen(theDocument); |
} |
PenMode(srcXor); |
PenSize(2,2); |
PenPat(&qd.black); |
DrawHandles(&frameRect); |
} |
} else { |
if( theDocument->selected == kQ3True) { |
theDocument->currentlySelectedObject = NULL; |
theDocument->selected = kQ3False; |
PenMode(srcXor); |
PenSize(2,2); |
PenPat(&qd.black); |
DrawHandles(&theDocument->dropArea); |
} |
SetCursor(&qd.arrow); |
} |
} |
else { |
if( theDocument->currentlySelectedObject ) { |
theDocument->currentlySelectedObject = NULL; |
PenMode(srcXor); |
PenSize(2,2); |
DrawHandles(&theDocument->dropArea); |
SetCursor(&qd.arrow); |
} |
} |
} |
/* |
* DoBackgroundContent handles mouseDown events in the content region of a document window |
* when the window is not frontmost. The following bullet items describe how this background |
* mouseDown event is handled: |
* |
* (1) If the mouseDown is not in a draggable object (not in the document's hiliteRgn) call |
* SelectWindow to bring the window to the front as usual. |
* |
* (2) If the mouseDown is in a draggable object and the mouse is released without |
* dragging, call SelectWindow when the mouse is released. |
* |
* (3) If the mouseDown is in a draggable object and a successful drag occurs, SelectWindow |
* should only be called if the drop occurred in the same window (the DragText function |
* calls SelectWindow in this case). |
*/ |
void Podium_DoBackgroundContent(DocumentPtr theDocument, EventRecord *theEvent) |
{ |
Point thePoint; |
RgnHandle tempRgn = NewRgn(); // Nick this needs to be the BBox of the group |
SetPort(theDocument->theWindow); |
thePoint = theEvent->where; |
GlobalToLocal(&thePoint); |
RectRgn(tempRgn, &theDocument->geometriesOffscreen->portRect); |
if (PtInRgn(thePoint,tempRgn)) { |
if (! DoDragObjects(theDocument, theEvent, tempRgn)) { |
SelectWindow(theDocument->theWindow); |
} |
} |
else { |
SelectWindow(theDocument->theWindow); |
} |
DisposeRgn(tempRgn); |
} |
/* |
* DoIdle get called repetitively while the application is not doing |
* anything. |
*/ |
void Podium_DoIdle(EventRecord *theEvent) |
{ |
WindowPtr theWindow; |
DocumentPtr theDocument; |
if ((theWindow = FrontWindow()) != nil) { |
if ((theDocument = GetDocumentFromWindow(theWindow)) != nil) { |
SetPort(theDocument->theWindow); |
if( theDocument->documentGroup ) { |
Point mouseLocation; |
GetMouse(&mouseLocation); |
theDocument->mouseLocation = mouseLocation; |
if( PointInRect(&theDocument->mouseLocation, &theDocument->dropArea) ) { |
if(/*DoHitTest(theDocument)*/1) { |
if( theEvent->modifiers & shiftKey) { |
SetCursor(*zoomInCursor); |
} else if( theEvent->modifiers & cmdKey) { |
SetCursor(*zoomOutCursor); |
} else if( theEvent->modifiers & controlKey) { |
SetCursor(*handCursor); |
} else { |
SetCursor(*objectCursor); |
} |
} else { |
SetCursor(&qd.arrow); |
} |
} else { |
SetCursor(&qd.arrow); |
} |
if( theDocument->animateModel == kQ3True) { |
TQ3Matrix4x4 tmp; |
if( theDocument->rotationDir.x == 0.0 && theDocument->rotationDir.y == 0.0 ) { |
Q3Matrix4x4_SetRotate_XYZ(&tmp, 0.03, 0.08, 0.0); |
Q3Matrix4x4_Multiply(&theDocument->modelRotation, &tmp, &theDocument->modelRotation); |
} else { |
Q3Matrix4x4_SetRotate_XYZ(&tmp, theDocument->rotationDir.x, theDocument->rotationDir.y, 0.0); |
Q3Matrix4x4_Multiply(&theDocument->modelRotation, &tmp, &theDocument->modelRotation); |
} |
DrawOffscreen(theDocument); |
DrawOnscreen(theDocument); |
} |
} |
} |
} |
} |
void Podium_Init(void) |
{ |
objectCursor = GetCursor(132); |
zoomInCursor = GetCursor(133); |
zoomOutCursor = GetCursor(134); |
handCursor = GetCursor(130); |
} |
#endif /* PODIUM_APP */ |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14