VDTextSample.c

/*
    File:       VDTextSample.c
    
    Written by: Larry Lai, DTS
 
    Copyright:  © 1995 by Apple Computer, Inc., all rights reserved.
 
    This snippet shows you how to draw and erase text to the video
    preview image without causing flickers on the screen. It only 
    works with 'vdig's that support key color (Quadra 660AV, 840AV, 
    630 and PowerMac 6100/7100/8100 AVs). Read "Inside Macintosh: 
    QuickTime Component" Video Digitizer Component chapter for more 
    information.
    
    Change History (most recent first):
 
        <1> 2/22/95 LL  create first working version.
            3/10/95 LL  add about-this-app box.
    To Do:  
    
*/
 
/* HEADER FILES */
 
#include    <Types.h>
#include    <Memory.h>
#include    <QuickDraw.h>
#include    <Palettes.h>
#include    <QDOffscreen.h>
#include    <Errors.h>
#include    <Fonts.h>
#include    <Dialogs.h>
#include    <Windows.h>
#include    <Menus.h>
#include    <Events.h>
#include    <OSUtils.h>
#include    <Resources.h>
#include    <ToolUtils.h>
#include    <AppleEvents.h>
#include    <GestaltEqu.h>
#include    <Processes.h>
#include    <Aliases.h>
#include    <MixedMode.h>
#include    <LowMem.h>
#include    <Sound.h>
 
#include    <Movies.h>
#include    <QuickTimeComponents.h>
#include    <ImageCompression.h>
 
/* DEFINES */
 
#define appleID         128         
#define appleMenu       0
#define aboutMeCommand  1
 
#define fileID          129
#define textCommand     1
#define quitCommand     3
 
#define aboutMeDLOG     128
#define okButton        1
 
#define kSoundID        128
#define kBruceIconItem  4
 
/* FUNCTION PROTOTYPES*/
 
void CheckError(OSErr error, Str255 displayString);
Boolean IsQuickTimeInstalled(void);
void initialize(void);
WindowPtr makeWindow(void);
SeqGrabComponent makeSequenceGrabber (WindowPtr aWindow);
void makeGrabChannels ( SeqGrabComponent anSG,
                        SGChannel *videoChannel,
                        SGChannel *soundChannel,
                        const Rect *bounds, Boolean willRecord);
void EraseVideo(SeqGrabComponent aSG, WindowPtr aWindow, SGChannel theChannel);
void ShowAboutMeDialog(void);
void DoCommand(long mResult);
pascal Boolean MyFilter(DialogPtr inputDialog, EventRecord *myDialogEvent, short *theDialogItem);
 
/* GLOBALS */
 
Boolean done = false;
Boolean showString = true;
Boolean menuKey = false;
MenuHandle mymenu0, mymenu1;
WindowPtr   theWindow;
SeqGrabComponent    theSG;
SGChannel   videoChannel, soundChannel;
 
/* FUNCTIONS */
 
void CheckError(OSErr error, Str255 displayString)
{
    if(error == noErr) return;
    if(displayString[0] > 0)
        DebugStr(displayString);
    ExitToShell();
}
 
Boolean IsQuickTimeInstalled(void)
{
    short   error;
    long    result;
    
    error = Gestalt(gestaltQuickTime, &result);
    return  (error == noErr);
}
 
void ShowAboutMeDialog(void)
{
    GrafPtr savePort;
    DialogPtr theDialog;
    Handle  theSound;
    short itemHit;
 
    GetPort(&savePort);
    theDialog = GetNewDialog(aboutMeDLOG, nil, (WindowPtr) - 1);
    SetPort(theDialog);
 
    do
    {
        ModalDialog((ModalFilterProcPtr) MyFilter, &itemHit);
 
        switch(itemHit){
            case kBruceIconItem:
                /* don't mess with Bruce */
                theSound = GetResource('snd ', kSoundID);
                if (theSound != nil) {
                    SndPlay(nil, (SndListHandle)theSound, false);
                    ReleaseResource(theSound);
                }
                break;
                
        }
 
    } while (itemHit != okButton);
 
    CloseDialog(theDialog);
 
    SetPort(savePort);
    return;
}
 
// True confession: this was stolen from C.K's "DialogBits.c".
pascal Boolean MyFilter(DialogPtr inputDialog, EventRecord *myDialogEvent, short *theDialogItem)
{
    Rect tempRect;
    short tempItem;
    Handle tempHandle;
    Point tempPoint;
    Point mousePoint;
    Boolean hiLit = false;
    Boolean returnVal = false;
 
    if (myDialogEvent->what == mouseDown) {
        mousePoint = (myDialogEvent->where);
        GlobalToLocal(&mousePoint);
        /* First see if we're in Bruce */
        GetDItem(inputDialog, kBruceIconItem, &tempItem, &tempHandle, &tempRect);
        if (PtInRect(mousePoint, &tempRect)) {
            /* invert my icon, and track it whilst the user holds the mouse down */
            InvertRect(&tempRect);
            hiLit = true;
            while (StillDown()) {
                GetMouse(&tempPoint);                       /* returns point in local coords */
                if (PtInRect(tempPoint, &tempRect)) {
                    /* in the rect.  See if it's hilighted or not */
                    if (hiLit == false) {
                        hiLit = true;
                        InvertRect(&tempRect);
                    }
                } else {
                    /* not in the rectangle.  If it's hilit, get rid of that */
                    if (hiLit == true) {
                        hiLit = false;
                        InvertRect(&tempRect);
                    }
                }
            }
            if (hiLit == true) {
                /* if it's still hilited when the mouse comes up, then that means the */
                /* user stayed in and wants to take this icon action */
                InvertRect(&tempRect);                      /* clear the hiliting if it's still lit */
                *theDialogItem = kBruceIconItem;
                returnVal = true;                           /* telling the Dialog Manager we handled it, pass item back */
            }
        } 
    }
    return returnVal;
}
 
 
void initialize(void)
{ 
    OSErr   err;
    short   i;
    
    InitGraf (&qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(nil);
    MaxApplZone();
    
    for (i = 0; i<=10; i++)
        MoreMasters();
    
    if(!IsQuickTimeInstalled())
        CheckError(-1, "\pPlease install QuickTime and try again.");
        
    err = EnterMovies();
    CheckError(err, "\pUnable to initialize Movie Toolbox.");
    
        /*  Set up menus.   */
    mymenu0 = GetMenu(appleID);
    AddResMenu(mymenu0, 'DRVR');
    InsertMenu(mymenu0, 0);
    mymenu1 = GetMenu(fileID);
    InsertMenu(mymenu1, 0);
    DrawMenuBar();
}
 
WindowPtr makeWindow(void)
{
    WindowPtr   aWindow;
    Rect        windowRect = {0, 0, 240, 320};
    Rect        bestRect;
    
    /* figure out the best monitor for the window */
    GetBestDeviceRect (nil, &bestRect);
    
    /* put the window in the top left corner of that monitor */
    OffsetRect(&windowRect, bestRect.left + 10, bestRect.top + 50);
    
    /* create the window */
    aWindow = NewCWindow(nil, &windowRect, "\pPreviewer",
                        true, noGrowDocProc, (WindowPtr)-1,
                        true, 0);
            
    /* and set the port to the new window */
    SetPort(aWindow);
    
    return aWindow;
    
}
 
main (void)
{
    OSErr       err = noErr;
    char        key;
 
    initialize();
    theWindow = makeWindow();
    theSG = makeSequenceGrabber(theWindow);
    if(!theSG) return;
    
    makeGrabChannels(theSG, &videoChannel, &soundChannel, 
                    &theWindow->portRect, false);
    
    if((videoChannel == nil) && (soundChannel == nil))
        CheckError(err, "\pCan't start preview");
        
    err = SGStartPreview(theSG);
    CheckError(err, "\pCan't start preview");
    
    while(!done) {
        ICMAlignmentProcRecord alignProc;
        short   part;
        WindowPtr   whichWindow;
        EventRecord theEvent;
        
        GetNextEvent(everyEvent, &theEvent);
        
        switch(theEvent.what) {
            case nullEvent: /*give the sequence grabber time */
                err = SGIdle (theSG);
                if(err ) done = true;
                break;
                
            case updateEvt: 
                if(theEvent.message == (long) theWindow) {
 
                        /* inform the sequesnce grabber of the update */
                    SGUpdate(theSG, nil);
                    EraseVideo(theSG, theWindow, videoChannel);
 
                    BeginUpdate(theWindow);
                    EndUpdate(theWindow);
                        /*and swallow the update event */
                }
                break;
            
            case mouseDown:
                part = FindWindow(theEvent.where,
                                            &whichWindow);
                switch(part) {
                    case inSysWindow:
                        SystemClick(&theEvent, whichWindow);
                        break;
                    case inMenuBar:
                        DoCommand(MenuSelect(theEvent.where));  
                    case inContent:
                        /* pause until mouse button is released */
                        SGPause(theSG, true);
                        while (StillDown())
                        ;
                        SGPause(theSG, false);
                        EraseVideo(theSG, theWindow, videoChannel);
                        break;
                    case inGoAway:
                        done = TrackGoAway (theWindow, theEvent.where);
                        break;
                    case inDrag:
                        /*pause when dragging window so video doesn't draw in
                            the wrong place */
                        SGPause (theSG, true);
                        SGGetAlignmentProc(theSG, &alignProc);
                        DragAlignedWindow(theWindow,
                                            theEvent.where,
                                            &qd.screenBits.bounds,
                                            nil, &alignProc);
                        SGPause(theSG, false);
                        EraseVideo(theSG, theWindow, videoChannel);
                        break;
                }
                break;
            
            case keyDown:
            case autoKey:
                    key = theEvent.message & charCodeMask;
                    if (theEvent.modifiers & cmdKey)
                        if (theEvent.what == keyDown)
                            DoCommand(MenuKey(key));
                    break;
    
        }
    }
        
    /*clean up*/
    SGStop (theSG);
    CloseComponent(theSG);
    DisposeWindow (theWindow);
}
 
void DoCommand(long mResult)
{
    int theMenu;
    short theItem;
    Str255 daName;
    GrafPtr saveThePort;
 
    theItem = LoWord(mResult);
    theMenu = HiWord(mResult);
 
    switch (theMenu)
    {
        case appleID:
            if (theItem == aboutMeCommand)
                ShowAboutMeDialog();
            else
            {
                GetMenuItemText(mymenu0, theItem, daName);
                GetPort(&saveThePort);
                (void)OpenDeskAcc(daName);
                SetPort(saveThePort);
            }
            break;
 
        case fileID:
            switch (theItem)
            {
                case textCommand:
                    showString = 1 - showString;
                    menuKey = true;
                    EraseVideo(theSG, theWindow, videoChannel);
                    break;
                case quitCommand:
                    done = true;
                    break;
                default:
                    break;
            }
            break;
    }
    HiliteMenu(0);
    return;
}
    
 
SeqGrabComponent makeSequenceGrabber (WindowPtr aWindow)
{
    SeqGrabComponent anSG;
    OSErr err = noErr;
    
    /* open up the default sequence grabber */
    anSG = OpenDefaultComponent (SeqGrabComponentType, 0);
    if (anSG) {
            /* initialize the default sequence grabber component */
        err = SGInitialize(anSG);
        if (!err ) {
            /* set the sequence grabber's graphics world to the 
                specified window */
            err = SGSetGWorld (anSG, (CGrafPtr) aWindow, nil);
        }
    }
 
    if (err && anSG) {
        /* clean up on failure */
        CloseComponent(anSG);
        anSG = nil;
    }
    return anSG;
}
 
void makeGrabChannels (SeqGrabComponent anSG,
                        SGChannel *videoChannel,
                        SGChannel *soundChannel,
                        const Rect *bounds, Boolean willRecord)
{
    OSErr   err;
    long    usage;
    /*figure out th usage */
    
    usage = seqGrabPreview;
    if(willRecord)
        usage |= seqGrabRecord;
    /* create a video channel */
    err = SGNewChannel (anSG, VideoMediaType, videoChannel);
    if(!err) {
    
    /* set boundries for new video channel */
        err = SGSetChannelBounds (*videoChannel, bounds);
    
    /*set usage for new video channel */
        if(!err)
            err = SGSetChannelUsage (*videoChannel,
                                        usage | seqGrabPlayDuringRecord);
            
        if(err) {
                /* clean up on failure */
                SGDisposeChannel(anSG, *videoChannel);
                *videoChannel = nil;
        }
    }
    
    /* create a sound channel */
    err = SGNewChannel (anSG, SoundMediaType, soundChannel);
    if(!err){
        /*set usage of new sound channel */
        err = SGSetChannelUsage (*soundChannel, usage);
        if(err){
            /* clean up on failure */
            SGDisposeChannel(anSG, *soundChannel);
            *soundChannel = nil;
        }
    }
}
 
 
void EraseVideo(SeqGrabComponent aSG, WindowPtr aWindow, SGChannel theChannel)
{
    GrafPtr                     savePort;
    GDHandle                    saveGD;
    RGBColor                    oldColor, rgb, myRGBColor;
    VideoDigitizerComponent     aVDIG;
    long                        index;
    OSErr                       error;
 
    aVDIG = SGGetVideoDigitizerComponent(theChannel);       
    error = VDGetKeyColor(aVDIG, &index);
    if(error == noErr){
        
        /* yellow is the color for the text on display */   
        myRGBColor.red = 0xFC00;
        myRGBColor.green = 0xF37D;
        myRGBColor.blue = 0x052F;
    
        GetPort(&savePort);
        saveGD = GetGDevice();
        SetGDevice(GetMainDevice());
        SetPort(aWindow);
    
        if(!showString && menuKey){
    
                Index2Color(index, &rgb);
                GetForeColor(&oldColor);
                RGBForeColor(&rgb);
                PaintRect(&((GrafPtr) aWindow)->portRect);
                RGBForeColor(&oldColor);
                menuKey = false;
 
        }
        
        if(showString){
    
            MoveTo (30,30);
            TextFont (applFont);
            TextSize (14);
            RGBForeColor(&myRGBColor);
            DrawString("\pCupertino News"); 
        }
 
        SetPort(savePort);
        SetGDevice(saveGD);
    }
    else
    {
            /* can not find the key color, let's us bail */
            SysBeep(10);
            Alert(129, nil);        
            done = true;
    }
    
}