Source/Q3UL.c

/*
 *
 * Utility library for QuickDraw 3D.
 *
 * Nick Thompson, nickt@apple.com
 * Send bug reports and feedback to devsupport@apple.com.
 *
 * ©1997 Apple Computer Inc, All Rights Reserved 
 *
 * Modification History:
 *
 */
 
#include <assert.h>
#include <DiskInit.h>
#include <Fonts.h>
#include <QuickDraw.h>
#include <Windows.h>
 
#include "QD3D.h"
#include "Q3UL.h"
#include "Q3ULPriv.h"
#include "Q3UL_QD3DUtils.h"
 
/* currently we have our window list stored in an array, this
 * could be extended to use a variable length array (we add items
 * to the array as needed, or as a linked list.  For now we just
 * want to keep it as simple as possible.
 */
 
TQ3UL_WindowDescriptor      gWindowArray[ MAXNUMWINDOWS ] ;
Boolean                     gQuitFlag = false ;
 
/*------------------------------------------------------------------------------
 * zero out the referenced element of the windows array.
 */
 
static void iZeroWinElement( TQ3UL_WindowRef windowID )
{
#if defined( DEBUGGING ) && DEBUGGING
    assert( windowID >= 0 && windowID < MAXNUMWINDOWS ) ;
#endif 
    gWindowArray[windowID].window   = NULL ;
    gWindowArray[windowID].refType  = 0L ;
    gWindowArray[windowID].refCon   = 0L ;
    
    gWindowArray[windowID].theCloseHandler      = NULL ;
    gWindowArray[windowID].theKeyHandler        = NULL ;
    gWindowArray[windowID].theMouseDownHandler  = NULL ;
    gWindowArray[windowID].theMouseUpHandler    = NULL ;
    gWindowArray[windowID].theMouseDragHandler  = NULL ;
    gWindowArray[windowID].theRedrawHandler     = NULL ;
    gWindowArray[windowID].theIdleHandler       = NULL ;
    
    gWindowArray[windowID].theView = NULL ;
}
 
/*------------------------------------------------------------------------------
 * get the index of the specified window, -1 if it can't be found.
 */
 
static long iWindowPtrToIdx( WindowPtr theWindow )
{
    long    idx ;
    for(idx = 0; idx<MAXNUMWINDOWS; idx++ )
        if(gWindowArray[idx].window == theWindow)
            break ;
            
    if(idx < 0 || idx >= MAXNUMWINDOWS)
        idx = -1 ;
 
    return idx ;    
}
 
/*------------------------------------------------------------------------------
 * get the high 16 bits of a long.
 */
 
short HiWrd(long aLong)
{
    return  (((aLong) >> 16) & 0xFFFF) ;
}
 
/*------------------------------------------------------------------------------
 * get the low 16 bits of a long.
 */
 
short LoWrd(long aLong)
{
    return  ((aLong) & 0xFFFF) ;
}
 
/*------------------------------------------------------------------------------
 * Initialize the utility library.  Calls Q3Initialize.  Initialize any other
 * data structures used by the library.
 */
 
TQ3Status Q3UL_Initialize( void )
{
    TQ3Status       theStatus ;
    long            i ;
    
    /* first step is to initialize the window array
     * to known values
     */
     
    for( i = 0; i<MAXNUMWINDOWS; i++)
        iZeroWinElement( i ) ;
    
    /*
     * next step is to initialize the toolbox managers
     */
    
    MaxApplZone() ;
    MoreMasters() ; MoreMasters() ; MoreMasters() ; 
    
    InitGraf( &qd.thePort );
    InitFonts();
    InitWindows();
    InitCursor();
 
    FlushEvents( everyEvent, 0 ) ;
    
    /*
     * finally initialize QuickDraw 3D
     */
    
    theStatus = Q3Initialize() ;
    
    return theStatus ;
} 
 
 
/*------------------------------------------------------------------------------
 * Call Q3Exit(), clean up and dispose of anything the library allocated
 */
TQ3Status Q3UL_Terminate( void )
{
    TQ3Status       theStatus ;
    
    /* signal the main event loop that we are done */
    gQuitFlag = true ;
    
    /* close the connection to the QD3D library */
    theStatus = Q3Exit() ;
    
    return theStatus ;
} 
 
/*------------------------------------------------------------------------------
 * 
 */
void    Q3UL_SetPrivType( 
    TQ3UL_WindowRef windowID, 
    unsigned long refType)
{
#if defined( DEBUGGING ) && DEBUGGING
    assert( windowID >= 0 && windowID < MAXNUMWINDOWS ) ;
#endif
    gWindowArray[windowID].refType = refType ;
}
 
/*------------------------------------------------------------------------------
 * 
 */
unsigned long Q3UL_GetPrivType( 
    TQ3UL_WindowRef windowID )
{
#if defined( DEBUGGING ) && DEBUGGING
    assert( windowID >= 0 && windowID < MAXNUMWINDOWS ) ;
#endif
    return gWindowArray[windowID].refType ;
}
 
/*------------------------------------------------------------------------------
 * 
 */
void    Q3UL_SetPrivData( 
    TQ3UL_WindowRef windowID, 
    void *priv)
{
#if defined( DEBUGGING ) && DEBUGGING
    assert( windowID >= 0 && windowID < MAXNUMWINDOWS ) ;
#endif
    if( priv != NULL )
        gWindowArray[windowID].refCon = (unsigned long)priv ;
}
 
/*------------------------------------------------------------------------------
 * 
 */
void    *Q3UL_GetPrivData( 
    TQ3UL_WindowRef windowID )
{
#if defined( DEBUGGING ) && DEBUGGING
    assert( windowID >= 0 && windowID < MAXNUMWINDOWS ) ;
#endif
    return (void *)gWindowArray[windowID].refCon ;
}
 
 
/*------------------------------------------------------------------------------
 * 
 */
 
void    Q3UL_RegisterCloseWindowHandler( 
    TQ3UL_WindowRef             windowID, 
    TQ3UL_CloseWindowHandler    theCloseHandler )
{
#if defined( DEBUGGING ) && DEBUGGING
    assert( windowID >= 0 && windowID < MAXNUMWINDOWS ) ;
#endif
    gWindowArray[windowID].theCloseHandler = theCloseHandler ;
 
}
 
/*------------------------------------------------------------------------------
 * 
 */
 
void    Q3UL_RegisterKeyHandler( 
    TQ3UL_WindowRef     windowID, 
    TQ3UL_KeyHandler    theKeyHandler )
{
#if defined( DEBUGGING ) && DEBUGGING
    assert( windowID >= 0 && windowID < MAXNUMWINDOWS ) ;
#endif
    gWindowArray[windowID].theKeyHandler = theKeyHandler ;
}
 
 
 
/*------------------------------------------------------------------------------
 * 
 */
 
void Q3UL_RegisterMouseDownHandler( 
    TQ3UL_WindowRef         windowID, 
    TQ3UL_MouseDownHandler  theMouseDownHandler )
{
#if defined( DEBUGGING ) && DEBUGGING
    assert( windowID >= 0 && windowID < MAXNUMWINDOWS ) ;
#endif
    gWindowArray[windowID].theMouseDownHandler = theMouseDownHandler ;
}
 
 
 
/*------------------------------------------------------------------------------
 * 
 */
 
void Q3UL_RegisterMouseUpHandler( 
    TQ3UL_WindowRef         windowID, 
    TQ3UL_MouseUpHandler    theMouseUpHandler )
{
#if defined( DEBUGGING ) && DEBUGGING
    assert( windowID >= 0 && windowID < MAXNUMWINDOWS ) ;
#endif
    gWindowArray[windowID].theMouseUpHandler = theMouseUpHandler ;
 
}
 
 
 
/*------------------------------------------------------------------------------
 * 
 */
 
void Q3UL_RegisterMouseDragHandler( 
    TQ3UL_WindowRef         windowID, 
    TQ3UL_MouseDragHandler  theMouseDragHandler )
{
#if defined( DEBUGGING ) && DEBUGGING
    assert( windowID >= 0 && windowID < MAXNUMWINDOWS ) ;
#endif
    gWindowArray[windowID].theMouseDragHandler = theMouseDragHandler ;
 
}
 
 
 
/*------------------------------------------------------------------------------
 * 
 */
 
void Q3UL_RegisterRedraw( 
    TQ3UL_WindowRef         windowID, 
    TQ3UL_RedrawHandler     theRedrawHandler )
{
#if defined( DEBUGGING ) && DEBUGGING
    assert( windowID >= 0 && windowID < MAXNUMWINDOWS ) ;
#endif
    gWindowArray[windowID].theRedrawHandler = theRedrawHandler ;
 
}
 
 
 
/*------------------------------------------------------------------------------
 * 
 */
 
void Q3UL_RegisterIdle( 
    TQ3UL_WindowRef         windowID, 
    TQ3UL_IdleHandler       theIdleHandler )
{
#if defined( DEBUGGING ) && DEBUGGING
    assert( windowID >= 0 && windowID < MAXNUMWINDOWS ) ;
#endif
    gWindowArray[windowID].theIdleHandler = theIdleHandler ;
}
 
 
 
/*------------------------------------------------------------------------------
 * 
 */
 
TQ3UL_WindowRef Q3UL_NewWindow(
    short width, 
    short height )
{
    WindowPtr       theWindow ;
    static  short   staggerPos = 50 ;
    int             i ;
 
    /* skanky hack to offset the window, not that you 
     * could create something that is offscreen, so really
     * should check to see if the values need to wrap.
     */
    Rect            boundsRect  ;
    
    boundsRect.top = boundsRect.left = staggerPos ;
    boundsRect.bottom = staggerPos+height ;
    boundsRect.right = staggerPos+height ;
 
    /* find a place for the window in the array */
    while( i < MAXNUMWINDOWS )
    {
        if( gWindowArray[i].window == NULL ) 
            break ;
    }
    
    if( i >= MAXNUMWINDOWS )
    {
        /* can create a window, the array is full */
        SysBeep(10) ;
        return -1 ;
    } 
    
    /* create a new window of width x height */
    theWindow = NewCWindow ( NULL, 
                             &boundsRect, 
                             "\pUntitled", 
                             false, 
                             zoomDocProc, 
                             (WindowPtr)-1, 
                             true, 
                             0L ) ;
    
    if( theWindow != NULL )
        gWindowArray[i].window = theWindow ;         
        
    /*
     * set up a quickDraw 3D view for this window 
     */
     
    gWindowArray[i].theView = Q3UL_NewView( i ) ;
                     
    ShowWindow(theWindow) ;
    
    return i ;
    
}
 
 
 
/*------------------------------------------------------------------------------
 * Dispose of a utility library window, make sure you dispose of associated
 * storage before calling this.
 */
 
void Q3UL_DestroyWindow( 
    TQ3UL_WindowRef windowID )
{
#if defined( DEBUGGING ) && DEBUGGING
    assert( windowID >= 0 && windowID < MAXNUMWINDOWS ) ;
#endif
    /*
     * first get rid of the view we created for this object
     */
    Q3Object_Dispose( gWindowArray[windowID].theView ) ;
    
    /*
     * get rid of the window itself
     */
    DisposeWindow( gWindowArray[windowID].window ) ;
 
    /* reset the fields to nil */
    iZeroWinElement( windowID ) ;
 
}
 
 
 
 
/*------------------------------------------------------------------------------
 * 
 */
 
void Q3UL_ResizeFrontWindow( 
    short x, 
    short y )
{
 
}
 
 
 
/*------------------------------------------------------------------------------
 * 
 */
 
void Q3UL_ZoomFrontWindow()
{
 
}
 
 
 
/*------------------------------------------------------------------------------
 * 
 */
 
void Q3UL_MoveFrontWindow( 
    short top, 
    short left )
{
    MoveWindow ( FrontWindow(), left, top, true ) ; 
}
 
/*------------------------------------------------------------------------------
 * 
 */
 
void Q3UL_RedrawWindow(
    TQ3UL_WindowRef windowID )
{
    GrafPtr     savedPort ;
    
    GetPort( &savedPort ) ;
    SetPort( gWindowArray[windowID].window ) ;
    InvalRect( &gWindowArray[windowID].window->portRect ) ; 
    SetPort( savedPort ) ;
}
 
/*------------------------------------------------------------------------------
 * 
 */
 
void Q3UL_MainEventLoop(void)
{
    EventRecord     event;
    WindowPtr       window;
    short           thePart;
    Rect            screenRect, updateRect;
    Point           aPoint = {100, 100};
    TQ3UL_WindowRef windowID ;
    
 
    while( !gQuitFlag )
    {
        if (WaitNextEvent( everyEvent, &event, 0, nil ))
        {
 
            switch (event.what) {
                case mouseDown:
                
                    thePart = FindWindow( event.where, &window );
                    windowID = iWindowPtrToIdx( window ) ;
                    
                    switch( thePart ) {
                        case inMenuBar: 
                            break;
                        
                        case inDrag:
                            /* drag the window by the title bar */
                            screenRect = (**GetGrayRgn()).rgnBBox;
                            DragWindow( FrontWindow(), event.where, &screenRect );
                            break ;
                    
                        case inContent:
                        
                            /* content region: if the window is not the front
                             * window make it so 
                             */
                            if (window != FrontWindow())
                                SelectWindow( window );
                            
                            /* if we have a mouse hanfler, call it, passing in the window 
                             * reference, and the x, and y position 
                             */
                            if(gWindowArray[windowID].theMouseDownHandler != NULL )
                                (*gWindowArray[windowID].theMouseDownHandler)( 
                                        windowID,
                                        event.where.h,
                                        event.where.v );
                            
                            break ;
                    
                        case inGoAway:
                            if (TrackGoAway( window, event.where )) {
                                /* check to see if there is a close handler for this window */
                                if( gWindowArray[windowID].theCloseHandler)
                                {
                                    /* yes: then call it */
                                    (*gWindowArray[windowID].theCloseHandler)(windowID) ;
                                }
                                else
                                {
                                    /* jusr dispose of the window */
                                    DisposeWindow ( window );
                                }
 
                            }
                            break ;
                            
                        default:
                            break ;
                    }
                    break ;
                            
                        
                case updateEvt:
                
                    window = (WindowPtr)event.message;
                    windowID = iWindowPtrToIdx( window ) ;
                    updateRect = (**(window->visRgn)).rgnBBox;
                    SetPort( window ) ;
                    BeginUpdate( window );
                    
                    /* check to see if there is a redraw handler for this window */
                    if( gWindowArray[windowID].theRedrawHandler)
                    {
                        /* yes: then call it */
                        (*gWindowArray[windowID].theRedrawHandler)(windowID,gWindowArray[windowID].theView) ;
                    }
 
                    EndUpdate( window );
                    break ;
                    
                case keyDown:
                case autoKey:
                    /* check to see if there is a redraw handler for this window */
                    if( gWindowArray[windowID].theKeyHandler)
                    {
                        /* yes: then call it */
                        (*gWindowArray[windowID].theKeyHandler)
                            (windowID,
                            event.where.h,
                            event.where.v,
                            (event.message & charCodeMask) ) ;
                    }
 
                    break;
                    
                case diskEvt:
                    if ( HiWrd(event.message) != noErr ) 
                        (void) DIBadMount(aPoint, event.message);
                    break;
                    
                case osEvt:
                case activateEvt:
                    break;
 
 
            }
        }
        else {
            /* check to see if there is a idle handler for this window */
            if( gWindowArray[windowID].theIdleHandler)
            {
                /* yes: then call it */
                (*gWindowArray[windowID].theIdleHandler)(windowID) ;
            }
        }
    }
}