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.
CApp.cp
/* |
Make QTVR Panorama 1.0b1 |
A simple PowerPlant application for processing PICT files into QuickTime VRª movies. |
Created 29 Jan 1996 by EGH |
Copyright © 1996, Apple Computer, Inc. All rights reserved. |
*/ |
#include <StandardFile.h> |
#include <String_Utils.h> |
#include <LCaption.h> |
#include <UDesktop.h> |
#include <UDrawingState.h> |
#include <LEditField.h> |
#include <LGrowZone.h> |
#include <UMemoryMgr.h> |
#include <LPlaceHolder.h> |
#include <URegistrar.h> |
#include <LScroller.h> |
#include <LStdControl.h> |
#include <LTabGroup.h> |
#include <LTextEdit.h> |
#include <LUndoer.h> |
#include <LWindow.h> |
#include <PP_Resources.h> |
#include "CApp.h" |
#include "CBeachBall.h" |
#include "CMovieMaker.h" |
#include "CPict2VRWindow.h" |
#include "CPrefsWindow.h" |
#include "CUtils.h" |
CPreferences *gAppPrefs = nil; |
CApp *gApp = nil; |
void main(void) |
{ |
SetDebugThrow_(debugAction_Alert); |
SetDebugSignal_(debugAction_Alert); |
InitializeHeap(8); |
UQDGlobals::InitializeToolbox(&qd); |
// check for the existence of QuickTime |
Int32 result; |
OSErr err = ::Gestalt(gestaltQuickTime, &result); |
if (err != noErr) |
{ |
::StopAlert(ALRT_NoQT, nil); |
ExitToShell(); |
} |
new LGrowZone(20000); |
// fire up QuickTime and load the components necessary for |
// creating pano media |
::EnterMovies(); |
::RegisterComponentResourceFile(CurResFile(), 0); |
CApp theApp; |
gApp = &theApp; |
theApp.Run(); |
::ExitMovies(); |
} |
CApp::CApp() |
{ |
mDropMode = false; |
// Register classes for objects created from 'PPob' resources |
URegistrar::RegisterClass(CPict2VRWindow::class_ID, CPict2VRWindow::CreatePict2VRWindowWindowStream); |
URegistrar::RegisterClass(CPrefsWindow::class_ID, CPrefsWindow::CreatePrefsWindowWindowStream); |
URegistrar::RegisterClass(LCaption::class_ID, LCaption::CreateCaptionStream); |
URegistrar::RegisterClass(LDialogBox::class_ID, LDialogBox::CreateDialogBoxStream); |
URegistrar::RegisterClass(LEditField::class_ID, LEditField::CreateEditFieldStream); |
URegistrar::RegisterClass(LPicture::class_ID, LPicture::CreatePictureStream); |
URegistrar::RegisterClass(LPlaceHolder::class_ID, LPlaceHolder::CreatePlaceHolderStream); |
URegistrar::RegisterClass(LStdButton::class_ID, LStdButton::CreateStdButtonStream); |
URegistrar::RegisterClass(LStdCheckBox::class_ID, LStdCheckBox::CreateStdCheckBoxStream); |
URegistrar::RegisterClass(LStdControl::class_ID, LStdControl::CreateStdControlStream); |
URegistrar::RegisterClass(LStdPopupMenu::class_ID, LStdPopupMenu::CreateStdPopupMenuStream); |
URegistrar::RegisterClass(LStdRadioButton::class_ID, LStdRadioButton::CreateStdRadioButtonStream); |
URegistrar::RegisterClass(LTabGroup::class_ID, LTabGroup::CreateTabGroupStream); |
URegistrar::RegisterClass(LView::class_ID, LView::CreateViewStream); |
URegistrar::RegisterClass(LWindow::class_ID, LWindow::CreateWindowStream); |
// create application preferences |
Str63 appName; |
::GetIndString(appName, STRx_Standards, str_ProgramName); |
gAppPrefs = new CPreferences('p2vr', Creator_, appName); |
// look for preferences and use them |
mPrefsHdl = (P2VRPrefsHdl)gAppPrefs->GetPreferenceResource(ResType_Preferences, 128); |
if (mPrefsHdl == nil) |
{ |
// no prefs, so create default ones |
mPrefsHdl = (P2VRPrefsHdl)::NewHandle(sizeof (P2VRPrefsRec)); |
if (mPrefsHdl != nil) |
{ |
(*mPrefsHdl)->dropMode = mDropMode; |
(*mPrefsHdl)->width = 400; |
(*mPrefsHdl)->height = 300; |
(*mPrefsHdl)->codec = 'cvid'; |
(*mPrefsHdl)->pan = 0; |
(*mPrefsHdl)->tilt = 0; |
(*mPrefsHdl)->zoom = 0; |
(*mPrefsHdl)->spatialQuality = codecHighQuality; |
(*mPrefsHdl)->depth = 32; |
CopyPStr("\p.tile", (*mPrefsHdl)->tileSuffix); |
CopyPStr("\p.snm", (*mPrefsHdl)->movieSuffix); |
(*mPrefsHdl)->replaceFiles = false; |
} |
} |
else |
{ |
mDropMode = (*mPrefsHdl)->dropMode; |
} |
// initialize spinning cursor |
CBeachBall::InitBeachBall(); |
if (!mDropMode) |
{ |
try |
{ |
LWindow *splash = LWindow::CreateWindow(WIND_Splash, this); |
if (splash != nil) |
{ |
splash->Show(); |
splash->UpdatePort(); |
UInt32 splashTime = ::TickCount() + 120; // this should be up for at least 180 ticks |
CBeachBall::StartSpinningTask(5); |
while (::TickCount() < splashTime) ; |
CBeachBall::StopSpinningTask(); |
delete splash; |
} |
} |
catch (...) |
{ |
// fall out |
} |
} |
} |
CApp::~CApp() |
{ |
// save the preferences |
if (gAppPrefs != nil && mPrefsHdl != nil) |
{ |
(*mPrefsHdl)->dropMode = mDropMode; |
gAppPrefs->SavePreferenceResource(ResType_Preferences, 128, (Handle)mPrefsHdl); |
} |
} |
Boolean CApp::ObeyCommand( |
CommandT inCommand, |
void *ioParam) |
{ |
Boolean cmdHandled = true; |
switch (inCommand) |
{ |
case cmd_DropMode: |
{ |
mDropMode = !mDropMode; |
SetUpdateCommandStatus(true); |
break; |
} |
case cmd_Preferences: |
{ |
CPrefsWindow *pw = (CPrefsWindow *)LWindow::CreateWindow(WIND_Preferences, this); |
pw->Show(); |
break; |
} |
default: |
cmdHandled = LDocApplication::ObeyCommand(inCommand, ioParam); |
break; |
} |
return cmdHandled; |
} |
void CApp::FindCommandStatus( |
CommandT inCommand, |
Boolean &outEnabled, |
Boolean &outUsesMark, |
Char16 &outMark, |
Str255 outName) |
{ |
outUsesMark = false; |
if (sBusy) |
outEnabled = false; |
else |
switch (inCommand) |
{ |
case cmd_DropMode: |
outEnabled = true; |
outUsesMark = true; |
outMark = mDropMode ? checkMark:noMark; |
break; |
case cmd_Preferences: |
outEnabled = true; |
break; |
default: |
LDocApplication::FindCommandStatus(inCommand, outEnabled, outUsesMark, |
outMark, outName); |
break; |
} |
} |
/* CApp::DoAEOpenOrPrintDoc |
Overridden from LDocApplication because we may want to quit afterwards. |
*/ |
void CApp::DoAEOpenOrPrintDoc( |
const AppleEvent &inAppleEvent, |
AppleEvent& /* outAEReply */, |
Int32 inAENumber) |
{ |
AEDescList docList; |
OSErr err = ::AEGetParamDesc(&inAppleEvent, keyDirectObject, |
typeAEList, &docList); |
ThrowIfOSErr_(err); |
Int32 numDocs; |
err = ::AECountItems(&docList, &numDocs); |
ThrowIfOSErr_(err); |
for (Int32 i = 1; i <= numDocs; i++) |
{ |
AEKeyword theKey; |
DescType theType; |
FSSpec theFileSpec; |
Size theSize; |
err = ::AEGetNthPtr(&docList, i, typeFSS, &theKey, &theType, |
(Ptr) &theFileSpec, sizeof(FSSpec), &theSize); |
ThrowIfOSErr_(err); |
if (inAENumber == ae_OpenDoc) |
{ |
OpenDocument(&theFileSpec); |
} |
else |
{ |
// let the user know we don't do printing in this app |
::StopAlert(ALRT_WeDontPrint, nil); |
} |
} |
::AEDisposeDesc(&docList); |
// if we are in drop mode, get outta here |
if (mDropMode) |
DoQuit(); |
} |
void CApp::OpenDocument( |
FSSpec *inMacFSSpec) |
{ |
Int16 errStrIndex; |
try |
{ |
errStrIndex = err_Window; |
if (mDropMode && mPrefsHdl != nil) |
{ |
// just start making the movie |
MovieMakinRec params; |
params.width = (*mPrefsHdl)->width; |
params.height = (*mPrefsHdl)->height; |
params.srcSpec = *inMacFSSpec; |
params.tileSpec = *inMacFSSpec; |
unsigned char charspace = 31 - (*mPrefsHdl)->tileSuffix[0]; |
if (params.tileSpec.name[0] > charspace) |
params.tileSpec.name[0] = charspace; |
ConcatPStr(params.tileSpec.name, (*mPrefsHdl)->tileSuffix); |
params.destSpec = *inMacFSSpec; |
charspace = 31 - (*mPrefsHdl)->movieSuffix[0]; |
if (params.destSpec.name[0] > charspace) |
params.destSpec.name[0] = charspace; |
ConcatPStr(params.destSpec.name, (*mPrefsHdl)->movieSuffix); |
params.codec = (*mPrefsHdl)->codec; |
params.spatialQuality = (*mPrefsHdl)->spatialQuality; |
params.depth = (*mPrefsHdl)->depth; |
ListenToMessage(msg_MakeMovie, ¶ms); |
} |
else |
{ |
// put up a window for editing movie making parameters |
CPict2VRWindow *p2vr = (CPict2VRWindow *)LWindow::CreateWindow(WIND_Pict2VR, this); |
p2vr->AddListener(this); |
p2vr->SetPictFile(inMacFSSpec); |
} |
} |
catch (ExceptionCode err) |
{ |
ReportError(err, err_Window); |
} |
// drop mode leaves the menu bar inactive |
if (mDropMode) |
UpdateMenus(); |
} |
void CApp::StartUp() |
{ |
ChooseDocument(); |
} |
void CApp::ChooseDocument() |
{ |
StandardFileReply macFileReply; |
SFTypeList typeList; |
UDesktop::Deactivate(); |
typeList[0] = 'PICT'; |
::StandardGetFile(nil, 1, typeList, &macFileReply); |
UDesktop::Activate(); |
if (macFileReply.sfGood) |
{ |
OpenDocument(&macFileReply.sfFile); |
} |
} |
/* CApp::ProgressEvents |
An event processing function necessary because the one implemented in |
LApplication does things we dont want such as changing the cursor. |
This one is useful for processing events during lengthy processes |
(and there is a spinning cursor and a modal window in front). |
*/ |
void CApp::ProgressEvents() |
{ |
EventRecord macEvent; |
SetUpdateCommandStatus(false); |
Boolean gotEvent; |
Int16 count = 0; |
do |
{ |
gotEvent = ::WaitNextEvent(everyEvent, &macEvent, 0, mMouseRgnH); |
if (LAttachable::ExecuteAttachments(msg_Event, &macEvent)) |
{ |
if (gotEvent) |
DispatchEvent(macEvent); |
else |
UseIdleTime(macEvent); |
} |
LPeriodical::DevoteTimeToRepeaters(macEvent); |
if (GetUpdateCommandStatus()) |
UpdateMenus(); |
} while (gotEvent && ++count < 3); // do not hand over too much time |
} |
// ====================================== |
// constants and statics for movie making |
Boolean CApp::sCancelled; |
LWindow *CApp::sProgressWindow = nil; |
Boolean CApp::sBusy = false; |
const PaneIDT Button_Stop = 'stop'; |
const PaneIDT Caption_Proc = 'proc'; |
const PaneIDT Caption_Message = 'mess'; |
const ResIDT WIND_Progress = 207; |
// ====================================== |
void CApp::ListenToMessage( |
MessageT inMessage, |
void *ioParam) |
{ |
switch (inMessage) |
{ |
// note: one could conceivably tell the app to make a movie |
// WHILE it is making one. this would work, except that the |
// newly dropped one will be completed before the original is |
// processed. this does not include numbers of PICTs dropped |
// on the app at once in the Finder |
case msg_MakeMovie: |
{ |
// the make movie message includes parameters for making the movie |
MovieMakinPtr mmp = (MovieMakinPtr)ioParam; |
Str255 procStr; |
::GetIndString(procStr, STRx_Progress, str_Making); |
// create a path name that fits into a Str255 minus the above string |
Str255 moviePathStr; |
GetFullPathName(&mmp->destSpec, moviePathStr, sizeof (Str255) - procStr[0]); |
try |
{ |
// prepare progress stuff |
sCancelled = false; |
sBusy = true; |
SetUpdateCommandStatus(true); |
UpdateMenus(); |
sProgressWindow = LWindow::CreateWindow(WIND_Progress, this); |
ThrowIfNil_(sProgressWindow); |
// set the main progress description string |
ConcatPStr(procStr, moviePathStr); |
SetSizedDescriptor(sProgressWindow, Caption_Proc, procStr); |
// listen to the stop button - provides both mouse and keyboard |
// initiated user cancellation |
LButton *button; |
button = (LButton *)sProgressWindow->FindPaneByID(Button_Stop); |
if (button != nil) |
button->AddListener(this); |
// decide if we are replacing files |
Boolean replaceFiles = false; |
if (mPrefsHdl != nil) |
replaceFiles = (*mPrefsHdl)->replaceFiles; |
// finally, make the movie! |
CBeachBall::StartSpinningTask(5); |
Boolean completed = CMovieMaker::MakeAMovie( |
replaceFiles, |
mmp->srcSpec, mmp->tileSpec, mmp->destSpec, |
mmp->width, mmp->height, |
mmp->pan, mmp->tilt, mmp->zoom, |
mmp->codec, mmp->spatialQuality, mmp->depth, MovieProgressProc); |
CBeachBall::StopSpinningTask(); |
delete sProgressWindow; |
sProgressWindow = nil; |
// let the caller know how things went |
mmp->completed = completed; |
} |
catch (ExceptionCode err) |
{ |
mmp->completed = false; |
// the only exception that can make it here is to fail |
// while creating the progress window |
// all other exceptions are caught by CMovieMaker::MakeAMovie |
if (err != Exception_UserCancelled) |
ReportError(err, err_Window); |
} |
sBusy = false; |
UpdateMenus(); |
break; |
} |
case Button_Stop: |
sCancelled = true; |
break; |
} |
} |
/* CApp::MovieProgressProc |
Called during processing. Gets events handled, messages displayed and |
user cancellation reported. |
*/ |
Boolean CApp::MovieProgressProc( |
StringPtr inMessage) |
{ |
if (inMessage != nil) |
{ |
LPane *messageCaption = sProgressWindow->FindPaneByID(Caption_Message); |
messageCaption->SetDescriptor(inMessage); |
messageCaption->UpdatePort(); |
} |
gApp->ProgressEvents(); |
return sCancelled; |
} |
/* CApp::BugUserTilSwitchedIn |
Use the notification manager to let the user know they should switch in. |
Returns once this has happened. |
Useful for waiting to put up alerts during long processes where the possibility |
of the user having switched out is an issue. |
*/ |
void CApp::BugUserTilSwitchedIn() |
{ |
if (!IsOnDuty()) |
{ |
NMRec note; |
OSErr nmErr; |
Handle sicnH = ::GetResource('SICN', 12000); |
if (sicnH) |
{ |
::HNoPurge(sicnH); |
::DetachResource(sicnH); |
} |
note.qType = nmType; |
note.nmMark = 1; |
note.nmIcon = sicnH; |
note.nmSound = (Handle) -1; |
note.nmStr = nil; |
note.nmResp = nil; |
note.nmRefCon = 0; |
if ((nmErr = ::NMInstall(¬e)) == noErr) |
{ |
while (!IsOnDuty()) |
{ |
ProgressEvents(); |
} |
nmErr = ::NMRemove(¬e); |
} |
if (sicnH != nil) |
::DisposeHandle(sicnH); |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14