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_event.c
// Tumbler)event.c |
// |
// Event handling routines. |
// |
// Author: Nick Thompson & Pablo Fernicola, with thanks to the QuickDraw 3D team |
// Date: Monday, Janurary 20, 1992 |
// |
// Copyright © 1992-95 Apple Computer, Inc., All Rights Reserved |
// |
// Modification History: |
// 12/2/94 nick |
// |
// Debugging Aids : |
// |
// Turn this flag on to see where the current hilite region is. |
// |
// #define _FLASH_HILITE_RGN_ |
// |
// |
#include <Drag.h> |
#include "QD3D.h" |
#include "Tumbler_globals.h" |
#include "Tumbler_prototypes.h" |
#include "Tumbler_resources.h" |
#include "AppleEvents.h" |
#include "Events.h" |
#include "QD3DView.h" |
#include "QD3DDrawContext.h" |
#include "QD3DDrawContext.h" |
#include "QD3DPick.h" |
#include "QD3DTransform.h" |
#include "QD3DLight.h" |
#include "QD3DMath.h" |
#include "QD3DGeometry.h" |
#define SleepDuration 20 /* WaitNextEvent sleep constant */ |
#include "Tumbler_event.h" |
#include "Tumbler_camera.h" |
#include "Tumbler_drag.h" |
#include "Tumbler_offscreen.h" |
#include "Tumbler_windows.h" |
#include "Tumbler_menus.h" |
#include "Tumbler_drag.h" |
#include "Tumbler_document.h" |
#include "Tumbler_cursor.h" |
#ifdef PODIUM_APP |
#include "Tumbler_Podium.h" |
#endif |
static void DoContentClick(WindowPtr theWindow, EventRecord *theEvent); |
static void DoBackgroundContentClick(WindowPtr theWindow, EventRecord *theEvent) ; |
static void DoMouseDown(EventRecord *theEvent); |
static void DoKey(char theChar); |
static void DoKeyDown(EventRecord *theEvent); |
static void DoActivate(EventRecord *theEvent); |
static void DoUpdate(EventRecord *theEvent); |
static void DoOSEvent(EventRecord *theEvent); |
static void DoHighLevelEvent(EventRecord *theEvent); |
static void DoEvent(EventRecord *theEvent); |
static void DoIdleHitTest(void); |
static void DoIdle(void); |
//------------------------------------------------------------------------------------- |
// DoContentClick handles mouseDown events in the content region of a document window. |
// |
// (1) If the mouseDown is on a draggable object (the document's hiliteRgn) and a |
// successful drag occurs, no further processing is necessary. |
// |
// (2) If the mouseDown is not on a draggable object and within the viewRect of the |
// TextEdit field, call TEClick to handle the mouseDown. |
static void DoContentClick( WindowPtr theWindow, EventRecord *theEvent) |
{ short thePart; |
Point thePoint; |
ControlHandle theControl; |
DocumentPtr theDocument = GetDocumentFromWindow(theWindow); |
GrafPtr savedPort ; |
if( theWindow == nil ) |
return ; |
GetPort( &savedPort) ; |
SetPort( theWindow ) ; |
thePoint = theEvent->where; |
GlobalToLocal(&thePoint); |
if( theDocument->documentGroup ) { |
// we can only do a drag if the option key is held down |
if (theEvent->modifiers & optionKey) { |
RgnHandle tempRgn = NewRgn(); // Nick this needs to be the BBox of the group |
RectRgn(tempRgn, &theWindow->portRect); |
DoDragObjects(theDocument, theEvent, tempRgn ) ; |
DisposeRgn(tempRgn); |
} else { |
Point oldMouse; |
Point newMouse; |
long mouseChanged = 0; |
long dx, dy, x, y, oldX, oldY; |
float width, height; |
float xRot, yRot; |
GetMouse(&newMouse); // get the mouse in local co-ordinates, |
// local to the current GrafPort |
oldX = newMouse.h; |
oldY = newMouse.v; |
width = theWindow->portRect.left - theWindow->portRect.right; |
height = theWindow->portRect.bottom - theWindow->portRect.top; |
while (WaitMouseUp()) { |
GetMouse(&newMouse); // get the mouse in local co-ordinates, |
// local to the current GrafPort |
dx = oldY - newMouse.v; |
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); |
} |
} |
oldX = newMouse.h; oldY = newMouse.v; |
} |
if( mouseChanged ) { |
theDocument->rotationDir.x = xRot; |
theDocument->rotationDir.y = yRot; |
DrawOffscreen(theDocument); |
DoDrawGrowIcon(theDocument->theWindow); |
} |
} |
} |
SetPort( savedPort ) ; |
} |
// |
// DoBackgroundContentClick 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 DoDragObjects function |
// calls SelectWindow in this case). |
// |
static void DoBackgroundContentClick(WindowPtr theWindow, EventRecord *theEvent) |
{ |
short thePart; |
Point thePoint; |
ControlHandle theControl; |
DocumentPtr theDocument ; |
RgnHandle tempRgn = NewRgn(); // Nick will fix later, needs to be the bbox of the group |
if( theWindow == nil ) |
return ; |
SetPort( theWindow ); |
theDocument = GetDocumentFromWindow(theWindow); |
thePoint = theEvent->where; |
GlobalToLocal(&thePoint); |
RectRgn(tempRgn, &theWindow->portRect); |
if (PtInRgn(thePoint, tempRgn)) { |
if (! DoDragObjects(theDocument, theEvent, tempRgn)) { |
SelectWindow(theDocument->theWindow); |
} |
} else { |
SelectWindow(theDocument->theWindow); |
} |
DisposeRgn( tempRgn ); |
} |
// |
// DoMouseDown is called to handle mouseDown events. |
// |
static void DoMouseDown(EventRecord *theEvent) |
{ short thePart; |
WindowPtr theWindow; |
Rect dragRect; |
DocumentPtr theDocument; |
thePart = FindWindow(theEvent->where, &theWindow); |
switch(thePart) { |
case inMenuBar: |
PrepareMenus(); |
DoMenuCommand(MenuSelect(theEvent->where)); |
break; |
case inSysWindow: |
SystemClick(theEvent, theWindow); |
break; |
case inContent: |
if (theWindow == FrontWindow()) { |
#ifndef PODIUM_APP |
DoContentClick(theWindow, theEvent); |
#else |
Podium_DoContent( GetDocumentFromWindow(theWindow), theEvent ) ; |
#endif |
} else { |
#ifndef PODIUM_APP |
DoBackgroundContentClick(theWindow, theEvent); |
#else |
Podium_DoBackgroundContent( GetDocumentFromWindow(theWindow), theEvent ) ; |
#endif |
} |
break; |
case inDrag: |
if (theWindow != FrontWindow()) |
SelectWindow(theWindow); |
dragRect = qd.screenBits.bounds; |
DragWindow(theWindow, theEvent->where, &dragRect); |
break; |
case inGrow: |
if ((theDocument = GetDocumentFromWindow(theWindow)) != nil) { |
GrowDocumentWindow(theWindow, theEvent->where); |
} |
break; |
case inGoAway: |
if ((theDocument = GetDocumentFromWindow(theWindow)) != nil) |
if (TrackGoAway(theWindow, theEvent->where)) { |
(void)CloseDocument(theDocument); // it's not important what the result is here |
} |
break; |
} |
} |
// |
// DoKey is called each time a character is typed on the keyboard to |
// be entered into a document window. |
// |
static void DoKey(char theChar) |
{ WindowPtr theWindow; |
DocumentPtr theDocument; |
if ((theWindow = FrontWindow()) != nil) { |
if ((theDocument = GetDocumentFromWindow(theWindow)) != nil) { |
// what d'ya want to do here? |
} |
} |
} |
// |
// DoKeyDown is called to handle keyDown or autoKey events. |
// |
static void DoKeyDown(EventRecord *theEvent) |
{ char theChar; |
theChar = theEvent->message & charCodeMask; |
if (theEvent->modifiers & cmdKey) { |
PrepareMenus(); |
DoMenuCommand(MenuKey(theChar)); |
} |
} |
// |
// DoActivate is called in response to activate/deactivate events. |
// |
static void DoActivate(EventRecord *theEvent) |
{ WindowPtr theWindow; |
DocumentPtr theDocument; |
if ((theWindow = (WindowPtr) theEvent->message) != nil) { |
if ((theDocument = GetDocumentFromWindow(theWindow)) != nil) { |
DoActivateDocument(theDocument, (theEvent->modifiers & activeFlag)); |
} |
} |
} |
// |
// DoUpdate is called in response to update events. |
// |
static void DoUpdate(EventRecord *theEvent) |
{ DocumentPtr theDocument; |
if ( ((WindowPtr) theEvent->message) != nil) |
UpdateWindow((WindowPtr) theEvent->message); |
} |
// |
// DoOSEvent is called in response to Operating System events. |
// |
static void DoOSEvent(EventRecord *theEvent) |
{ DocumentPtr theDocument; |
switch ((theEvent->message >> 24) & 0x0FF) { |
case suspendResumeMessage: |
gInBackground = (theEvent->message & resumeFlag) == 0; |
if ((theDocument = GetDocumentFromWindow(FrontWindow())) != nil) |
DoActivateDocument(theDocument, !gInBackground); |
break; |
} |
} |
static void DoHighLevelEvent(EventRecord *theEvent) |
{ |
AEProcessAppleEvent(theEvent); |
} |
// |
// Each time WaitNextEvent returns an event to this application, DoEvent |
// is called to handle the event. |
// |
static void DoEvent(EventRecord *theEvent) |
{ WindowPtr theWindow; |
DocumentPtr theDocument; |
if ((theWindow = FrontWindow()) != nil) { |
if ((theDocument = GetDocumentFromWindow(theWindow)) != nil) { |
gFrontDocument = theDocument; |
} |
} |
switch(theEvent->what) { |
case mouseDown: |
DoMouseDown(theEvent); |
break; |
case mouseUp: |
break; |
case keyDown: |
case autoKey: |
DoKeyDown(theEvent); |
break; |
case activateEvt: |
DoActivate(theEvent); |
break; |
case updateEvt: |
DoUpdate(theEvent); |
break; |
case osEvt: |
DoOSEvent(theEvent); |
break; |
case kHighLevelEvent: |
DoHighLevelEvent(theEvent); |
break; |
} |
} |
// |
// DoIdle get called repetitively while the application is not doing |
// anything. |
// |
static void DoIdleHitTest(void) |
{ |
WindowPtr theWindow; |
DocumentPtr theDocument; |
if ((theWindow = FrontWindow()) != nil) { |
if ((theDocument = GetDocumentFromWindow(theWindow)) != nil) { |
SetPort(theDocument->theWindow); |
if( theDocument->documentGroup ) { |
Point screenPoint; |
TQ3WindowPointPickData withData; |
unsigned long numPicked; |
TQ3PickObject pickObject; |
withData.data.sort = kQ3PickSortNone; |
withData.data.numHitsToReturn= 1; |
withData.data.mask = kQ3PickDetailMaskObject; |
GetMouse( &screenPoint ); |
withData.point.x = screenPoint.h; |
withData.point.y = screenPoint.v; |
withData.vertexTolerance = withData.edgeTolerance = 3; |
// gone and sadly missed in b1c1, delete this line at b2c1!! |
// withData.view = theDocument->theView; |
pickObject = Q3WindowPointPick_New(&withData); |
Q3View_StartPicking(theDocument->theView, pickObject); |
do { |
Q3DisplayGroup_Submit(theDocument->documentGroup, theDocument->theView); |
} while (Q3View_EndPicking(theDocument->theView) == kQ3ViewStatusRetraverse); |
if (Q3Pick_GetNumHits(pickObject, &numPicked) && (numPicked != 0)) { |
SetCursor(*GetCursor(plusCursor)); |
} else { |
SetCursor(&qd.arrow); |
} |
Q3Object_Dispose(pickObject); |
} |
#ifdef _FLASH_HILITE_RGN_ |
{ long dTime; |
InvertRgn(theDocument->hiliteRgn); |
Delay(10, &dTime); |
InvertRgn(theDocument->hiliteRgn); |
} |
#endif |
} |
} |
} |
// |
// DoIdle get called repetitively while the application is not doing |
// anything. |
// |
static void DoIdle(void) |
{ |
WindowPtr theWindow; |
DocumentPtr theDocument; |
if ((theWindow = FrontWindow()) != nil) { |
if ((theDocument = GetDocumentFromWindow(theWindow)) != nil) { |
Boolean update = false; |
SetPort(theDocument->theWindow); |
if( theDocument->documentGroup && theDocument->animateLights && theDocument->light) { |
#if defined(ESCHER_VER_15) && ESCHER_VER_15 |
float angle; |
TQ3GroupPosition lightPosition, position; |
TQ3LightObject theLight; |
TQ3GroupObject lightGroup; |
TQ3Matrix4x4 matrix; |
TQ3Point3D location; |
TQ3Object ellipsoid; |
TQ3Point3D origin; |
theDocument->light = kQ3True; |
Q3View_GetLightGroup(theDocument->theView, &lightGroup); |
Q3Group_GetFirstPosition(lightGroup, &lightPosition); |
/* First one is always on, skip */ |
Q3Group_GetNextPosition(lightGroup, &lightPosition); |
/* Adjust the transform for the Red sphere */ |
Q3RotateTransform_GetAngle(theDocument->lightXform1, &angle); |
angle += 0.8; |
Q3RotateTransform_SetAngle(theDocument->lightXform1, angle); |
Q3Transform_GetMatrix(theDocument->lightXform1, &matrix); |
/* Get the Red light */ |
Q3Group_GetPositionObject(lightGroup, lightPosition, &theLight); |
/* Get the Red sphere */ |
Q3Group_GetFirstPositionOfType(theDocument->light1, |
kQ3ShapeTypeGeometry, &position); |
Q3Group_GetPositionObject(theDocument->light1, position, &ellipsoid); |
Q3Ellipsoid_GetOrigin( ellipsoid, &origin); |
Q3Point3D_Transform(&origin, &matrix, &location); |
Q3PointLight_SetLocation(theLight, &location); |
Q3Object_Dispose(theLight); |
Q3Object_Dispose(ellipsoid); |
/* Adjust the transform for the Green sphere */ |
Q3Group_GetNextPosition(lightGroup, &lightPosition); |
Q3RotateTransform_GetAngle(theDocument->lightXform2, &angle); |
angle += 0.5; |
Q3RotateTransform_SetAngle(theDocument->lightXform2, angle); |
Q3Transform_GetMatrix(theDocument->lightXform2, &matrix); |
/* Get the Green light */ |
Q3Group_GetPositionObject(lightGroup, lightPosition, &theLight); |
/* Get the Green sphere */ |
Q3Group_GetFirstPositionOfType(theDocument->light2, |
kQ3ShapeTypeGeometry, &position); |
Q3Group_GetPositionObject(theDocument->light2, position, &ellipsoid); |
Q3Ellipsoid_GetOrigin( ellipsoid, &origin); |
Q3Point3D_Transform(&origin, &matrix, &location); |
Q3PointLight_SetLocation(theLight, &location); |
Q3Object_Dispose(theLight); |
Q3Object_Dispose(ellipsoid); |
/* Adjust the transform for the Blue sphere */ |
Q3Group_GetNextPosition(lightGroup, &lightPosition); |
Q3RotateTransform_GetAngle(theDocument->lightXform3, &angle); |
angle += 0.3; |
Q3RotateTransform_SetAngle(theDocument->lightXform3, angle); |
Q3Transform_GetMatrix(theDocument->lightXform3, &matrix); |
/* Get the Blue light */ |
Q3Group_GetPositionObject(lightGroup, lightPosition, &theLight); |
/* Get the Blue sphere */ |
Q3Group_GetFirstPositionOfType(theDocument->light3, |
kQ3ShapeTypeGeometry, &position); |
Q3Group_GetPositionObject(theDocument->light3, position, &ellipsoid); |
Q3Ellipsoid_GetOrigin( ellipsoid, &origin); |
Q3Point3D_Transform(&origin, &matrix, &location); |
Q3PointLight_SetLocation(theLight, &location); |
Q3Object_Dispose(theLight); |
Q3Object_Dispose(ellipsoid); |
Q3Object_Dispose(lightGroup); |
update = true; |
#endif |
} |
if( theDocument->documentGroup && theDocument->animateModel) { |
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); |
} |
update = true; |
} |
if( update ) { |
DrawOffscreen(theDocument); |
DrawOnscreen(theDocument); |
DoDrawGrowIcon(theDocument->theWindow); |
} |
} |
} |
} |
// |
// This is the main event loop of the program. It calls WaitNextEvent |
// and dispatches the returned event until gQuit is true. |
// |
void EventLoop(void) |
{ short gotEvent; |
EventRecord theEvent; |
RgnHandle theMouseRgn; |
Point theLoc; |
theMouseRgn = NewRgn(); |
do { |
gotEvent = WaitNextEvent(everyEvent, &theEvent, 0L, theMouseRgn); |
if (gotEvent) { |
DoEvent(&theEvent); |
} else { |
#ifndef PODIUM_APP |
DoIdle(); |
#else |
Podium_DoIdle(&theEvent) ; |
#endif |
} |
} while (! gQuit); |
DisposeRgn(theMouseRgn); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14