/* Copyright (c) Microsoft Corporation. Licensed under the MIT License. */ /*************************************************************************** esl.cpp: Easel classes Primary Author: ****** Listener Easel: ***** Review Status: REVIEWED - any changes to this file must be reviewed! ESL is the base class for all easels. It handles cidEaselOk and cidEaselCancel commands, and calls the virtual _FAcceptChanges() function for cidEaselOk. Custom easels have their own command maps to handle specific messages, and implement _FAcceptChanges() to do the right thing. ***************************************************************************/ #include "studio.h" ASSERTNAME const long kcchMaxTdt = 50; // max length of a spletter const long kdtsMaxRecord = 10 * kdtsSecond; // max time to record a sound const long kdtimMeterUpdate = kdtimSecond / 10; // interval to update meter const long kcsampSec = 11025; // sampling rate for recorder easel long csampSec; // sampling rate for recorder easel RTCLASS(ESL) RTCLASS(ESLT) RTCLASS(ESLA) RTCLASS(SNE) RTCLASS(ESLL) RTCLASS(LSND) RTCLASS(ESLR) /*************************************************************************** Function to build a GCB for creating a child GOB ***************************************************************************/ bool FBuildGcb(PGCB pgcb, long kidParent, long kidChild) { AssertVarMem(pgcb); PGOK pgokPar; RC rcRel; pgokPar = (PGOK)vpapp->Pkwa()->PgobFromHid(kidParent); if (pvNil == pgokPar) { TrashVar(pgcb); return fFalse; } rcRel.Set(krelZero, krelZero, krelOne, krelOne); pgcb->Set(kidChild, pgokPar, fgobNil, kginDefault, pvNil, &rcRel); return fTrue; } /*************************************************************************** Sets the given gok to the given state ***************************************************************************/ void SetGokState(long kid, long st) { PGOK pgok; pgok = (PGOK)vpapp->Pkwa()->PgobFromHid(kid); if (pvNil != pgok && pgok->FIs(kclsGOK) && pgok->Sno() != st) pgok->FChangeState(st); // ignore failure } // // // // ESL (generic easel) stuff begins here // // // BEGIN_CMD_MAP(ESL, GOK) ON_CID_GEN(cidEaselOk, FCmdDismiss, pvNil) ON_CID_GEN(cidEaselCancel, FCmdDismiss, pvNil) END_CMD_MAP_NIL() /*************************************************************************** Create a new easel ***************************************************************************/ PESL ESL::PeslNew(PRCA prca, long kidParent, long kidEasel) { AssertPo(prca, 0); GCB gcb; PESL pesl; if (!FBuildGcb(&gcb, kidParent, kidEasel)) return pvNil; pesl = NewObj ESL(&gcb); if (pvNil == pesl) return pvNil; if (!pesl->_FInit(prca, kidEasel)) { ReleasePpo(&pesl); return pvNil; } AssertPo(pesl, 0); vpcex->EnqueueCid(cidEaselVisible); return pesl; } /*************************************************************************** Initialize the easel and make it visible ***************************************************************************/ bool ESL::_FInit(PRCA prca, long kidEasel) { AssertBaseThis(0); AssertPo(prca, 0); if (!ESL_PAR::_FInit(vpapp->Pkwa(), kidEasel, prca)) return fFalse; if (!_FEnterState(ksnoInit)) return fFalse; vpapp->DisableAccel(); STDIO::PauseActionButton(); return fTrue; } /*************************************************************************** Clean up and delete this easel ***************************************************************************/ ESL::~ESL(void) { AssertBaseThis(0); vpapp->EnableAccel(); STDIO::ResumeActionButton(); } /*************************************************************************** Dismiss and delete this easel ***************************************************************************/ bool ESL::FCmdDismiss(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); if (pcmd->cid == cidEaselOk) { bool fDismissEasel = fTrue; // Could return fTrue here if _FAcceptChanges fails to abort // dismissal of easel, but instead we release anyway to be // consistent with browsers. _FAcceptChanges(&fDismissEasel); // If we did not accept the changes, (but nothing failed), // then we will not dismiss the easel. if(!fDismissEasel) return fTrue; } Release(); // destroys entire gob tree return fTrue; } #ifdef DEBUG /*************************************************************************** Assert the validity of the ESL. ***************************************************************************/ void ESL::AssertValid(ulong grf) { ESL_PAR::AssertValid(fobjAllocated); } /*************************************************************************** Mark memory used by the ESL ***************************************************************************/ void ESL::MarkMem(void) { AssertThis(0); ESL_PAR::MarkMem(); } #endif //DEBUG // // // // ESLT (text easel) stuff begins here // // // BEGIN_CMD_MAP(ESLT, ESL) ON_CID_GEN(cidEaselRotate, FCmdRotate, pvNil) ON_CID_GEN(cidEaselTransmogrify, FCmdTransmogrify, pvNil) ON_CID_GEN(cidEaselFont, FCmdStartPopup, pvNil) ON_CID_GEN(cidEaselShape, FCmdStartPopup, pvNil) ON_CID_GEN(cidEaselTexture, FCmdStartPopup, pvNil) ON_CID_GEN(cidEaselSetFont, FCmdSetFont, pvNil) ON_CID_GEN(cidEaselSetShape, FCmdSetShape, pvNil) ON_CID_GEN(cidEaselSetColor, FCmdSetColor, pvNil) END_CMD_MAP_NIL() /*************************************************************************** Create a new text easel. If pactr is pvNil, this is for a new TDT and pstnNew, tdtsNew, and ptagTdfNew will be used as initial values. ***************************************************************************/ PESLT ESLT::PesltNew(PRCA prca, PMVIE pmvie, PACTR pactr, PSTN pstnNew, long tdtsNew, PTAG ptagTdfNew) { AssertPo(prca, 0); AssertPo(pmvie, 0); AssertNilOrPo(pactr, 0); AssertNilOrPo(pstnNew, 0); if (tdtsNew != tdtsNil) AssertIn(tdtsNew, 0, tdtsLim); AssertNilOrVarMem(ptagTdfNew); PESLT peslt; GCB gcb; if (!FBuildGcb(&gcb, kidBackground, kidSpltGlass)) return pvNil; peslt = NewObj ESLT(&gcb); if (pvNil == peslt) return pvNil; if (!peslt->_FInit(prca, kidSpltGlass, pmvie, pactr, pstnNew, tdtsNew, ptagTdfNew)) { ReleasePpo(&peslt); return pvNil; } AssertPo(peslt, 0); vpcex->EnqueueCid(cidEaselVisible); return peslt; } /*************************************************************************** Set up this easel ***************************************************************************/ bool ESLT::_FInit(PRCA prca, long kidEasel, PMVIE pmvie, PACTR pactr, PSTN pstnNew, long tdtsNew, PTAG ptagTdfNew) { AssertBaseThis(0); AssertPo(prca, 0); AssertPo(pmvie, 0); AssertNilOrPo(pactr, 0); Assert(pvNil == pactr || pactr->Ptmpl()->FIsTdt(), "only use ESLT for TDTs"); AssertNilOrPo(pstnNew, 0); if (tdtsNew != tdtsNil) AssertIn(tdtsNew, 0, tdtsLim); AssertNilOrVarMem(ptagTdfNew); GCB gcb; COST cost; STN stn; bool fNewTdt = (pactr == pvNil); PTDT ptdt; _prca = prca; _pactr = pactr; _pmvie = pmvie; if (!ESLT_PAR::_FInit(prca, kidEasel)) return fFalse; if (!FBuildGcb(&gcb, kidSpltPreviewFrame, CMH::HidUnique())) return fFalse; _psflTdts = NewObj SFL; if (pvNil == _psflTdts) return fFalse; _psflTdf = NewObj SFL; if (pvNil == _psflTdf) return fFalse; _psflMtrl = NewObj SFL; if (pvNil == _psflMtrl) return fFalse; if (fNewTdt) { AssertPo(pstnNew, 0); AssertIn(tdtsNew, 0, tdtsLim); AssertVarMem(ptagTdfNew); ptdt = TDT::PtdtNew(pstnNew, tdtsNew, ptagTdfNew); if (pvNil == ptdt) return fFalse; _pape = APE::PapeNew(&gcb, ptdt, pvNil, 0, fFalse, _prca); ReleasePpo(&ptdt); if (pvNil == _pape) return fFalse; stn = *pstnNew; } else { // We have to make a duplicate TDT rather than use the existing one // because the user may experimentally change the TDT, then hit Cancel. if (!cost.FGet(pactr->Pbody())) return fFalse; ptdt = ((PTDT)pactr->Ptmpl())->PtdtDup(); if (pvNil == ptdt) return fFalse; _pape = APE::PapeNew(&gcb, ptdt, &cost, 0, fFalse, _prca); ReleasePpo(&ptdt); if (pvNil == _pape) return fFalse; pactr->Ptmpl()->GetName(&stn); } // Set up the edit box if (!FBuildGcb(&gcb, kidSpltEditBox, CMH::HidUnique())) return fFalse; EDPAR edpar(gcb._hid, gcb._pgob, gcb._grfgob, gcb._gin, &gcb._rcAbs, &gcb._rcRel, vpappb->OnnDefVariable(), 0, vpappb->DypTextDef(), tahLeft, tavCenter); _psne = SNE::PsneNew(&edpar, this, &stn); if (pvNil == _psne) return fFalse; _psne->Activate(fTrue); _psne->SetSel(0, _psne->IchMac(), fFalse); // select all of the text _psne->SetCursCno(_prca, kcrsIBeam); return fTrue; } /*************************************************************************** Clean up and delete this easel. Note that I don't need to delete _psne or _pape because they're GOBs and are automatically destroyed with the gob tree. ***************************************************************************/ ESLT::~ESLT(void) { AssertBaseThis(0); ReleasePpo(&_psflTdts); ReleasePpo(&_psflTdf); ReleasePpo(&_psflMtrl); ReleasePpo(&_pbclTdf); ReleasePpo(&_pbclMtrl); } /*************************************************************************** Handle a rotate command ***************************************************************************/ bool ESLT::FCmdRotate(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); _pape->ChangeView(); return fTrue; } /*************************************************************************** Handle a transmogrify command (pick a random shape, font, and material) ***************************************************************************/ bool ESLT::FCmdTransmogrify(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); long tdts; CKI cki; long ithd; THD thd; TAG tagTdf; TAG tagMtrl; vpappb->BeginLongOp(); // Pick a random shape tdts = _psflTdts->LwNext(tdtsLim); // Pick a random font if (pvNil == _pbclTdf) { cki.ctg = kctgTfth; cki.cno = cnoNil; _pbclTdf = BCL::PbclNew(pvNil, &cki, ctgNil, pvNil, fTrue); } if (_pbclTdf != pvNil && _pbclTdf->IthdMac() != 0) { ithd = _psflTdf->LwNext(_pbclTdf->IthdMac()); _pbclTdf->GetThd(ithd, &thd); tagTdf = thd.tag; if (vptagm->FCacheTagToHD(&tagTdf)) { // Failure here is harmless _pape->FChangeTdt(pvNil, tdts, &tagTdf); } } // Pick a random material if (pvNil == _pbclMtrl) { cki.ctg = kctgMtth; cki.cno = cnoNil; _pbclMtrl = BCL::PbclNew(pvNil, &cki, ctgNil, pvNil, fTrue); } if (_pbclMtrl != pvNil && _pbclMtrl->IthdMac() != 0) { ithd = _psflMtrl->LwNext(_pbclMtrl->IthdMac()); _pbclMtrl->GetThd(ithd, &thd); tagMtrl = thd.tag; if (vptagm->FCacheTagToHD(&tagMtrl)) { // Failure here is harmless _pape->FSetTdtMtrl(&tagMtrl); } } vpappb->EndLongOp(); return fTrue; } /*************************************************************************** Start a popup ***************************************************************************/ bool ESLT::FCmdStartPopup(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); CKI ckiGPar; long kid; long ithumSelect = ivNil; long sidSelect = vpapp->SidProduct(); long cidSelect; TAG tagTdf; long tdts; CNO cnoSelect; ckiGPar.cno = cnoNil; switch (pcmd->cid) { case cidEaselFont: ckiGPar.ctg = kctgTfth; kid = kidSpltsFont; _pape->GetTdtInfo(pvNil, pvNil, &tagTdf); ithumSelect = tagTdf.cno; sidSelect = tagTdf.sid; cidSelect = cidEaselSetFont; break; case cidEaselShape: ckiGPar.ctg = kctgTsth; kid = kidSpltsShape; _pape->GetTdtInfo(pvNil, &tdts, pvNil); ithumSelect = tdts; cidSelect = cidEaselSetShape; break; case cidEaselTexture: ckiGPar.ctg = kctgMtth; if (_pape->FGetTdtMtrlCno(&cnoSelect)) ithumSelect = cnoSelect; else ithumSelect = ivNil; kid = kidSpltsColor; cidSelect = cidEaselSetColor; break; default: Bug("Invalid cid for ESLT::FCmdStartPopup"); break; } MP::PmpNew(kidSpltBackground, kid, _prca, pcmd, kbwsCnoRoot, ithumSelect, sidSelect, ckiGPar, ctgNil, this, cidSelect, fTrue); return fTrue; } /*************************************************************************** Handle a command to change the font ***************************************************************************/ bool ESLT::FCmdSetFont(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); TAG tagTdfOld; TAG tagTdfNew; tagTdfNew.sid = pcmd->rglw[1]; tagTdfNew.pcrf = pvNil; tagTdfNew.ctg = kctgTdf; tagTdfNew.cno = pcmd->rglw[0]; _pape->GetTdtInfo(pvNil, pvNil, &tagTdfOld); if (fcmpEq == vptagm->FcmpCompareTags(&tagTdfOld, &tagTdfNew)) return fTrue; // nothing to do // If FChangeTdt fails, someone will report the error if (vptagm->FCacheTagToHD(&tagTdfNew)) _pape->FChangeTdt(pvNil, tdtsNil, &tagTdfNew); return fTrue; } /*************************************************************************** Handle a command to change the shape ***************************************************************************/ bool ESLT::FCmdSetShape(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); long tdtsOld; long tdtsNew = pcmd->rglw[0]; _pape->GetTdtInfo(pvNil, &tdtsOld, pvNil); // If FChangeTdt fails, someone will report the error if (tdtsOld != tdtsNew) _pape->FChangeTdt(pvNil, tdtsNew, pvNil); return fTrue; } /*************************************************************************** Handle a command to change the color ***************************************************************************/ bool ESLT::FCmdSetColor(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); TAG tagTdfNew; tagTdfNew.sid = pcmd->rglw[1]; tagTdfNew.pcrf = pvNil; tagTdfNew.ctg = kctgMtrl; tagTdfNew.cno = pcmd->rglw[0]; // If FSetTdtMtrl fails, someone will report the error if (vptagm->FCacheTagToHD(&tagTdfNew)) _pape->FSetTdtMtrl(&tagTdfNew); return fTrue; } /*************************************************************************** Update the APE when the text of the SNE changed ***************************************************************************/ bool ESLT::FTextChanged(PSTN pstnNew) { AssertBaseThis(0); // we may still be setting up the ESLT AssertPo(pstnNew, 0); return _pape->FChangeTdt(pstnNew, tdtsNil, pvNil); } /*************************************************************************** Make the changes to pactr ***************************************************************************/ bool ESLT::_FAcceptChanges(bool *pfDismissEasel) { AssertThis(0); AssertVarMem(pfDismissEasel); long ich; bool fNonSpaceFound = fFalse; PACTR pactrDup = pvNil; bool fChangesMade = fFalse; PTDT ptdtOld; STN stnOld; long tdtsOld; TAG tagTdfOld; STN stnNew; long tdtsNew; TAG tagTdfNew; long cbset; long ibset; bool fMtrl; long cmid; TAG tagMtrl; if (pvNil == _pactr) // new TDT { _pape->GetTdtInfo(&stnNew, &tdtsNew, &tagTdfNew); for (ich = 0; ich < stnNew.Cch(); ich++) { if (stnNew.Psz()[ich] != ChLit(' ')) { fNonSpaceFound = fTrue; break; } } if (!fNonSpaceFound) { // user deleted all text, so treat like a cancel vpcex->EnqueueCid(cidEaselClosing, pvNil, pvNil, fFalse); return fTrue; } if (!_pmvie->FInsTdt(&stnNew, tdtsNew, &tagTdfNew)) goto LFail; _pactr = _pmvie->Pscen()->PactrSelected(); cbset = _pape->Cbset(); // Now apply costume changes for (ibset = 0; ibset < cbset; ibset++) { if (_pape->FGetMaterial(ibset, &fMtrl, &cmid, &tagMtrl)) { if (!_pactr->FSetCostumeCore(ibset, &tagMtrl, cmid, !fMtrl)) goto LFail; fChangesMade = fTrue; } } _pmvie->PmvuCur()->StartPlaceActor(); } else { ptdtOld = (PTDT)_pactr->Ptmpl(); if (!_pactr->FDup(&pactrDup)) goto LFail; // first apply TDT changes ptdtOld->GetInfo(&stnOld, &tdtsOld, &tagTdfOld); _pape->GetTdtInfo(&stnNew, &tdtsNew, &tagTdfNew); if (!stnOld.FEqual(&stnNew) || tdtsOld != tdtsNew || fcmpEq != TAGM::FcmpCompareTags(&tagTdfOld, &tagTdfNew)) { if (!_pmvie->FChangeActrTdt(_pactr, &stnNew, tdtsNew, &tagTdfNew)) goto LFail; fChangesMade = fTrue; } // Now apply costume changes cbset = _pape->Cbset(); for (ibset = 0; ibset < cbset; ibset++) { if (_pape->FGetMaterial(ibset, &fMtrl, &cmid, &tagMtrl)) { if (!_pactr->FSetCostumeCore(ibset, &tagMtrl, cmid, !fMtrl)) goto LFail; fChangesMade = fTrue; } } if (fChangesMade) { if (!_pactr->FCreateUndo(pactrDup)) goto LFail; } ReleasePpo(&pactrDup); } vpcex->EnqueueCid(cidEaselClosing, pvNil, pvNil, fTrue); _pmvie->Pscen()->SelectActr(_pactr); return fTrue; LFail: if (_pactr != pvNil) { if (pvNil != pactrDup) { _pactr->Restore(pactrDup); ReleasePpo(&pactrDup); } PushErc(ercSoc3DWordChange); } else PushErc(ercSoc3DWordCreate); return fFalse; } #ifdef DEBUG /*************************************************************************** Assert the validity of the ESLT. ***************************************************************************/ void ESLT::AssertValid(ulong grf) { ESLT_PAR::AssertValid(fobjAllocated); AssertPo(_pmvie, 0); AssertNilOrPo(_pactr, 0); AssertPo(_pape, 0); AssertPo(_psne, 0); AssertPo(_prca, 0); AssertPo(_psflTdts, 0); AssertPo(_psflTdf, 0); AssertPo(_psflMtrl, 0); AssertNilOrPo(_pbclTdf, 0); AssertNilOrPo(_pbclMtrl, 0); } /*************************************************************************** Mark memory used by the ESLT. The _pape and _psne are marked automatically with the GOB tree. ***************************************************************************/ void ESLT::MarkMem(void) { AssertThis(0); ESLT_PAR::MarkMem(); MarkMemObj(_psflTdts); MarkMemObj(_psflTdf); MarkMemObj(_psflMtrl); MarkMemObj(_pbclTdf); MarkMemObj(_pbclMtrl); } #endif //DEBUG // // // // SNE (spletter name editor) stuff begins here // // // /*************************************************************************** Create a new spletter name editor with initial string pstnInit. Text change notifications will be sent to peslt. ***************************************************************************/ PSNE SNE::PsneNew(PEDPAR pedpar, PESLT peslt, PSTN pstnInit) { AssertVarMem(pedpar); AssertBasePo(peslt, 0); AssertPo(pstnInit, 0); PSNE psne; psne = NewObj SNE(pedpar); if (pvNil == psne) return pvNil; if (!psne->_FInit()) { ReleasePpo(&psne); return pvNil; } psne->_peslt = peslt; psne->SetStn(pstnInit, fFalse); return psne; } /*************************************************************************** Trap the default FReplace to prevent illegal strings and to notify the ESLT that the text has changed. ***************************************************************************/ bool SNE::FReplace(achar *prgch, long cchIns, long ich1, long ich2, long gin) { AssertThis(0); STN stnOld; STN stnNew; GetStn(&stnOld); // Note that gin is forced to ginNil here so there's no flicker if // the resulting text is illegal if (!SNE_PAR::FReplace(prgch, cchIns, ich1, ich2, ginNil)) return fFalse; // Look for illegal strings: GetStn(&stnNew); if (stnNew.Cch() > kcchMaxTdt) { SetStn(&stnOld, fFalse); GetStn(&stnNew); } #ifdef DEBUG else if (stnNew.Cch() == 5 && stnNew.Psz()[0] == ChLit(')') && stnNew.Psz()[4] == ChLit('(')) { // Hack for testing: ")xxx(" changes the TDT to // all ASCII values from xxx to xxx + kcchMaxTdt (or up to chNil). STN stnT; achar rgch[kcchMaxTdt]; long ichStart; long ich; long cch = 0; stnT.SetRgch(&stnNew.Psz()[1], 3); if (stnT.FGetLw(&ichStart, 10)) { for (ich = 0; ich < kcchMaxTdt; ich++) { rgch[ich] = (achar)ichStart + (achar)ich; if (rgch[ich] == chNil) break; cch++; } SNE_PAR::FReplace(rgch, cch, 0, IchMac(), fFalse); GetStn(&stnNew); } } #endif //DEBUG // Notify the easel so the TDT can be updated if (!_peslt->FTextChanged(&stnNew)) SetStn(&stnOld, fFalse); // Now do the actual update _UpdateLn(0, 1, 1, _dypLine, gin); return fTrue; } #ifdef DEBUG /*************************************************************************** Assert the validity of the SNE. ***************************************************************************/ void SNE::AssertValid(ulong grf) { SNE_PAR::AssertValid(fobjAllocated); AssertBasePo(_peslt, 0); } /*************************************************************************** Mark memory used by the SNE ***************************************************************************/ void SNE::MarkMem(void) { AssertThis(0); SNE_PAR::MarkMem(); } #endif //DEBUG // // // // ESLA (actor easel) stuff begins here // // // BEGIN_CMD_MAP(ESLA, ESL) ON_CID_GEN(cidEaselRotate, FCmdRotate, pvNil) ON_CID_GEN(cidEaselCostumes, FCmdTool, pvNil) ON_CID_GEN(cidEaselAccessories, FCmdTool, pvNil) END_CMD_MAP_NIL() /*************************************************************************** Create a new actor easel ***************************************************************************/ PESLA ESLA::PeslaNew(PRCA prca, PMVIE pmvie, PACTR pactr) { AssertPo(prca, 0); AssertPo(pmvie, 0); AssertPo(pactr, 0); PESLA pesla; GCB gcb; if (!FBuildGcb(&gcb, kidBackground, kidCostGlass)) return pvNil; pesla = NewObj ESLA(&gcb); if (pvNil == pesla) return pvNil; if (!pesla->_FInit(prca, kidCostGlass, pmvie, pactr)) { ReleasePpo(&pesla); return pvNil; } AssertPo(pesla, 0); vpcex->EnqueueCid(cidEaselVisible); return pesla; } /*************************************************************************** Set up this easel ***************************************************************************/ bool ESLA::_FInit(PRCA prca, long kidEasel, PMVIE pmvie, PACTR pactr) { AssertBaseThis(0); AssertPo(prca, 0); AssertPo(pmvie, 0); AssertPo(pactr, 0); GCB gcb; COST cost; STN stn; EDPAR edpar; if (!ESLA_PAR::_FInit(prca, kidEasel)) return fFalse; if (!cost.FGet(pactr->Pbody())) return fFalse; if (!FBuildGcb(&gcb, kidCostPreviewFrame, CMH::HidUnique())) return fFalse; _pape = APE::PapeNew(&gcb, pactr->Ptmpl(), &cost, pactr->AnidCur(), fFalse, prca); if (pvNil == _pape) return fFalse; _pape->SetToolIncCmtl(); if (!FBuildGcb(&gcb, kidCostEditBox, CMH::HidUnique())) return fFalse; edpar.Set(gcb._hid, gcb._pgob, gcb._grfgob, gcb._gin, &gcb._rcAbs, &gcb._rcRel, vpappb->OnnDefVariable(), 0, vpappb->DypTextDef(), tahLeft, tavCenter); _pmvie = pmvie; _pactr = pactr; _pactr->GetName(&stn); _pedsl = EDSL::PedslNew(&edpar); if (pvNil == _pedsl) return fFalse; _pedsl->SetStn(&stn); _pedsl->SetSel(0, _pedsl->IchMac()); // select all of the text _pedsl->Activate(fTrue); _pedsl->SetCursCno(prca, kcrsIBeam); return fTrue; } /*************************************************************************** Clean up and delete this easel. Note that I don't need to delete _pedsl or _pape because they're GOBs and are automatically destroyed with the gob tree. ***************************************************************************/ ESLA::~ESLA(void) { AssertBaseThis(0); } /*************************************************************************** Handle a rotate command ***************************************************************************/ bool ESLA::FCmdRotate(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); _pape->ChangeView(); return fTrue; } /*************************************************************************** Handle a tool change command ***************************************************************************/ bool ESLA::FCmdTool(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); switch(pcmd->cid) { case cidEaselAccessories: _pape->SetToolIncAccessory(); break; case cidEaselCostumes: _pape->SetToolIncCmtl(); break; default: Bug("unexpected cid"); break; } return fTrue; } /*************************************************************************** Make the changes to _pactr ***************************************************************************/ bool ESLA::_FAcceptChanges(bool *pfDismissEasel) { AssertThis(0); AssertVarMem(pfDismissEasel); PACTR pactrDup; bool fNonSpaceFound; long ich; bool fChangesMade = fFalse; STN stnOld; STN stnNew; long cbset; long ibset; bool fMtrl; long cmid; TAG tagMtrl; if (!_pactr->FDup(&pactrDup)) return fFalse; _pactr->GetName(&stnOld); _pedsl->GetStn(&stnNew); if (!stnOld.FEqual(&stnNew)) { // Check for empty or "spaces only" string fNonSpaceFound = fFalse; for (ich = 0; ich < stnNew.Cch(); ich++) { if (stnNew.Psz()[ich] != ChLit(' ')) { fNonSpaceFound = fTrue; break; } } if (fNonSpaceFound) { if (!_pmvie->FNameActr(_pactr->Arid(), &stnNew)) goto LFail; fChangesMade = fTrue; } } // Now apply costume changes cbset = _pape->Cbset(); for (ibset = 0; ibset < cbset; ibset++) { if (_pape->FGetMaterial(ibset, &fMtrl, &cmid, &tagMtrl)) { if (!_pactr->FSetCostumeCore(ibset, &tagMtrl, cmid, !fMtrl)) goto LFail; fChangesMade = fTrue; } } if (fChangesMade) { if (!_pactr->FCreateUndo(pactrDup, fFalse, &stnOld)) goto LFail; } ReleasePpo(&pactrDup); return fTrue; LFail: _pactr->Restore(pactrDup); ReleasePpo(&pactrDup); return fFalse; } #ifdef DEBUG /*************************************************************************** Assert the validity of the ESLA. ***************************************************************************/ void ESLA::AssertValid(ulong grf) { ESLA_PAR::AssertValid(fobjAllocated); AssertPo(_pmvie, 0); AssertPo(_pactr, 0); AssertPo(_pape, 0); AssertPo(_pedsl, 0); } /*************************************************************************** Mark memory used by the ESLA. The _pape and _pedsl are marked automatically with the GOB tree. ***************************************************************************/ void ESLA::MarkMem(void) { AssertThis(0); ESLA_PAR::MarkMem(); } #endif //DEBUG // // // ESLL (EaSeL Listener) // The Listener displays either all background sounds or the // actor Sound Effects and the actor Speech sounds of highest precedence. // Note: A sounder speech sound takes precedence over a motion match // speech sound // BEGIN_CMD_MAP(ESLL, ESL) ON_CID_GEN(cidEaselVol, FCmdVlm, pvNil) ON_CID_GEN(cidEaselPlay, FCmdPlay, pvNil) END_CMD_MAP_NIL() /*************************************************************************** Create a new listener easel ***************************************************************************/ PESLL ESLL::PesllNew(PRCA prca, PMVIE pmvie, PACTR pactr) { AssertPo(prca, 0); AssertPo(pmvie, 0); AssertNilOrPo(pactr, 0); PESLL pesll; GCB gcb; long kidGlass; if (pvNil == pactr) kidGlass = kidListenGlassBkgd; else kidGlass = kidListenGlassActor; if (!FBuildGcb(&gcb, kidBackground, kidGlass)) return pvNil; pesll = NewObj ESLL(&gcb); if (pvNil == pesll) return pvNil; if (!pesll->_FInit(prca, kidGlass, pmvie, pactr)) { ReleasePpo(&pesll); return pvNil; } AssertPo(pesll, 0); vpcex->EnqueueCid(cidEaselVisible); return pesll; } /*************************************************************************** Set up this easel ***************************************************************************/ bool ESLL::_FInit(PRCA prca, long kidEasel, PMVIE pmvie, PACTR pactr) { AssertBaseThis(0); AssertPo(prca, 0); AssertPo(pmvie, 0); AssertNilOrPo(pactr, 0); PGL pgltag; long vlm; bool fLoop; if (!ESLL_PAR::_FInit(prca, kidEasel)) return fFalse; _pmvie = pmvie; _pscen = pmvie->Pscen(); _pactr = pactr; if (pvNil == pactr) { // Scene sounds // Speech if (!_pscen->FQuerySnd(stySpeech, &pgltag, &vlm, &fLoop)) return fFalse; if (!_lsndSpeech.FInit(stySpeech, kidListenVolSpeech, kidListenSpeechIcon, kidListenEditBoxSpeech, &pgltag, vlm, fLoop, 0, fFalse)) { return fFalse; } // SFX if (!_pscen->FQuerySnd(stySfx, &pgltag, &vlm, &fLoop)) return fFalse; if (!_lsndSfx.FInit(stySfx, kidListenVolFX, kidListenFXIcon, kidListenEditBoxFX, &pgltag, vlm, fLoop, 0, fFalse)) { return fFalse; } // Midi if (!_pscen->FQuerySnd(styMidi, &pgltag, &vlm, &fLoop)) return fFalse; if (!_lsndMidi.FInit(styMidi, kidListenVolMidi, kidListenMidiIcon, kidListenEditBoxMidi, &pgltag, vlm, fLoop, 0, fFalse)) { return fFalse; } } else { // Actor sounds // Speech if (!_pactr->FQuerySnd(stySpeech, fFalse, &pgltag, &vlm, &fLoop)) return fFalse; if (!_lsndSpeech.FInit(stySpeech, kidListenVolSpeech, kidListenSpeechIcon, kidListenEditBoxSpeech, &pgltag, vlm, fLoop, _pactr->Arid(), fFalse)) { return fFalse; } // SFX if (!_pactr->FQuerySnd(stySfx, fFalse, &pgltag, &vlm, &fLoop)) return fFalse; if (!_lsndSfx.FInit(stySfx, kidListenVolFX, kidListenFXIcon, kidListenEditBoxFX, &pgltag, vlm, fLoop, _pactr->Arid(), fFalse)) { return fFalse; } // Motion-match speech // If no non-motion match speech sounds take precedence, display // motion match speech sounds if (!_lsndSpeech.FValidSnd()) { if (!_pactr->FQuerySnd(stySpeech, fTrue, &pgltag, &vlm, &fLoop)) return fFalse; if (!_lsndSpeechMM.FInit(stySpeech, kidListenVolSpeechMM, kidListenSpeechMMIcon, kidListenEditBoxSpeechMM, &pgltag, vlm, fLoop, _pactr->Arid(), fTrue)) { return fFalse; } } // Motion-match SFX // If no non-motion match sound effects sounds take precedence, display // motion match sound effects sounds if (!_lsndSfx.FValidSnd()) { if (!_pactr->FQuerySnd(stySfx, fTrue, &pgltag, &vlm, &fLoop)) return fFalse; if (!_lsndSfxMM.FInit(stySfx, kidListenVolFXMM, kidListenFXMMIcon, kidListenEditBoxFXMM, &pgltag, vlm, fLoop, _pactr->Arid(), fTrue)) { return fFalse; } } } return fTrue; } /*************************************************************************** Are there valid sounds in this Lsnd? ***************************************************************************/ bool LSND::FValidSnd(void) { AssertThis(0); PMSND pmsnd; long itag; TAG tag; if (pvNil == _pgltag) return fFalse; for(itag = 0; itag < _pgltag->IvMac(); itag++) { _pgltag->Get(itag, &tag); pmsnd = (PMSND)vptagm->PbacoFetch(&tag, MSND::FReadMsnd); if (pvNil == pmsnd) continue; if (!pmsnd->FValid()) { ReleasePpo(&pmsnd); continue; } ReleasePpo(&pmsnd); return fTrue; } return fFalse; } /*************************************************************************** Clean up and delete this easel ***************************************************************************/ ESLL::~ESLL(void) { AssertBaseThis(0); } /*************************************************************************** Handle a Listener volume change command ***************************************************************************/ bool ESLL::FCmdVlm(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); long kid = pcmd->rglw[0]; long vlm = pcmd->rglw[1]; switch (kid) { case kidListenVolSpeech: _lsndSpeech.SetVlmNew(vlm); break; case kidListenVolFX: _lsndSfx.SetVlmNew(vlm); break; case kidListenVolSpeechMM: _lsndSpeechMM.SetVlmNew(vlm); break; case kidListenVolFXMM: _lsndSfxMM.SetVlmNew(vlm); break; case kidListenVolMidi: _lsndMidi.SetVlmNew(vlm); break; default: Bug("Invalid kid"); break; } return fTrue; } /*************************************************************************** Handle a Listener play command ***************************************************************************/ bool ESLL::FCmdPlay(PCMD pcmd) { AssertVarMem(pcmd); AssertNilOrPo(_pactr, 0); long kid = pcmd->rglw[0]; bool fPlay = FPure(pcmd->rglw[1]); if (!fPlay) { StopAllMovieSounds(); return fTrue; } // Actor Sounds switch (kid) { case kidListenEditBoxSpeech: _lsndSpeech.Play(); break; case kidListenEditBoxFX: _lsndSfx.Play(); break; case kidListenEditBoxSpeechMM: _lsndSpeechMM.Play(); break; case kidListenEditBoxFXMM: _lsndSfxMM.Play(); break; case kidListenEditBoxMidi: _lsndMidi.Play(); break; default: Bug("Invalid Vlm type"); break; } return fTrue; } /*************************************************************************** Make the changes to _pscen or _pactr. For actor sounds, we could create an undo object here, but we currently don't. Scene sounds would require a new type of undo object so that's definitely not supported. ***************************************************************************/ bool ESLL::_FAcceptChanges(bool *pfDismissEasel) { AssertThis(0); AssertVarMem(pfDismissEasel); long vlmNew; bool fNuked; if (pvNil == _pactr) { // Scene sounds if (_lsndSpeech.FChanged(&vlmNew, &fNuked)) { if (fNuked) _pscen->RemSndCore(stySpeech); else _pscen->SetSndVlmCore(stySpeech, vlmNew); } if (_lsndSfx.FChanged(&vlmNew, &fNuked)) { if (fNuked) _pscen->RemSndCore(stySfx); else _pscen->SetSndVlmCore(stySfx, vlmNew); } if (_lsndMidi.FChanged(&vlmNew, &fNuked)) { if (fNuked) _pscen->RemSndCore(styMidi); else _pscen->SetSndVlmCore(styMidi, vlmNew); } } else { // Actor sounds if (_lsndSpeech.FChanged(&vlmNew, &fNuked)) { if (fNuked) { if (!_pactr->FDeleteSndCore(stySpeech, fFalse)) return fFalse; } else { if (!_pactr->FSetVlmSnd(stySpeech, fFalse, vlmNew)) return fFalse; } } if (_lsndSfx.FChanged(&vlmNew, &fNuked)) { if (fNuked) { if (!_pactr->FDeleteSndCore(stySfx, fFalse)) return fFalse; } else { if (!_pactr->FSetVlmSnd(stySfx, fFalse, vlmNew)) return fFalse; } } if (_lsndSpeechMM.FChanged(&vlmNew, &fNuked)) { if (fNuked) { if (!_pactr->FDeleteSndCore(stySpeech, fTrue)) return fFalse; } else { if (!_pactr->FSetVlmSnd(stySpeech, fTrue, vlmNew)) return fFalse; } } if (_lsndSfxMM.FChanged(&vlmNew, &fNuked)) { if (fNuked) { if (!_pactr->FDeleteSndCore(stySfx, fTrue)) return fFalse; } else { if (!_pactr->FSetVlmSnd(stySfx, fTrue, vlmNew)) return fFalse; } } } _pmvie->ClearUndo(); return fTrue; } #ifdef DEBUG /*************************************************************************** Assert the validity of the ESLL. ***************************************************************************/ void ESLL::AssertValid(ulong grf) { ESLL_PAR::AssertValid(fobjAllocated); } /*************************************************************************** Mark memory used by the ESLL ***************************************************************************/ void ESLL::MarkMem(void) { AssertThis(0); ESLL_PAR::MarkMem(); MarkMemObj(&_lsndSpeech); MarkMemObj(&_lsndSfx); MarkMemObj(&_lsndSpeechMM); MarkMemObj(&_lsndSfxMM); MarkMemObj(&_lsndMidi); } #endif //DEBUG // // // LSND (Listener Sound) stuff begins here // // /*************************************************************************** Initialize a LSND. Note that the LSND takes over the reference to *ppgltag. ***************************************************************************/ bool LSND::FInit(long sty, long kidVol, long kidIcon, long kidEditBox, PGL *ppgltag, long vlm, bool fLoop, long objID, bool fMatcher) { AssertBaseThis(0); AssertIn(sty, 0, styLim); AssertNilOrPo(*ppgltag, 0); long st; PGOK pgok; PTGOB ptgob; PMSND pmsnd; long itag; TAG tag; _sty = sty; _kidVol = kidVol; _kidIcon = kidIcon; _kidEditBox = kidEditBox; _pgltag = *ppgltag; *ppgltag = pvNil; _vlm = vlm; _vlmNew = vlm; _fLoop = fLoop; _objID = objID; _fMatcher = fMatcher; if (pvNil == _pgltag || 0 == _pgltag->IvMac()) return fTrue; // Set button state based on the tool if (_pgltag == pvNil || _pgltag->IvMac() == 0) st = kstListenDisabled; else if (_fMatcher) st = kstListenMatcher; else if (_pgltag->IvMac() > 1) st = kstListenSounderChain; else if (_fLoop) st = kstListenLooper; else st = kstListenSounder; // Create the TGOB to display the sound name // Search until a valid (not deleted) msnd is found for(itag = 0; itag < _pgltag->IvMac(); itag++) { _pgltag->Get(itag, &tag); pmsnd = (PMSND)vptagm->PbacoFetch(&tag, MSND::FReadMsnd); if (pvNil == pmsnd) return fFalse; if (!pmsnd->FValid()) { ReleasePpo(&pmsnd); continue; } ptgob = TGOB::PtgobCreate(kidEditBox, idsListenFont, tavCenter); if (pvNil == ptgob) { Warn("missing edit box"); ReleasePpo(&pmsnd); return fFalse; } ptgob->SetText(pmsnd->Pstn()); ReleasePpo(&pmsnd); goto LFound; } // No valid msnd -> no UI change required return fTrue; LFound: // Update the slider volume vpcex->EnqueueCid(cidListenVolSet, vpapp->Pkwa()->PgobFromHid(kidVol), pvNil, _vlm); pgok = (PGOK)vpapp->Pkwa()->PgobFromHid(kidIcon); if ((pgok != pvNil) && pgok->FIs(kclsGOK)) pgok->FChangeState(st); return fTrue; } /*************************************************************************** Play the LSND's sound ***************************************************************************/ void LSND::Play(void) { AssertThis(0); long itag; TAG tag; PMSND pmsnd; if (pvNil == _pgltag || _pgltag->IvMac() == 0) return; // nothing to play if (_vlmNew < 0) return; // don't play nuked sounds // Stop sounds that are already playing. This handles, among other // things, a problem that would otherwise occur when changing the // volume of a MIDI sound. Normally, MSND doesn't restart a MIDI // sound that's currently playing, but we want to force it to // restart here. StopAllMovieSounds(); for (itag = 0; itag < _pgltag->IvMac(); itag++) { _pgltag->Get(itag, &tag); // Verify sound before including in the event list pmsnd = (PMSND)vptagm->PbacoFetch(&tag, MSND::FReadMsnd); if (pvNil == pmsnd) continue; // ignore failure Assert(pmsnd->Sty() == _sty, 0); pmsnd->Play(_objID, _fLoop, (itag > 0), _vlmNew, 1, fTrue); ReleasePpo(&pmsnd); } } /*************************************************************************** Return whether the LSND has changed. Specifies new volume and whether the sound was nuked. ***************************************************************************/ bool LSND::FChanged(long *pvlmNew, bool *pfNuked) { AssertThis(0); AssertVarMem(pvlmNew); AssertVarMem(pfNuked); *pfNuked = (_vlmNew < 0); *pvlmNew = _vlmNew; return (_pgltag != pvNil && _pgltag->IvMac() > 0 && _vlm != _vlmNew); } /*************************************************************************** Destroy a LSND ***************************************************************************/ LSND::~LSND(void) { AssertBaseThis(0); ReleasePpo(&_pgltag); } #ifdef DEBUG /*************************************************************************** Assert the validity of the LSND. ***************************************************************************/ void LSND::AssertValid(ulong grf) { LSND_PAR::AssertValid(0); AssertNilOrPo(_pgltag, 0); } /*************************************************************************** Mark memory used by the LSND ***************************************************************************/ void LSND::MarkMem(void) { AssertThis(0); LSND_PAR::MarkMem(); MarkMemObj(_pgltag); } #endif //DEBUG // // // ESLR (Sound recording easel) stuff begins here // // BEGIN_CMD_MAP(ESLR, ESL) ON_CID_GEN(cidEaselRecord, FCmdRecord, pvNil) ON_CID_GEN(cidEaselPlay, FCmdPlay, pvNil) ON_CID_GEN(cidAlarm, FCmdUpdateMeter, pvNil) END_CMD_MAP_NIL() /*************************************************************************** Create a new sound recording easel ***************************************************************************/ PESLR ESLR::PeslrNew(PRCA prca, PMVIE pmvie, bool fSpeech, PSTN pstnNew) { AssertPo(prca, 0); AssertPo(pmvie, 0); AssertPo(pstnNew, 0); PESLR peslr; GCB gcb; if (!FBuildGcb(&gcb, kidBackground, kidRecordGlass)) return pvNil; peslr = NewObj ESLR(&gcb); if (pvNil == peslr) return pvNil; if (!peslr->_FInit(prca, kidRecordGlass, pmvie, fSpeech, pstnNew)) { ReleasePpo(&peslr); return pvNil; } AssertPo(peslr, 0); vpcex->EnqueueCid(cidEaselVisible); return peslr; } /*************************************************************************** Set up this easel ***************************************************************************/ bool ESLR::_FInit(PRCA prca, long kidEasel, PMVIE pmvie, bool fSpeech, PSTN pstnNew) { AssertBaseThis(0); AssertPo(prca, 0); AssertPo(pmvie, 0); AssertPo(pstnNew, 0); GCB gcb; EDPAR edpar; _pmvie = pmvie; _fSpeech = fSpeech; if (!ESLR_PAR::_FInit(prca, kidEasel)) return fFalse; if (!FBuildGcb(&gcb, kidRecordSoundName, CMH::HidUnique())) return fFalse; edpar.Set(gcb._hid, gcb._pgob, gcb._grfgob, gcb._gin, &gcb._rcAbs, &gcb._rcRel, vpappb->OnnDefVariable(), 0, vpappb->DypTextDef(), tahLeft, tavCenter); _pedsl = EDSL::PedslNew(&edpar); if (pvNil == _pedsl) return fFalse; _pedsl->SetStn(pstnNew, fFalse); _pedsl->SetSel(0, _pedsl->IchMac(), fFalse); // select all of the text _pedsl->Activate(fTrue); _pedsl->SetCursCno(prca, kcrsIBeam); // added loop around psrecNew to drop sample rate until it worked // to work around Win95 SB16 bug. (Tom Laird-McConnell) csampSec = kcsampSec; do { _psrec = SREC::PsrecNew(csampSec, 1, 1, kdtsMaxRecord); // if we failed, then the pointer is nil if (pvNil == _psrec) { // then downgrade the samples per second to next level csampSec >>= 1; } // until it succeeds, or the sample rate drops below 11025. } while ((pvNil == _psrec) && (csampSec >= 11025)); // if we still failed if (pvNil == _psrec) { PushErc(ercSndamWaveDeviceBusy); return fFalse; } _clok.Start(0); // Set sound meter to 0 PGOK pgok = (PGOK)vpapp->Pkwa()->PgobFromHid(kidRecordSoundLength); if (pvNil != pgok) vpcex->EnqueueCid(cidRecordSetLength, pgok, 0, 0, 0, 0, 0); return fTrue; } /*************************************************************************** Clean up and delete this easel ***************************************************************************/ ESLR::~ESLR(void) { AssertBaseThis(0); ReleasePpo(&_psrec); } /*************************************************************************** Update the meter that shows how long we've been recording. ***************************************************************************/ void ESLR::_UpdateMeter(void) { AssertThis(0); PGOK pgok; long dtsRec; long percentDone; // no good hungarian for a percent if (_fRecording) { dtsRec = TsCurrent() - _tsStartRec; percentDone = LwMulDiv(dtsRec, 100, kdtsMaxRecord); percentDone = LwBound(percentDone, 0, 100); pgok = (PGOK)vpapp->Pkwa()->PgobFromHid(kidRecordSoundLength); if (pvNil != pgok) vpcex->EnqueueCid(cidRecordSetLength, pgok, 0, percentDone, 0, 0, 0); else Bug("where's the sound length gok?"); } } /*************************************************************************** Start or stop recording ***************************************************************************/ bool ESLR::FCmdRecord(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); if (!_fRecording) { if (_psrec->FStart()) { _tsStartRec = TsCurrent(); _fRecording = fTrue; if (!_clok.FSetAlarm(0, this)) return fFalse; } else { SetGokState(kidRecordRecord, kstDefault); // pop out rec button _fRecording = fFalse; _UpdateMeter(); PushErc(ercSndamWaveDeviceBusy); return fFalse; } } else { if (_psrec->FStop()) { SetGokState(kidRecordRecord, kstDefault); // pop out rec button _fRecording = fFalse; _UpdateMeter(); } } return fTrue; } /*************************************************************************** Time to update the meter that shows how long we've been recording. ***************************************************************************/ bool ESLR::FCmdUpdateMeter(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); bool fRecordingOld = _fRecording; bool fPlayingOld = _fPlaying; _UpdateMeter(); _fRecording = _psrec->FRecording(); _fPlaying = _psrec->FPlaying(); if (fRecordingOld && !_fRecording) { SetGokState(kidRecordRecord, kstDefault); // pop out rec button _UpdateMeter(); } if (fPlayingOld && !_fPlaying) SetGokState(kidRecordPlay, kstDefault); // pop out play button if (_fRecording || _fPlaying) _clok.FSetAlarm(kdtimMeterUpdate, this); return fTrue; } /*************************************************************************** Play the sound that was recorded ***************************************************************************/ bool ESLR::FCmdPlay(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); if (_fRecording) { // try to stop recording if (_psrec->FStop()) { SetGokState(kidRecordRecord, kstDefault); // pop out rec button _fRecording = fFalse; _UpdateMeter(); } else { // We can't stop the recording, so set the record btn to its // selected state. (Script had popped the record btn out as // soon as the play button was selected). SetGokState(kidRecordRecord, kstSelected); // pop in rec button } } if (!_fRecording && _psrec->FHaveSound()) { if (!_fPlaying) { if (_psrec->FPlay()) { _fPlaying = fTrue; if (!_clok.FSetAlarm(0, this)) return fFalse; } } else { if (_psrec->FStop()) { _fPlaying = fFalse; SetGokState(kidRecordPlay, kstDefault); // pop out play button } } } else { SetGokState(kidRecordPlay, kstDefault); // pop out play button } return fTrue; } /*************************************************************************** Save the new sound ***************************************************************************/ bool ESLR::_FAcceptChanges(bool *pfDismissEasel) { AssertThis(0); AssertVarMem(pfDismissEasel); FNI fni; STN stn; PFIL pfil = pvNil; CNO cno; long sty = _fSpeech ? stySpeech : stySfx; long kid = _fSpeech ? kidSpeechGlass : kidFXGlass; if (_psrec->FRecording()) { if (_psrec->FStop()) { SetGokState(kidRecordRecord, kstDefault); // pop out rec button _fRecording = fFalse; _UpdateMeter(); } } if (_psrec->FPlaying()) { if (_psrec->FStop()) { _fPlaying = fFalse; SetGokState(kidRecordPlay, kstDefault); // pop out play button } } if (!_psrec->FHaveSound()) return fTrue; // user didn't record anything, so don't do anything _pedsl->GetStn(&stn); // If the user did not specify a name for the recorded sound, then // display an error and keep the recording easel displayed. if (stn.Cch() == 0) { PushErc(ercSocNoSoundName); *pfDismissEasel = fFalse; return fTrue; } if (!fni.FGetTemp()) return fFalse; if (!_psrec->FSave(&fni)) return fFalse; pfil = FIL::PfilOpen(&fni, ffilNil); if (pvNil == pfil) goto LFail; if (!_pmvie->FCopySndFileToMvie(pfil, sty, &cno, &stn)) goto LFail; // Select the item, extend lists and hilite it vpcex->EnqueueCid(cidBrowserSelectThum, vpappb->PcmhFromHid(kid), pvNil, cno, ksidUseCrf, 1, 1); ReleasePpo(&pfil); if (!fni.FDelete()) Warn("Couldn't delete temp sound file"); return fTrue; LFail: ReleasePpo(&pfil); if (!fni.FDelete()) Warn("Couldn't delete temp sound file"); return fFalse; } #ifdef DEBUG /*************************************************************************** Assert the validity of the ESLR. ***************************************************************************/ void ESLR::AssertValid(ulong grf) { ESLL_PAR::AssertValid(fobjAllocated); AssertPo(_psrec, 0); } /*************************************************************************** Mark memory used by the ESLR ***************************************************************************/ void ESLR::MarkMem(void) { AssertThis(0); ESLL_PAR::MarkMem(); MarkMemObj(_psrec); } #endif //DEBUG