mirror of
https://github.com/microsoft/Microsoft-3D-Movie-Maker.git
synced 2024-11-14 15:35:06 +00:00
3565 lines
80 KiB
C++
3565 lines
80 KiB
C++
/* Copyright (c) Microsoft Corporation.
|
|
Licensed under the MIT License. */
|
|
|
|
/***************************************************************************
|
|
|
|
Chunky editor document management
|
|
|
|
***************************************************************************/
|
|
#include "ched.h"
|
|
ASSERTNAME
|
|
|
|
|
|
BEGIN_CMD_MAP(DCD, DDG)
|
|
ON_CID_GEN(cidAddChunk, &DCD::FCmdAddChunk, pvNil)
|
|
ON_CID_GEN(cidAddPicChunk, &DCD::FCmdAddPicChunk, pvNil)
|
|
ON_CID_GEN(cidAddMbmpChunk, &DCD::FCmdAddBitmapChunk, pvNil)
|
|
ON_CID_GEN(cidAddMaskChunk, &DCD::FCmdAddBitmapChunk, pvNil)
|
|
ON_CID_GEN(cidCompilePostScript, &DCD::FCmdImportScript, pvNil)
|
|
ON_CID_GEN(cidCompileInScript, &DCD::FCmdImportScript, pvNil)
|
|
ON_CID_GEN(cidTestScript, &DCD::FCmdTestScript, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidRunScriptCache, &DCD::FCmdTestScript, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidAddFileChunk, &DCD::FCmdAddFileChunk, pvNil)
|
|
ON_CID_GEN(cidAdoptChunk, &DCD::FCmdAdoptChunk, pvNil)
|
|
ON_CID_GEN(cidDeleteChunk, &DCD::FCmdDeleteChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidUndeleteChunk, &DCD::FCmdDeleteChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidUnadoptChunk, &DCD::FCmdUnadoptChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidEditNatural, &DCD::FCmdEditChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidEditHex, &DCD::FCmdEditChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidEditGL, &DCD::FCmdEditChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidEditAL, &DCD::FCmdEditChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidEditGG, &DCD::FCmdEditChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidEditAG, &DCD::FCmdEditChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidEditGST, &DCD::FCmdEditChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidEditAST, &DCD::FCmdEditChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidEditPic, &DCD::FCmdEditChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidEditMbmp, &DCD::FCmdEditChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidPlaySound, &DCD::FCmdEditChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidStopSound, &DCD::FCmdStopSound, pvNil)
|
|
ON_CID_GEN(cidDisassembleScript, &DCD::FCmdDisasmScript, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidEditChunkInfo, &DCD::FCmdEditChunkInfo, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidChangeChid, &DCD::FCmdChangeChid, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidSetColorTable, &DCD::FCmdSetColorTable, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidFilterChunk, &DCD::FCmdFilterChunk, pvNil)
|
|
ON_CID_GEN(cidPack, &DCD::FCmdPack, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidTogglePack, &DCD::FCmdPack, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidCloneChunk, &DCD::FCmdCloneChunk, &DCD::FEnableDcdCmd)
|
|
ON_CID_GEN(cidReopen, &DCD::FCmdReopen, pvNil)
|
|
END_CMD_MAP_NIL()
|
|
|
|
|
|
BEGIN_CMD_MAP(TSCG, GOB)
|
|
ON_CID_GEN(cidClose, &GOB::FCmdCloseWnd, pvNil)
|
|
END_CMD_MAP_NIL()
|
|
|
|
|
|
bool _FGetCtg(PDLG pdlg, long idit, CTG *pctg);
|
|
void _PutCtgStn(PDLG pdlg, long idit, CTG ctg);
|
|
|
|
RTCLASS(DOC)
|
|
RTCLASS(DOCE)
|
|
RTCLASS(DCLB)
|
|
RTCLASS(DCD)
|
|
RTCLASS(SEL)
|
|
RTCLASS(TSCG)
|
|
|
|
|
|
/****************************************
|
|
Add Chunk dialog
|
|
****************************************/
|
|
enum
|
|
{
|
|
kiditOkInfo,
|
|
kiditCancelInfo,
|
|
kiditCtgInfo,
|
|
kiditCnoInfo,
|
|
kiditNameInfo,
|
|
kiditLimInfo
|
|
};
|
|
|
|
//add chunk data
|
|
struct ADCD
|
|
{
|
|
PCFL pcfl;
|
|
bool fCkiValid;
|
|
CKI cki;
|
|
};
|
|
|
|
bool _FDlgAddChunk(PDLG pdlg, long *pidit, void *pv);
|
|
|
|
|
|
/***************************************************************************
|
|
Dialog proc for Add Chunk dialog. pv should be a padcd.
|
|
***************************************************************************/
|
|
bool _FDlgAddChunk(PDLG pdlg, long *pidit, void *pv)
|
|
{
|
|
AssertPo(pdlg, 0);
|
|
AssertVarMem(pidit);
|
|
CTG ctg;
|
|
long lw;
|
|
bool fEmpty;
|
|
ADCD *padcd = (ADCD *)pv;
|
|
|
|
switch (*pidit)
|
|
{
|
|
case kiditCancelInfo:
|
|
return fTrue; //dismiss the dialog
|
|
|
|
case kiditOkInfo:
|
|
if (!pdlg->FGetValues(0, kiditLimInfo))
|
|
{
|
|
*pidit = ivNil;
|
|
return fTrue;
|
|
}
|
|
if (!_FGetCtg(pdlg, kiditCtgInfo, &ctg))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("CTG is bad"), bkOk, cokStop);
|
|
pdlg->SelectDit(kiditCtgInfo);
|
|
return fFalse;
|
|
}
|
|
if (!pdlg->FGetLwFromEdit(kiditCnoInfo, &lw, &fEmpty) && !fEmpty)
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("CNO is bad"), bkOk, cokStop);
|
|
pdlg->SelectDit(kiditCnoInfo);
|
|
return fFalse;
|
|
}
|
|
AssertPo(padcd->pcfl, 0);
|
|
if (!fEmpty && (!padcd->fCkiValid || ctg != padcd->cki.ctg ||
|
|
lw != (long)padcd->cki.cno) &&
|
|
padcd->pcfl->FFind(ctg, lw))
|
|
{
|
|
bool tRet = vpappb->TGiveAlertSz(PszLit("A chunk with this CTG & CNO")
|
|
PszLit(" already exists. Replace the existing chunk?"),
|
|
bkYesNoCancel, cokQuestion);
|
|
|
|
switch (tRet)
|
|
{
|
|
case tMaybe:
|
|
*pidit = kiditCancelInfo;
|
|
return fTrue;
|
|
|
|
case tNo:
|
|
pdlg->SelectDit(kiditCnoInfo);
|
|
return fFalse;
|
|
}
|
|
}
|
|
return fTrue;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Constructor for DOC class.
|
|
***************************************************************************/
|
|
DOC::DOC(void)
|
|
{
|
|
_pcfl = pvNil;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Destructor for DOC class.
|
|
***************************************************************************/
|
|
DOC::~DOC(void)
|
|
{
|
|
ReleasePpo(&_pcfl);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to create a new document based on the given fni.
|
|
Use pfni == pvNil to create a new file, non-nil to open an
|
|
existing file.
|
|
***************************************************************************/
|
|
PDOC DOC::PdocNew(FNI *pfni)
|
|
{
|
|
PCFL pcfl;
|
|
PDOC pdoc;
|
|
|
|
if (pvNil == pfni)
|
|
pcfl = CFL::PcflCreateTemp();
|
|
else
|
|
{
|
|
AssertPo(pfni, ffniFile);
|
|
|
|
//make sure no other docs are based on this pcfl.
|
|
if (pvNil != DOCB::PdocbFromFni(pfni))
|
|
return pvNil;
|
|
pcfl = CFL::PcflOpen(pfni, fcflNil);
|
|
}
|
|
|
|
if (pvNil == pcfl)
|
|
return pvNil;
|
|
|
|
if (pvNil == (pdoc = NewObj DOC()))
|
|
{
|
|
ReleasePpo(&pcfl);
|
|
return pvNil;
|
|
}
|
|
|
|
pdoc->_pcfl = pcfl;
|
|
AssertPo(pdoc, 0);
|
|
return pdoc;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Create a new DDG for the doc.
|
|
***************************************************************************/
|
|
PDDG DOC::PddgNew(PGCB pgcb)
|
|
{
|
|
AssertThis(0);
|
|
return DCD::PdcdNew(this, _pcfl, pgcb);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the current FNI for the doc. Return false if the doc is not
|
|
currently based on an FNI (it's a new doc or an internal one).
|
|
***************************************************************************/
|
|
bool DOC::FGetFni(FNI *pfni)
|
|
{
|
|
AssertThis(0);
|
|
AssertBasePo(pfni, 0);
|
|
if (_pcfl->FTemp())
|
|
return fFalse;
|
|
|
|
_pcfl->GetFni(pfni);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Save the document and optionally set this fni as the current one.
|
|
If the doc is currently based on an FNI, pfni may be nil, indicating
|
|
that this is a normal save (not save as). If pfni is not nil and
|
|
fSetFni is false, this just writes a copy of the doc but doesn't change
|
|
the doc one bit.
|
|
***************************************************************************/
|
|
bool DOC::FSaveToFni(FNI *pfni, bool fSetFni)
|
|
{
|
|
AssertThis(0);
|
|
if (!fSetFni && pvNil != pfni)
|
|
{
|
|
if (!_pcfl->FSaveACopy(kctgChed, pfni))
|
|
goto LFail;
|
|
return fTrue;
|
|
}
|
|
|
|
if (!_pcfl->FSave(kctgChed, pfni))
|
|
{
|
|
LFail:
|
|
vpappb->TGiveAlertSz(PszLit("Saving chunky file failed!"),
|
|
bkOk, cokExclamation);
|
|
return fFalse;
|
|
}
|
|
|
|
_fDirty = fFalse;
|
|
_pcfl->SetTemp(fFalse);
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Ask the user what file they want to save to.
|
|
***************************************************************************/
|
|
bool DOC::FGetFniSave(FNI *pfni)
|
|
{
|
|
AssertThis(0);
|
|
return FGetFniSaveMacro(pfni, 'CHN2', "\x9" "Save As: ", "",
|
|
PszLit("All files\0*.*\0"), vwig.hwndApp);
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Assert the validity of the DOC.
|
|
***************************************************************************/
|
|
void DOC::AssertValid(ulong grf)
|
|
{
|
|
DOC_PAR::AssertValid(grf);
|
|
AssertPo(_pcfl, 0);
|
|
}
|
|
#endif //DEBUG
|
|
|
|
|
|
/***************************************************************************
|
|
Constructor for chunk editing doc.
|
|
***************************************************************************/
|
|
DOCE::DOCE(PDOCB pdocb, PCFL pcfl, CTG ctg, CNO cno) : DOCB(pdocb)
|
|
{
|
|
_pcfl = pcfl;
|
|
_ctg = ctg;
|
|
_cno = cno;
|
|
AssertThis(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Initialize the DOCH - initialize the stream.
|
|
***************************************************************************/
|
|
bool DOCE::_FInit(void)
|
|
{
|
|
BLCK blck;
|
|
|
|
if (!_pcfl->FFind(_ctg, _cno, &blck))
|
|
{
|
|
Bug("Chunk not found");
|
|
return fFalse;
|
|
}
|
|
if (!_FRead(&blck))
|
|
return fFalse;
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to look for a DOCE for the given chunk.
|
|
***************************************************************************/
|
|
PDOCE DOCE::PdoceFromChunk(PDOCB pdocb, PCFL pcfl, CTG ctg, CNO cno)
|
|
{
|
|
PDOCE pdoce;
|
|
|
|
for (pdocb = pdocb->PdocbChd(); pvNil != pdocb; pdocb = pdocb->PdocbSib())
|
|
{
|
|
if (!pdocb->FIs(kclsDOCE))
|
|
continue;
|
|
pdoce = (PDOCE)pdocb;
|
|
AssertPo(pdoce, 0);
|
|
if (pdoce->_pcfl == pcfl && pdoce->_ctg == ctg && pdoce->_cno == cno)
|
|
return pdoce;
|
|
}
|
|
return pvNil;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method: For all DOCE children of the DOCB, checks if the chunk
|
|
still exists and nukes the DOCE if not.
|
|
***************************************************************************/
|
|
void DOCE::CloseDeletedDoce(PDOCB pdocb)
|
|
{
|
|
PDOCB pdocbNext;
|
|
PDOCE pdoce;
|
|
|
|
for (pdocb = pdocb->PdocbChd(); pvNil != pdocb; pdocb = pdocbNext)
|
|
{
|
|
pdocbNext = pdocb->PdocbSib();
|
|
if (!pdocb->FIs(kclsDOCE))
|
|
continue;
|
|
pdoce = (PDOCE)pdocb;
|
|
//NOTE: can't assert the pdoce here because the chunk may be gone
|
|
//AssertPo(pdoce, 0);
|
|
AssertPo(pdoce->_pcfl, 0);
|
|
if (!pdoce->_pcfl->FFind(pdoce->_ctg, pdoce->_cno))
|
|
pdoce->CloseAllDdg();
|
|
else
|
|
AssertPo(pdoce, 0);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the name of the item document.
|
|
***************************************************************************/
|
|
void DOCE::GetName(PSTN pstn)
|
|
{
|
|
AssertThis(0);
|
|
STN stn;
|
|
|
|
stn.FFormatSz(PszLit(": %f %08x"), _ctg, _cno);
|
|
_pdocbPar->GetName(pstn);
|
|
pstn->FAppendStn(&stn);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Save the document. Handles cidSave, cidSaveAs and cidSaveCopy.
|
|
***************************************************************************/
|
|
bool DOCE::FSave(long cid)
|
|
{
|
|
AssertThis(0);
|
|
CTG ctg;
|
|
CNO cno;
|
|
bool fCreated = fFalse;
|
|
PDLG pdlg = pvNil;
|
|
|
|
switch (cid)
|
|
{
|
|
case cidSave:
|
|
ctg = _ctg;
|
|
cno = _cno;
|
|
break;
|
|
|
|
case cidSaveAs:
|
|
case cidSaveCopy:
|
|
long idit;
|
|
long lw;
|
|
ADCD adcd;
|
|
|
|
//put up the dialog
|
|
adcd.pcfl = _pcfl;
|
|
adcd.fCkiValid = fTrue;
|
|
adcd.cki.ctg = _ctg;
|
|
adcd.cki.cno = _cno;
|
|
pdlg = DLG::PdlgNew(dlidChunkInfo, _FDlgAddChunk, &adcd);
|
|
if (pvNil == pdlg)
|
|
goto LCancel;
|
|
_PutCtgStn(pdlg, kiditCtgInfo, _ctg);
|
|
idit = kiditCnoInfo;
|
|
idit = pdlg->IditDo(idit);
|
|
if (idit != kiditOkInfo)
|
|
goto LCancel;
|
|
|
|
if (!_FGetCtg(pdlg, kiditCtgInfo, &ctg) ||
|
|
!pdlg->FGetLwFromEdit(kiditCnoInfo, &lw, &fCreated) &&
|
|
!fCreated)
|
|
{
|
|
goto LFail;
|
|
}
|
|
ReleasePpo(&pdlg);
|
|
cno = lw;
|
|
|
|
if (fCreated)
|
|
{
|
|
if (!_pcfl->FAdd(0, ctg, &cno))
|
|
goto LFail;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return fFalse;
|
|
}
|
|
|
|
if (_FSaveToChunk(ctg, cno, cid != cidSaveCopy))
|
|
{
|
|
PDOCB pdocb;
|
|
PDDG pddg;
|
|
|
|
if (pvNil != (pdocb = PdocbPar()) && pvNil != (pddg = pdocb->PddgGet(0)) &&
|
|
pddg->FIs(kclsDCD))
|
|
{
|
|
((PDCD)pddg)->InvalAllDcd(pdocb, _pcfl);
|
|
}
|
|
if (cid != cidSaveCopy)
|
|
UpdateName();
|
|
return fTrue;
|
|
}
|
|
|
|
//saving failed
|
|
if (fCreated)
|
|
_pcfl->Delete(ctg, cno);
|
|
|
|
LFail:
|
|
vpappb->TGiveAlertSz(PszLit("Saving chunk failed"), bkOk, cokExclamation);
|
|
LCancel:
|
|
ReleasePpo(&pdlg);
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Save the chunk data to a chunk.
|
|
***************************************************************************/
|
|
bool DOCE::_FSaveToChunk(CTG ctg, CNO cno, bool fRedirect)
|
|
{
|
|
AssertThis(0);
|
|
CNO cnoT;
|
|
CKI cki;
|
|
BLCK blck;
|
|
long cb = _CbOnFile();
|
|
|
|
//if the chunk already exists, add a temporary chunk, swap the data
|
|
//between the two chunks, then delete the temporary chunk.
|
|
//if the chunk doesn't yet exist, create it.
|
|
if (!_pcfl->FFind(ctg, cno))
|
|
{
|
|
cnoT = cno;
|
|
if (!_pcfl->FPut(cb, ctg, cno, &blck))
|
|
return fFalse;
|
|
}
|
|
else if (!_pcfl->FAdd(cb, ctg, &cnoT, &blck))
|
|
return fFalse;
|
|
|
|
if (!_FWrite(&blck, fRedirect))
|
|
{
|
|
_pcfl->Delete(ctg, cnoT);
|
|
return fFalse;
|
|
}
|
|
|
|
if (cno != cnoT)
|
|
{
|
|
_pcfl->SwapData(ctg, cno, ctg, cnoT);
|
|
_pcfl->Delete(ctg, cnoT);
|
|
}
|
|
|
|
if (fRedirect)
|
|
{
|
|
_ctg = ctg;
|
|
_cno = cno;
|
|
_fDirty = fFalse;
|
|
}
|
|
|
|
//need to invalidate the line
|
|
cki.ctg = ctg;
|
|
cki.cno = cno;
|
|
DCD::InvalAllDcd(_pdocbPar, _pcfl, &cki);
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Assert the validity of an object.
|
|
***************************************************************************/
|
|
void DOCE::AssertValid(ulong grf)
|
|
{
|
|
DOCE_PAR::AssertValid(0);
|
|
AssertPo(_pcfl, 0);
|
|
Assert(_pcfl->FFind(_ctg, _cno), "chunk not in CFL");
|
|
}
|
|
#endif //DEBUG
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
Constructor for a DCLB.
|
|
***************************************************************************/
|
|
DCLB::DCLB(PDOCB pdocb, PGCB pgcb) : DDG(pdocb, pgcb)
|
|
{
|
|
achar ch;
|
|
RC rc;
|
|
GNV gnv(this);
|
|
|
|
_dypHeader = 0;
|
|
_onn = vpappb->OnnDefFixed();
|
|
gnv.SetOnn(_onn);
|
|
ch = 'A';
|
|
gnv.GetRcFromRgch(&rc, &ch, 1, 0, 0);
|
|
_dypLine = rc.Dyp();
|
|
_dxpChar = rc.Dxp();
|
|
AssertThis(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return the ln that corresponds with the given yp value. If yp is in
|
|
the header, returns lnNil.
|
|
***************************************************************************/
|
|
long DCLB::_LnFromYp(long yp)
|
|
{
|
|
AssertThis(0);
|
|
if (yp < _dypHeader)
|
|
return lnNil;
|
|
return _scvVert + (yp - _dypHeader) / _dypLine;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Perform a scroll according to scaHorz and scaVert.
|
|
***************************************************************************/
|
|
void DCLB::_Scroll(long scaHorz, long scaVert, long scvHorz, long scvVert)
|
|
{
|
|
AssertThis(0);
|
|
RC rc;
|
|
long dscvHorz, dscvVert;
|
|
long dxp, dyp;
|
|
|
|
_GetContent(&rc);
|
|
dscvHorz = dscvVert = 0;
|
|
dxp = 0;
|
|
switch (scaHorz)
|
|
{
|
|
case scaPageUp:
|
|
dscvHorz = -LwMax(1, LwMulDiv(rc.Dxp(), 9, 10) / _dxpChar);
|
|
goto LHorz;
|
|
case scaPageDown:
|
|
dscvHorz = LwMax(1, LwMulDiv(rc.Dxp(), 9, 10) / _dxpChar);
|
|
goto LHorz;
|
|
case scaLineUp:
|
|
dscvHorz = -LwMax(1, rc.Dxp() / 10 / _dxpChar);
|
|
goto LHorz;
|
|
case scaLineDown:
|
|
dscvHorz = LwMax(1, rc.Dxp() / 10 / _dxpChar);
|
|
goto LHorz;
|
|
case scaToVal:
|
|
dscvHorz = scvHorz - _scvHorz;
|
|
LHorz:
|
|
dscvHorz = LwBound(_scvHorz + dscvHorz, 0, _ScvMax(fFalse) + 1) - _scvHorz;
|
|
_scvHorz += dscvHorz;
|
|
dxp = LwMul(dscvHorz, _dxpChar);
|
|
break;
|
|
}
|
|
|
|
dyp = 0;
|
|
switch (scaVert)
|
|
{
|
|
case scaPageUp:
|
|
dscvVert = -LwMax(1, rc.Dyp() / _dypLine - 1);
|
|
goto LVert;
|
|
case scaPageDown:
|
|
dscvVert = LwMax(1, rc.Dyp() / _dypLine - 1);
|
|
goto LVert;
|
|
case scaLineUp:
|
|
dscvVert = -1;
|
|
goto LVert;
|
|
case scaLineDown:
|
|
dscvVert = 1;
|
|
goto LVert;
|
|
case scaToVal:
|
|
dscvVert = scvVert - _scvVert;
|
|
LVert:
|
|
dscvVert = LwBound(_scvVert + dscvVert, 0, _ScvMax(fTrue) + 1) - _scvVert;
|
|
_scvVert += dscvVert;
|
|
dyp = LwMul(dscvVert, _dypLine);
|
|
break;
|
|
}
|
|
|
|
_SetScrollValues();
|
|
if (dxp != 0 || dyp != 0)
|
|
_ScrollDxpDyp(dxp, dyp);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Move the bits in the window.
|
|
***************************************************************************/
|
|
void DCLB::_ScrollDxpDyp(long dxp, long dyp)
|
|
{
|
|
AssertThis(0);
|
|
RC rc;
|
|
|
|
_GetContent(&rc);
|
|
Scroll(&rc, -dxp, -dyp, kginDraw);
|
|
if (0 != dxp)
|
|
{
|
|
//scroll the header
|
|
rc.ypTop = 0;
|
|
rc.ypBottom = _dypHeader - 1;
|
|
Scroll(&rc, -dxp, 0, kginDraw);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the content part of the DCLB minus header (and any future footer).
|
|
***************************************************************************/
|
|
void DCLB::_GetContent(RC *prc)
|
|
{
|
|
GetRc(prc, cooLocal);
|
|
prc->ypTop += _dypHeader;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Fill in reasonable minimum and maximum sizes.
|
|
***************************************************************************/
|
|
void DCLB::GetMinMax(RC *prcMinMax)
|
|
{
|
|
prcMinMax->xpLeft = 20 * _dxpChar;
|
|
prcMinMax->ypTop = _dypHeader + 2 * _dypLine;
|
|
prcMinMax->xpRight = kswMax;
|
|
prcMinMax->ypBottom = kswMax;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Assert the validity of an object.
|
|
***************************************************************************/
|
|
void DCLB::AssertValid(ulong grf)
|
|
{
|
|
DCLB_PAR::AssertValid(0);
|
|
AssertIn(_dypLine, 1, 1000);
|
|
AssertIn(_dxpChar, 1, 1000);
|
|
AssertIn(_dypHeader, 0, 1000);
|
|
}
|
|
#endif //DEBUG
|
|
|
|
|
|
/***************************************************************************
|
|
Constructor for the DCD.
|
|
***************************************************************************/
|
|
DCD::DCD(PDOCB pdocb, PCFL pcfl, PGCB pgcb) : DCLB(pdocb, pgcb), _sel(pcfl)
|
|
{
|
|
_pcfl = pcfl;
|
|
_dypBorder = 1;
|
|
_dypLine += _dypBorder;
|
|
_dypHeader = _dypLine;
|
|
AssertThis(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to create a new DCD.
|
|
***************************************************************************/
|
|
PDCD DCD::PdcdNew(PDOCB pdocb, PCFL pcfl, PGCB pgcb)
|
|
{
|
|
PDCD pdcd;
|
|
|
|
if (pvNil == (pdcd = NewObj DCD(pdocb, pcfl, pgcb)))
|
|
return pvNil;
|
|
|
|
if (!pdcd->_FInit())
|
|
{
|
|
ReleasePpo(&pdcd);
|
|
return pvNil;
|
|
}
|
|
pdcd->Activate(fTrue);
|
|
|
|
AssertPo(pdcd, 0);
|
|
return pdcd;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
We're being activated or deactivated, invert the sel.
|
|
***************************************************************************/
|
|
void DCD::_Activate(bool fActive)
|
|
{
|
|
AssertThis(0);
|
|
DDG::_Activate(fActive);
|
|
|
|
GNV gnv(this);
|
|
_DrawSel(&gnv);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method: should be called by any code that edits the pcfl.
|
|
*pcki and *pkid should be at or before the first line modified.
|
|
pcki and pkid can be nil.
|
|
***************************************************************************/
|
|
void DCD::InvalAllDcd(PDOCB pdocb, PCFL pcfl, CKI *pcki, KID *pkid)
|
|
{
|
|
AssertPo(pdocb, 0);
|
|
AssertPo(pcfl, 0);
|
|
AssertNilOrVarMem(pcki);
|
|
AssertNilOrVarMem(pkid);
|
|
long ipddg;
|
|
PDDG pddg;
|
|
PDCD pdcd;
|
|
|
|
//mark the document dirty
|
|
pdocb->SetDirty();
|
|
|
|
//inform the DCDs
|
|
for (ipddg = 0; pvNil != (pddg = pdocb->PddgGet(ipddg)); ipddg++)
|
|
{
|
|
if (!pddg->FIs(kclsDCD))
|
|
continue;
|
|
pdcd = (PDCD)pddg;
|
|
AssertPo(pdcd, 0);
|
|
if (pdcd->_pcfl == pcfl)
|
|
pdcd->_InvalCkiKid(pcki, pkid);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Invalidate the display from (pcki, pkid) to the end of the display. If
|
|
we're the active DCD, also redraw.
|
|
***************************************************************************/
|
|
void DCD::_InvalCkiKid(CKI *pcki, KID *pkid)
|
|
{
|
|
AssertThis(0);
|
|
AssertNilOrVarMem(pcki);
|
|
AssertNilOrVarMem(pkid);
|
|
RC rc;
|
|
long lnMin;
|
|
|
|
//we need to recalculate the lnLim
|
|
_sel.InvalLim();
|
|
|
|
if (pvNil != pcki)
|
|
{
|
|
SEL sel = _sel;
|
|
|
|
sel.FSetCkiKid(pcki, pkid, fFalse);
|
|
lnMin = sel.Ln();
|
|
}
|
|
else
|
|
lnMin = lnNil;
|
|
|
|
//correct the sel
|
|
if (lnNil != _sel.Ln() && _sel.Ln() >= lnMin)
|
|
_sel.Adjust();
|
|
|
|
GetRc(&rc, cooLocal);
|
|
rc.ypTop = LwMax(0, _YpFromLn(lnMin) - _dypBorder);
|
|
if (rc.FEmpty())
|
|
return;
|
|
|
|
if (_fActive)
|
|
{
|
|
ValidRc(&rc, kginDraw);
|
|
InvalRc(&rc, kginDraw);
|
|
}
|
|
else
|
|
InvalRc(&rc);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Draw the chunk list
|
|
***************************************************************************/
|
|
void DCD::Draw(PGNV pgnv, RC *prcClip)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pgnv, 0);
|
|
AssertVarMem(prcClip);
|
|
STN stn;
|
|
STN stnT;
|
|
RC rc;
|
|
long yp, xp;
|
|
long ikid, cckiRef;
|
|
CKI cki;
|
|
KID kid;
|
|
BLCK blck;
|
|
ulong grfsel;
|
|
SEL sel = _sel;
|
|
|
|
pgnv->ClipRc(prcClip);
|
|
pgnv->SetOnn(_onn);
|
|
|
|
xp = _XpFromIch(0);
|
|
//draw the header
|
|
rc = *prcClip;
|
|
rc.ypTop = 0;
|
|
rc.ypBottom = _dypHeader - _dypBorder;
|
|
pgnv->FillRc(&rc, kacrWhite);
|
|
stn.FFormatSz(
|
|
PszLit("LPF PARS SIZE (CHID) CTG CNO Name Lines: %d"),
|
|
_sel.LnLim());
|
|
pgnv->DrawStn(&stn, xp, 0);
|
|
rc = *prcClip;
|
|
rc.ypTop = _dypHeader - _dypBorder;
|
|
rc.ypBottom = _dypHeader;
|
|
pgnv->FillRc(&rc, kacrBlack);
|
|
|
|
//use the sel to find the first (icki, ikid) to draw
|
|
if (!sel.FSetLn(_LnFromYp(LwMax(prcClip->ypTop, _dypHeader))))
|
|
{
|
|
//no visible lines
|
|
rc = *prcClip;
|
|
rc.ypTop = _dypHeader;
|
|
pgnv->FillRc(&rc, kacrWhite);
|
|
return;
|
|
}
|
|
|
|
for (yp = _YpFromLn(sel.Ln()); yp < prcClip->ypBottom; )
|
|
{
|
|
if (sel.Ln() == lnNil)
|
|
{
|
|
rc = *prcClip;
|
|
rc.ypTop = yp;
|
|
pgnv->FillRc(&rc, kacrWhite);
|
|
break;
|
|
}
|
|
|
|
grfsel = sel.GrfselGetCkiKid(&cki, &kid);
|
|
rc = *prcClip;
|
|
rc.ypTop = yp;
|
|
rc.ypBottom = yp + _dypLine;
|
|
pgnv->FillRc(&rc, kacrWhite);
|
|
if (grfsel & fselKid)
|
|
{
|
|
stn.FFormatSz(PszLit(" %08x %f %08x"),
|
|
kid.chid, kid.cki.ctg, kid.cki.cno);
|
|
pgnv->DrawStn(&stn, xp, yp);
|
|
yp += _dypLine;
|
|
}
|
|
else
|
|
{
|
|
Assert(grfsel & fselCki, "bad grfsel");
|
|
|
|
//draw the cki description
|
|
_pcfl->FFind(cki.ctg, cki.cno, &blck);
|
|
_pcfl->FGetName(cki.ctg, cki.cno, &stnT);
|
|
cckiRef = _pcfl->CckiRef(cki.ctg, cki.cno);
|
|
ikid = _pcfl->Ckid(cki.ctg, cki.cno);
|
|
|
|
stn.FFormatSz(PszLit("%c%c%c %3d %08x -------- %f %08x \"%s\""),
|
|
_pcfl->FLoner(cki.ctg, cki.cno) ? ChLit('L') : ChLit(' '),
|
|
blck.FPacked() ? ChLit('P') : ChLit(' '),
|
|
_pcfl->FForest(cki.ctg, cki.cno) ? ChLit('F') : ChLit(' '),
|
|
cckiRef, blck.Cb(fTrue), cki.ctg, cki.cno, &stnT);
|
|
pgnv->DrawStn(&stn, xp, yp);
|
|
yp += _dypLine;
|
|
}
|
|
|
|
sel.FAdvance();
|
|
|
|
//draw seperating line
|
|
if (yp > _dypHeader)
|
|
{
|
|
rc = *prcClip;
|
|
rc.ypTop = yp - _dypBorder;
|
|
rc.ypBottom = yp;
|
|
pgnv->FillRc(&rc, (sel.Ikid() == ivNil) ? kacrGray : kacrWhite);
|
|
}
|
|
}
|
|
|
|
//draw the selection
|
|
if (_fActive)
|
|
_DrawSel(pgnv);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Hilite the selection (if there is one)
|
|
***************************************************************************/
|
|
void DCD::_DrawSel(PGNV pgnv)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pgnv, 0);
|
|
RC rc;
|
|
long ln;
|
|
|
|
if (lnNil == (ln = _sel.Ln()))
|
|
return;
|
|
|
|
pgnv->GetRcSrc(&rc);
|
|
rc.ypTop = _YpFromLn(ln);
|
|
rc.ypBottom = rc.ypTop + _dypLine - _dypBorder;
|
|
rc.ypTop = LwMax(rc.ypTop, _dypHeader);
|
|
pgnv->HiliteRc(&rc, kacrWhite);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Set the selection to the given ln.
|
|
***************************************************************************/
|
|
void DCD::_SetSel(long ln, CKI *pcki, KID *pkid)
|
|
{
|
|
AssertThis(0);
|
|
AssertNilOrVarMem(pcki);
|
|
AssertNilOrVarMem(pkid);
|
|
SEL sel = _sel;
|
|
|
|
if (pvNil != pcki)
|
|
{
|
|
Assert(lnNil == ln, "ln and pcki both not nil");
|
|
sel.FSetCkiKid(pcki, pkid);
|
|
}
|
|
else
|
|
{
|
|
Assert(pvNil == pkid, 0);
|
|
sel.FSetLn(ln);
|
|
}
|
|
|
|
if (_sel.Ln() == sel.Ln())
|
|
return;
|
|
|
|
GNV gnv(this);
|
|
|
|
//erase the old sel
|
|
if (_fActive)
|
|
_DrawSel(&gnv);
|
|
|
|
//set the new sel and draw it
|
|
_sel = sel;
|
|
if (_fActive)
|
|
_DrawSel(&gnv);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Scroll the sel into view.
|
|
***************************************************************************/
|
|
void DCD::_ShowSel(void)
|
|
{
|
|
AssertThis(0);
|
|
RC rc;
|
|
long ln, lnLim;
|
|
|
|
if (lnNil == (ln = _sel.Ln()))
|
|
_Scroll(scaNil, scaToVal, 0, _scvVert);
|
|
else if (ln < _scvVert)
|
|
_Scroll(scaNil, scaToVal, 0, ln);
|
|
else
|
|
{
|
|
_GetContent(&rc);
|
|
lnLim = LwMax(_scvVert + 1, _LnFromYp(rc.ypBottom));
|
|
if (ln >= lnLim)
|
|
_Scroll(scaNil, scaToVal, 0, _scvVert + ln + 1 - lnLim);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle a mouse down in our content.
|
|
***************************************************************************/
|
|
void DCD::MouseDown(long xp, long yp, long cact, ulong grfcust)
|
|
{
|
|
AssertThis(0);
|
|
PGOB pgob;
|
|
PDCD pdcd, pdcdNew;
|
|
PT pt, ptT;
|
|
bool fDown;
|
|
long ln, lnNew;
|
|
CKI cki, ckiNew;
|
|
KID kid;
|
|
ulong grfsel;
|
|
|
|
ln = _sel.Ln();
|
|
if (lnNil != (lnNew = _LnFromYp(yp)))
|
|
{
|
|
_SetSel(lnNew);
|
|
grfsel = _sel.GrfselGetCkiKid(&cki, &kid);
|
|
if ((grfsel & fselCki) && !(grfsel & fselKid))
|
|
{
|
|
kid.cki = cki;
|
|
kid.chid = 0;
|
|
}
|
|
lnNew = _sel.Ln();
|
|
}
|
|
|
|
if (!_fActive)
|
|
Activate(fTrue);
|
|
|
|
if (lnNil == lnNew)
|
|
return;
|
|
|
|
// handle a control/command click--edit chunk information/change CHID
|
|
if (grfcust & fcustCmd)
|
|
{
|
|
_SetSel(lnNil);
|
|
if (grfsel & fselKid)
|
|
{
|
|
if (_FChangeChid(&cki, &kid))
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
_SetSel(lnNil, &cki, &kid);
|
|
_ShowSel();
|
|
}
|
|
else
|
|
{
|
|
if (_FEditChunkInfo(&cki))
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
_SetSel(lnNil, &cki);
|
|
_ShowSel();
|
|
}
|
|
return;
|
|
}
|
|
|
|
// handle a double click - edit or goto the item
|
|
if (cact > 1 && ln == lnNew)
|
|
{
|
|
if (!(grfsel & fselKid))
|
|
_EditCki(&cki, cidEditNatural);
|
|
else
|
|
{
|
|
_SetSel(lnNil, &kid.cki);
|
|
_ShowSel();
|
|
}
|
|
return;
|
|
}
|
|
|
|
pt.xp = xp;
|
|
pt.yp = yp;
|
|
pdcd = pvNil;
|
|
ln = lnNil;
|
|
for (fDown = fTrue; fDown; GetPtMouse(&pt, &fDown))
|
|
{
|
|
ptT = pt;
|
|
MapPt(&ptT, cooLocal, cooGlobal);
|
|
pgob = GOB::PgobFromPtGlobal(ptT.xp, ptT.yp, &ptT);
|
|
if (pgob != this && (pvNil == pgob || !pgob->FIs(kclsDCD) ||
|
|
_pcfl != ((PDCD)pgob)->_pcfl))
|
|
{
|
|
pdcdNew = pvNil;
|
|
}
|
|
else
|
|
{
|
|
pdcdNew = (PDCD)pgob;
|
|
lnNew = pdcdNew->_LnFromYp(ptT.yp);
|
|
|
|
SEL sel = pdcdNew->_sel;
|
|
sel.FSetLn(lnNew);
|
|
grfsel = sel.GrfselGetCkiKid(&ckiNew, pvNil);
|
|
|
|
if (!(grfsel & fselCki) ||
|
|
tNo != _pcfl->TIsDescendent(kid.cki.ctg, kid.cki.cno,
|
|
ckiNew.ctg, ckiNew.cno) ||
|
|
(pdcdNew == this && _sel.Ln() == sel.Ln()))
|
|
{
|
|
pdcdNew = pvNil;
|
|
}
|
|
else
|
|
{
|
|
if (grfsel & fselKid)
|
|
sel.FSetCkiKid(&ckiNew);
|
|
lnNew = sel.Ln();
|
|
if (lnNew < pdcdNew->_scvVert)
|
|
pdcdNew = pvNil;
|
|
}
|
|
}
|
|
if (pvNil == pdcdNew)
|
|
lnNew = lnNil;
|
|
|
|
if (pdcd != pdcdNew || ln != lnNew)
|
|
{
|
|
//target change
|
|
if (pvNil != pdcdNew)
|
|
pdcdNew->_HiliteLn(lnNew);
|
|
if (pvNil != pdcd)
|
|
pdcd->_HiliteLn(ln);
|
|
pdcd = pdcdNew;
|
|
ln = lnNew;
|
|
}
|
|
}
|
|
if (pvNil != pdcd)
|
|
{
|
|
pdcd->_HiliteLn(ln);
|
|
if (pdcd != this || ln != _sel.Ln())
|
|
_FDoAdoptChunkDlg(&ckiNew, &kid);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Hilite the line (to indicate a drag target)
|
|
***************************************************************************/
|
|
void DCD::_HiliteLn(long ln)
|
|
{
|
|
AssertThis(0);
|
|
RC rc;
|
|
GNV gnv(this);
|
|
|
|
gnv.GetRcSrc(&rc);
|
|
rc.ypTop = _YpFromLn(ln);
|
|
rc.ypBottom = rc.ypTop + _dypLine - _dypBorder;
|
|
gnv.SetPenSize(2 * _dypBorder, 2 * _dypBorder);
|
|
gnv.FrameRcApt(&rc, &vaptGray, kacrInvert, kacrClear);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Reopen the file - nuking all changes since last saved.
|
|
***************************************************************************/
|
|
bool DCD::FCmdReopen(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pcmd, 0);
|
|
PDOCB pdocb;
|
|
CKI cki;
|
|
KID kid;
|
|
ulong grfsel;
|
|
long lnOld;
|
|
|
|
if (tYes != vpappb->TGiveAlertSz(
|
|
PszLit("Nuke all changes since the last save?"),
|
|
bkYesNo, cokQuestion))
|
|
{
|
|
return fTrue;
|
|
}
|
|
|
|
grfsel = _sel.GrfselGetCkiKid(&cki, &kid);
|
|
lnOld = _sel.Ln();
|
|
_SetSel(lnNil);
|
|
|
|
if (!_pcfl->FReopen())
|
|
{
|
|
_SetSel(lnOld);
|
|
return fTrue;
|
|
}
|
|
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
if (lnNil != lnOld)
|
|
{
|
|
_SetSel(lnNil, &cki, (grfsel & fselKid) ? &kid : pvNil);
|
|
_ShowSel();
|
|
}
|
|
|
|
// get rid of all child documents
|
|
while (pvNil != (pdocb = _pdocb->PdocbChd()))
|
|
{
|
|
pdocb->CloseAllDdg();
|
|
if (pdocb == _pdocb->PdocbChd())
|
|
{
|
|
// REVIEW shonk: Release: is this the right thing to do? What if
|
|
// someone else has a reference count to this child DOCB?
|
|
Bug("why wasn't this child doc released?");
|
|
ReleasePpo(&pdocb);
|
|
}
|
|
}
|
|
|
|
_pdocb->SetDirty(fFalse);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle key input.
|
|
***************************************************************************/
|
|
bool DCD::FCmdKey(PCMD_KEY pcmd)
|
|
{
|
|
AssertThis(0);
|
|
long ln, lnLim, lnNew, cln;
|
|
ulong grfsel;
|
|
KID kid;
|
|
CKI cki;
|
|
RC rc;
|
|
|
|
ln = _sel.Ln();
|
|
lnLim = _sel.LnLim();
|
|
switch (pcmd->vk)
|
|
{
|
|
case kvkDown:
|
|
lnNew = (0 > ln) ? 0 : (ln + 1) % lnLim;
|
|
goto LChangeSel;
|
|
|
|
case kvkUp:
|
|
lnNew = (0 > ln) ? lnLim - 1 : (ln + lnLim - 1) % lnLim;
|
|
goto LChangeSel;
|
|
|
|
case kvkPageUp:
|
|
case kvkPageDown:
|
|
_GetContent(&rc);
|
|
cln = LwMax(1, rc.Dyp() / _dypLine - 1);
|
|
if (pcmd->vk == kvkPageDown)
|
|
lnNew = LwMin(lnLim - 1, lnNil == ln ? cln : ln + cln);
|
|
else
|
|
lnNew = LwMax(0, lnNil == ln ? 0 : ln - cln);
|
|
goto LChangeSel;
|
|
|
|
case kvkHome:
|
|
lnNew = 0;
|
|
goto LChangeSel;
|
|
|
|
case kvkEnd:
|
|
lnNew = lnLim - 1;
|
|
LChangeSel:
|
|
if (lnLim == 0)
|
|
{
|
|
Assert(lnNil == ln, "no lines, but non-nil sel");
|
|
break;
|
|
}
|
|
|
|
AssertIn(lnNew, 0, lnLim);
|
|
_SetSel(lnNew);
|
|
_ShowSel();
|
|
break;
|
|
|
|
case kvkDelete:
|
|
case kvkBack:
|
|
_ClearSel();
|
|
break;
|
|
|
|
case kvkReturn:
|
|
grfsel = _sel.GrfselGetCkiKid(&cki, &kid);
|
|
if (pcmd->grfcust & fcustCmd)
|
|
{
|
|
_SetSel(lnNil);
|
|
if (grfsel & fselKid)
|
|
{
|
|
if (_FChangeChid(&cki, &kid))
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
_SetSel(lnNil, &cki, &kid);
|
|
_ShowSel();
|
|
}
|
|
else
|
|
{
|
|
if (_FEditChunkInfo(&cki))
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
_SetSel(lnNil, &cki);
|
|
_ShowSel();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (grfsel & fselKid)
|
|
{
|
|
_SetSel(lnNil, &kid.cki);
|
|
_ShowSel();
|
|
}
|
|
else if (grfsel & fselCki)
|
|
{
|
|
//edit the chunk
|
|
_ShowSel();
|
|
_EditCki(&cki, cidEditNatural);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return the maximum for the indicated scroll bar.
|
|
***************************************************************************/
|
|
long DCD::_ScvMax(bool fVert)
|
|
{
|
|
AssertThis(0);
|
|
|
|
if (fVert)
|
|
{
|
|
RC rc;
|
|
|
|
_GetContent(&rc);
|
|
return LwMax(0, _sel.LnLim() - rc.Dyp() / _dypLine + 1);
|
|
}
|
|
return 320;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle enabling/disabling DCD commands.
|
|
***************************************************************************/
|
|
bool DCD::FEnableDcdCmd(PCMD pcmd, ulong *pgrfeds)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
AssertVarMem(pgrfeds);
|
|
CKI cki;
|
|
|
|
switch (pcmd->cid)
|
|
{
|
|
case cidUnadoptChunk:
|
|
case cidChangeChid:
|
|
if (ivNil == _sel.Ikid())
|
|
goto LDisable;
|
|
break;
|
|
|
|
case cidPlaySound:
|
|
if (fselCki != _sel.GrfselGetCkiKid(&cki, pvNil))
|
|
goto LDisable;
|
|
if (cki.ctg != kctgWave && cki.ctg != kctgMidi)
|
|
goto LDisable;
|
|
break;
|
|
|
|
case cidDeleteChunk:
|
|
case cidUndeleteChunk:
|
|
case cidEditNatural:
|
|
case cidEditHex:
|
|
case cidEditGL:
|
|
case cidEditAL:
|
|
case cidEditGG:
|
|
case cidEditAG:
|
|
case cidEditGST:
|
|
case cidEditAST:
|
|
case cidEditPic:
|
|
case cidEditMbmp:
|
|
case cidTestScript:
|
|
case cidRunScriptCache:
|
|
case cidDisassembleScript:
|
|
case cidEditChunkInfo:
|
|
case cidSetColorTable:
|
|
case cidPack:
|
|
case cidTogglePack:
|
|
case cidCloneChunk:
|
|
if (fselCki != _sel.GrfselGetCkiKid(pvNil, pvNil))
|
|
goto LDisable;
|
|
break;
|
|
|
|
default:
|
|
BugVar("unhandled command in FEnableDcdCmd", &pcmd->cid);
|
|
LDisable:
|
|
*pgrfeds = fedsDisable;
|
|
return fTrue;
|
|
}
|
|
|
|
*pgrfeds = fedsEnable;
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Put up the dialog and add the chunk.
|
|
***************************************************************************/
|
|
bool DCD::_FAddChunk(CTG ctgDef, CKI *pcki, bool *pfCreated)
|
|
{
|
|
AssertVarMem(pcki);
|
|
AssertVarMem(pfCreated);
|
|
long idit;
|
|
long lw;
|
|
bool fEmpty;
|
|
PDLG pdlg;
|
|
ADCD adcd;
|
|
STN stn;
|
|
|
|
//put up the dialog
|
|
adcd.pcfl = _pcfl;
|
|
adcd.fCkiValid = fFalse;
|
|
pdlg = DLG::PdlgNew(dlidChunkInfo, _FDlgAddChunk, &adcd);
|
|
if (pvNil == pdlg)
|
|
goto LCancel;
|
|
if (ctgNil != ctgDef)
|
|
{
|
|
_PutCtgStn(pdlg, kiditCtgInfo, ctgDef);
|
|
idit = kiditCnoInfo;
|
|
}
|
|
else
|
|
idit = kiditCtgInfo;
|
|
idit = pdlg->IditDo(idit);
|
|
if (idit != kiditOkInfo)
|
|
goto LCancel;
|
|
|
|
if (!_FGetCtg(pdlg, kiditCtgInfo, &pcki->ctg) ||
|
|
!pdlg->FGetLwFromEdit(kiditCnoInfo, &lw, &fEmpty) && !fEmpty)
|
|
{
|
|
goto LFail;
|
|
}
|
|
pcki->cno = lw;
|
|
pdlg->GetStn(kiditNameInfo, &stn);
|
|
ReleasePpo(&pdlg);
|
|
|
|
if (fEmpty)
|
|
{
|
|
if (!_pcfl->FAdd(0, pcki->ctg, &pcki->cno))
|
|
goto LFail;
|
|
*pfCreated = fTrue;
|
|
}
|
|
else
|
|
{
|
|
*pfCreated = !_pcfl->FFind(pcki->ctg, pcki->cno);
|
|
if (*pfCreated && !_pcfl->FPut(0, pcki->ctg, pcki->cno))
|
|
{
|
|
LFail:
|
|
vpappb->TGiveAlertSz(PszLit("Writing chunk failed"),
|
|
bkOk, cokExclamation);
|
|
LCancel:
|
|
ReleasePpo(&pdlg);
|
|
TrashVar(pcki);
|
|
TrashVar(pfCreated);
|
|
return fFalse;
|
|
}
|
|
}
|
|
if (stn.Cch() != 0)
|
|
{
|
|
if (!_pcfl->FSetName(pcki->ctg, pcki->cno, &stn))
|
|
Warn("can't set name");
|
|
}
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle command to add a chunk.
|
|
***************************************************************************/
|
|
bool DCD::FCmdAddChunk(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
CKI cki;
|
|
long lnOld;
|
|
bool fCreated;
|
|
|
|
//save and clear the sel
|
|
lnOld = _sel.Ln();
|
|
_SetSel(lnNil);
|
|
|
|
if (!_FAddChunk(ctgNil, &cki, &fCreated))
|
|
{
|
|
pcmd->cid = cidNil; //don't record
|
|
_SetSel(lnOld);
|
|
return fTrue;
|
|
}
|
|
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
_SetSel(lnNil, &cki);
|
|
_ShowSel();
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle command to add a chunk.
|
|
***************************************************************************/
|
|
bool DCD::FCmdAddPicChunk(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
CKI cki;
|
|
BLCK blck;
|
|
long cb;
|
|
long lnOld;
|
|
FNI fni;
|
|
bool fCreated;
|
|
PPIC ppic = pvNil;
|
|
|
|
//save and clear the sel
|
|
lnOld = _sel.Ln();
|
|
_SetSel(lnNil);
|
|
|
|
//get the fni of the file to add
|
|
Mac( FTG ftg = 'PICT'; )
|
|
if (!FGetFniOpenMacro(&fni, &ftg, 1, PszLit("MetaFiles\0*.EMF;*.WMF\0"),
|
|
vwig.hwndApp))
|
|
{
|
|
goto LCancel;
|
|
}
|
|
if (pvNil == (ppic = PIC::PpicReadNative(&fni)))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Reading picture file failed"),
|
|
bkOk, cokExclamation);
|
|
goto LCancel;
|
|
}
|
|
|
|
//add the chunk and write the data
|
|
if (!_FAddChunk(kctgPictNative, &cki, &fCreated))
|
|
goto LCancel;
|
|
cb = ppic->CbOnFile();
|
|
if (!_pcfl->FPut(cb, cki.ctg, cki.cno, &blck) ||
|
|
!ppic->FWrite(&blck))
|
|
{
|
|
if (fCreated)
|
|
_pcfl->Delete(cki.ctg, cki.cno);
|
|
vpappb->TGiveAlertSz(PszLit("Writing chunk failed"), bkOk, cokExclamation);
|
|
LCancel:
|
|
ReleasePpo(&ppic);
|
|
pcmd->cid = cidNil; //don't record
|
|
_SetSel(lnOld);
|
|
return fTrue;
|
|
}
|
|
ReleasePpo(&ppic);
|
|
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
_SetSel(lnNil, &cki);
|
|
_ShowSel();
|
|
return fTrue;
|
|
}
|
|
|
|
/***************************************************************************
|
|
Masked bitmap dialog
|
|
***************************************************************************/
|
|
enum
|
|
{
|
|
kiditOkMbmp,
|
|
kiditCancelMbmp,
|
|
kiditPixelMbmp,
|
|
kiditXPosMbmp,
|
|
kiditYPosMbmp,
|
|
kiditDefaultMbmp,
|
|
kiditLimMbmp
|
|
};
|
|
bool _FDlgMbmp(PDLG pdlg, long *pidit, void *pv);
|
|
|
|
|
|
/****************************************************************************
|
|
Dialog proc for input of transparent pixel value and reference point
|
|
****************************************************************************/
|
|
bool _FDlgMbmp(PDLG pdlg, long *pidit, void *pv)
|
|
{
|
|
AssertPo(pdlg, 0);
|
|
AssertVarMem(pidit);
|
|
long lw;
|
|
|
|
switch (*pidit)
|
|
{
|
|
case kiditCancelMbmp:
|
|
return fTrue;
|
|
case kiditOkMbmp:
|
|
if (!pdlg->FGetValues(0, kiditLimMbmp))
|
|
{
|
|
*pidit = ivNil;
|
|
return fTrue;
|
|
}
|
|
if (!pdlg->FGetLwFromEdit(kiditPixelMbmp, &lw) ||
|
|
!FIn(lw, 0, (long) kbMax + 1))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("The transparent pixel value must be ")
|
|
PszLit("between 0 and 255."), bkOk, cokStop);
|
|
pdlg->SelectDit(kiditPixelMbmp);
|
|
return fFalse;
|
|
}
|
|
if (!pdlg->FGetLwFromEdit(kiditXPosMbmp, &lw))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("The X Position must be an integer."),
|
|
bkOk, cokStop);
|
|
pdlg->SelectDit(kiditXPosMbmp);
|
|
return fFalse;
|
|
}
|
|
if (!pdlg->FGetLwFromEdit(kiditYPosMbmp, &lw))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("The Y Position must be an integer."),
|
|
bkOk, cokStop);
|
|
pdlg->SelectDit(kiditYPosMbmp);
|
|
return fFalse;
|
|
}
|
|
return fTrue;
|
|
default:
|
|
break;
|
|
}
|
|
return fFalse;
|
|
}
|
|
|
|
/***************************************************************************
|
|
Handle command to add Mbmp or chunk.
|
|
***************************************************************************/
|
|
bool DCD::FCmdAddBitmapChunk(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
CKI cki;
|
|
BLCK blck;
|
|
long lw;
|
|
long lnOld;
|
|
FNI fni;
|
|
bool fCreated;
|
|
byte bTransparent;
|
|
long xp, yp;
|
|
bool fMask = pcmd->cid != cidAddMbmpChunk;
|
|
PBACO pbaco = pvNil;
|
|
CTG ctg;
|
|
PDLG pdlg = pvNil;
|
|
|
|
// save and clear the sel
|
|
lnOld = _sel.Ln();
|
|
_SetSel(lnNil);
|
|
|
|
// get the fni of the file to add
|
|
Mac(FTG ftg = '\0BMP';) //REVIEW shonk: this is bogus
|
|
if (!FGetFniOpenMacro(&fni, &ftg, 1, PszLit("Bitmaps\0*.BMP\0"), vwig.hwndApp))
|
|
goto LCancel;
|
|
|
|
|
|
// get the transparent pixel value
|
|
pdlg = DLG::PdlgNew(dlidMbmp, _FDlgMbmp);
|
|
if (pvNil == pdlg)
|
|
goto LCancel;
|
|
// put up the initial values
|
|
pdlg->FPutLwInEdit(kiditPixelMbmp, 0);
|
|
pdlg->FPutLwInEdit(kiditXPosMbmp, 0);
|
|
pdlg->FPutLwInEdit(kiditYPosMbmp, 0);
|
|
if (pdlg->IditDo(kiditPixelMbmp) != kiditOkMbmp)
|
|
goto LErrDlg;
|
|
if (!pdlg->FGetLwFromEdit(kiditPixelMbmp, &lw) ||
|
|
!FIn(lw, 0, (long) kbMax + 1))
|
|
{
|
|
goto LErrDlg;
|
|
}
|
|
bTransparent = (byte) lw;
|
|
|
|
if (!pdlg->FGetLwFromEdit(kiditXPosMbmp, &lw))
|
|
goto LErrDlg;
|
|
xp = lw;
|
|
if (!pdlg->FGetLwFromEdit(kiditXPosMbmp, &lw))
|
|
{
|
|
LErrDlg:
|
|
ReleasePpo(&pdlg);
|
|
goto LCancel;
|
|
}
|
|
yp = lw;
|
|
ReleasePpo(&pdlg);
|
|
|
|
if (pvNil == (pbaco = MBMP::PmbmpReadNative(&fni, bTransparent, xp, yp,
|
|
fMask ? fmbmpMask : fmbmpNil)))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Reading bitmap file failed"),
|
|
bkOk, cokExclamation);
|
|
goto LCancel;
|
|
}
|
|
ctg = fMask ? kctgMask : kctgMbmp;
|
|
|
|
// add the chunk and write the data
|
|
if (!_FAddChunk(ctg, &cki, &fCreated))
|
|
goto LCancel;
|
|
|
|
if (!_pcfl->FPut(pbaco->CbOnFile(), cki.ctg, cki.cno, &blck) ||
|
|
!pbaco->FWrite(&blck))
|
|
{
|
|
if (fCreated)
|
|
_pcfl->Delete(cki.ctg, cki.cno);
|
|
vpappb->TGiveAlertSz(PszLit("Writing chunk failed"), bkOk, cokExclamation);
|
|
LCancel:
|
|
ReleasePpo(&pbaco);
|
|
pcmd->cid = cidNil; // don't record
|
|
_SetSel(lnOld);
|
|
return fTrue;
|
|
}
|
|
ReleasePpo(&pbaco);
|
|
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
_SetSel(lnNil, &cki);
|
|
_ShowSel();
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle command to add a chunk that is a copy of a file's contents.
|
|
***************************************************************************/
|
|
bool DCD::FCmdAddFileChunk(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
CKI cki;
|
|
PFIL pfil;
|
|
BLCK blck;
|
|
long lnOld;
|
|
FNI fni;
|
|
bool fCreated;
|
|
|
|
//save and clear the sel
|
|
lnOld = _sel.Ln();
|
|
_SetSel(lnNil);
|
|
|
|
//get the fni of the file to add
|
|
if (!FGetFniOpenMacro(&fni, pvNil, 0, PszLit("All files\0*.*\0"), vwig.hwndApp))
|
|
goto LCancel;
|
|
if (pvNil == (pfil = FIL::PfilOpen(&fni)))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Opening file failed"), bkOk, cokExclamation);
|
|
goto LCancel;
|
|
}
|
|
blck.Set(pfil, 0, pfil->FpMac());
|
|
ReleasePpo(&pfil);
|
|
|
|
//add the chunk and write the data
|
|
if (!_FAddChunk(ctgNil, &cki, &fCreated))
|
|
goto LCancel;
|
|
if (!_pcfl->FPutBlck(&blck, cki.ctg, cki.cno))
|
|
{
|
|
if (fCreated)
|
|
_pcfl->Delete(cki.ctg, cki.cno);
|
|
vpappb->TGiveAlertSz(PszLit("Writing chunk failed"), bkOk, cokExclamation);
|
|
LCancel:
|
|
pcmd->cid = cidNil; //don't record
|
|
_SetSel(lnOld);
|
|
return fTrue;
|
|
}
|
|
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
_SetSel(lnNil, &cki);
|
|
_ShowSel();
|
|
return fTrue;
|
|
}
|
|
|
|
/**************************************************************************
|
|
Edit Chunk Information dialog
|
|
**************************************************************************/
|
|
|
|
// This struct is needed so _FDlgEditChunkInfo() has access to the chunk
|
|
// and chunky file and so _FDlgChangeChunk() has access to the parent and
|
|
// child chunks and the chunky file.
|
|
struct CLAN
|
|
{
|
|
CKI cki;
|
|
KID kid;
|
|
PCFL pcfl;
|
|
};
|
|
|
|
|
|
bool _FDlgEditChunkInfo(PDLG pdlg, long *pidit, void *pv);
|
|
|
|
/**************************************************************************
|
|
Dialog proc for Edit Chunk Info dialog. *pv should be a CLAN *, with
|
|
the cki and pcfl fields filled in (the kid field is not used).
|
|
**************************************************************************/
|
|
bool _FDlgEditChunkInfo(PDLG pdlg, long *pidit, void *pv)
|
|
{
|
|
AssertPo(pdlg, 0);
|
|
AssertVarMem(pidit);
|
|
CKI cki;
|
|
long lw;
|
|
bool fEmpty;
|
|
CLAN *pclan = (CLAN *)pv;
|
|
AssertVarMem(pclan);
|
|
AssertPo(pclan->pcfl, 0);
|
|
|
|
switch (*pidit)
|
|
{
|
|
case kiditCancelInfo:
|
|
return fTrue; // dismiss the dialog
|
|
case kiditOkInfo:
|
|
if (!pdlg->FGetValues(0, kiditLimInfo))
|
|
{
|
|
*pidit = ivNil;
|
|
return fTrue;
|
|
}
|
|
|
|
// check the chunk
|
|
if (!_FGetCtg(pdlg, kiditCtgInfo, &cki.ctg))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("CTG is bad"), bkOk, cokStop);
|
|
pdlg->SelectDit(kiditCtgInfo);
|
|
return fFalse;
|
|
}
|
|
if (!pdlg->FGetLwFromEdit(kiditCnoInfo, &lw, &fEmpty))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("CNO is bad"), bkOk, cokStop);
|
|
pdlg->SelectDit(kiditCnoInfo);
|
|
return fFalse;
|
|
}
|
|
cki.cno = lw;
|
|
if (pclan->pcfl->FFind(cki.ctg, cki.cno) &&
|
|
(cki.ctg != pclan->cki.ctg || cki.cno != pclan->cki.cno))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("That CTG/CNO pair already exists"),
|
|
bkOk, cokStop);
|
|
pdlg->SelectDit(kiditCtgInfo);
|
|
return fFalse;
|
|
}
|
|
return fTrue;
|
|
default:
|
|
break;
|
|
}
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
Put up the dialog with initial values and edit the chunk. This function
|
|
will update *pckiOld to contain the new ctg and cno values.
|
|
****************************************************************************/
|
|
bool DCD::_FEditChunkInfo(CKI *pckiOld)
|
|
{
|
|
AssertVarMem(pckiOld);
|
|
long idit;
|
|
long lw;
|
|
PDLG pdlg;
|
|
STN stn;
|
|
CLAN clan;
|
|
CKI cki;
|
|
|
|
clan.pcfl = _pcfl;
|
|
clan.cki = *pckiOld;
|
|
TrashVar(&clan.kid);
|
|
// put up the dialog
|
|
pdlg = DLG::PdlgNew(dlidChunkInfo, _FDlgEditChunkInfo, &clan);
|
|
if (pvNil == pdlg)
|
|
return fFalse;
|
|
|
|
// set the initial values
|
|
idit = kiditCtgInfo;
|
|
_PutCtgStn(pdlg, kiditCtgInfo, pckiOld->ctg);
|
|
pdlg->FPutLwInEdit(kiditCnoInfo, pckiOld->cno);
|
|
_pcfl->FGetName(pckiOld->ctg, pckiOld->cno, &stn);
|
|
pdlg->FPutStn(kiditNameInfo, &stn);
|
|
|
|
idit = pdlg->IditDo(idit);
|
|
if (idit != kiditOkInfo ||
|
|
!_FGetCtg(pdlg, kiditCtgInfo, &cki.ctg) ||
|
|
!pdlg->FGetLwFromEdit(kiditCnoInfo, &lw))
|
|
{
|
|
ReleasePpo(&pdlg);
|
|
return fFalse;
|
|
}
|
|
pdlg->GetStn(kiditNameInfo, &stn);
|
|
ReleasePpo(&pdlg);
|
|
cki.cno = lw;
|
|
|
|
if (cki.ctg != pckiOld->ctg || cki.cno != pckiOld->cno)
|
|
_pcfl->Move(pckiOld->ctg, pckiOld->cno, cki.ctg, cki.cno);
|
|
|
|
// set the original cki to the new cki so the caller has the new chunk
|
|
pckiOld->ctg = cki.ctg;
|
|
pckiOld->cno = cki.cno;
|
|
|
|
if (!_pcfl->FSetName(cki.ctg, cki.cno, &stn))
|
|
Warn("can't set new name");
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
Handle command to edit chunk information.
|
|
**************************************************************************/
|
|
bool DCD::FCmdEditChunkInfo(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
CKI cki;
|
|
long lnOld;
|
|
|
|
// record, save, and clear the sel
|
|
if (fselCki != _sel.GrfselGetCkiKid(&cki, pvNil))
|
|
goto LFail;
|
|
lnOld = _sel.Ln();
|
|
_SetSel(lnNil);
|
|
|
|
if (!_FEditChunkInfo(&cki))
|
|
{
|
|
_SetSel(lnOld);
|
|
LFail:
|
|
pcmd->cid = cidNil; // don't record
|
|
return fTrue;
|
|
}
|
|
|
|
// refresh the window and reset the selection
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
_SetSel(lnNil, &cki);
|
|
_ShowSel();
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle command to delete a chunk.
|
|
***************************************************************************/
|
|
bool DCD::FCmdDeleteChunk(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
CKI cki;
|
|
|
|
if (fselCki != _sel.GrfselGetCkiKid(&cki, pvNil))
|
|
goto LCancel;
|
|
|
|
if (pcmd->cid == cidDeleteChunk)
|
|
{
|
|
_pcfl->SetLoner(cki.ctg, cki.cno, fFalse);
|
|
DOCE::CloseDeletedDoce(_pdocb);
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
_ShowSel();
|
|
}
|
|
else
|
|
{
|
|
_pcfl->SetLoner(cki.ctg, cki.cno, fTrue);
|
|
InvalAllDcd(_pdocb, _pcfl, &cki);
|
|
_ShowSel();
|
|
}
|
|
|
|
return fTrue;
|
|
|
|
LCancel:
|
|
pcmd->cid = cidNil; //don't record
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
Change CHID dialog
|
|
**************************************************************************/
|
|
enum
|
|
{
|
|
kiditOkChid,
|
|
kiditCancelChid,
|
|
kiditChidChid,
|
|
kiditLimChid
|
|
};
|
|
|
|
bool _FDlgChangeChid(PDLG pdlg, long *pidit, void *pv);
|
|
|
|
/**************************************************************************
|
|
Dialog proc for Change CHID dialog.
|
|
**************************************************************************/
|
|
bool _FDlgChangeChid(PDLG pdlg, long *pidit, void *pv)
|
|
{
|
|
AssertPo(pdlg, 0);
|
|
AssertVarMem(pidit);
|
|
CHID chid;
|
|
long lw;
|
|
long ikid;
|
|
CLAN *pclan = (CLAN *)pv;
|
|
AssertVarMem(pclan);
|
|
AssertPo(pclan->pcfl, 0);
|
|
|
|
switch (*pidit)
|
|
{
|
|
case kiditCancelChid:
|
|
return fTrue; // dismiss the dialog
|
|
case kiditOkChid:
|
|
if (!pdlg->FGetValues(kiditChidChid, kiditLimChid))
|
|
{
|
|
*pidit = ivNil;
|
|
return fTrue;
|
|
}
|
|
|
|
// get the new chid
|
|
if (!pdlg->FGetLwFromEdit(kiditChidChid, &lw))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("CHID value is bad"), bkOk, cokStop);
|
|
pdlg->SelectDit(kiditChidChid);
|
|
return fFalse;
|
|
}
|
|
chid = lw;
|
|
|
|
// check the new chid to make sure that the CTG/CNO/new CHID does not
|
|
// already exist
|
|
if (pclan->pcfl->FGetIkid(pclan->cki.ctg, pclan->cki.cno,
|
|
pclan->kid.cki.ctg, pclan->kid.cki.cno, chid, &ikid) &&
|
|
chid != pclan->kid.chid)
|
|
{
|
|
vpappb->TGiveAlertSz(
|
|
PszLit("This parent/child relationship already exists."),
|
|
bkOk, cokStop);
|
|
pdlg->SelectDit(kiditChidChid);
|
|
return fFalse;
|
|
}
|
|
return fTrue;
|
|
default:
|
|
break;
|
|
}
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
Put up the dialog with initial values and change the CHID. *pkid will be
|
|
affected to reflect this change.
|
|
****************************************************************************/
|
|
bool DCD::_FChangeChid(CKI *pcki, KID *pkid)
|
|
{
|
|
AssertVarMem(pcki);
|
|
AssertVarMem(pkid);
|
|
long idit;
|
|
CHID chid;
|
|
PDLG pdlg;
|
|
long lw;
|
|
CLAN clan;
|
|
|
|
clan.cki = *pcki;
|
|
clan.kid = *pkid;
|
|
clan.pcfl = _pcfl;
|
|
|
|
// put up the dialog
|
|
pdlg = DLG::PdlgNew(dlidChangeChid, _FDlgChangeChid, &clan);
|
|
if (pvNil == pdlg)
|
|
return fFalse;
|
|
|
|
// set the initial value
|
|
pdlg->FPutLwInEdit(kiditChidChid, pkid->chid);
|
|
|
|
idit = pdlg->IditDo(kiditChidChid);
|
|
if (idit != kiditOkChid ||
|
|
!pdlg->FGetLwFromEdit(kiditChidChid, &lw))
|
|
{
|
|
ReleasePpo(&pdlg);
|
|
return fFalse;
|
|
}
|
|
chid = lw;
|
|
ReleasePpo(&pdlg);
|
|
|
|
// If new CHID is different, unadopt and adopt child to change CHID.
|
|
// This is easier than directly changing the GG which keeps track of the
|
|
// parent and its children.
|
|
if (chid != pkid->chid)
|
|
{
|
|
_pcfl->ChangeChid(pcki->ctg, pcki->cno, pkid->cki.ctg,
|
|
pkid->cki.cno, pkid->chid, chid);
|
|
// set the new CHID so the caller has the right kid
|
|
pkid->chid = chid;
|
|
}
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
/**************************************************************************
|
|
Handle command to change the CHID.
|
|
**************************************************************************/
|
|
bool DCD::FCmdChangeChid(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
CKI cki;
|
|
KID kid;
|
|
long lnOld;
|
|
|
|
// record, save, and clear the sel
|
|
if (ivNil == _sel.Icki() || ivNil == _sel.Ikid())
|
|
goto LFail;
|
|
_sel.GrfselGetCkiKid(&cki, &kid);
|
|
lnOld = _sel.Ln();
|
|
_SetSel(lnNil);
|
|
|
|
if (!_FChangeChid(&cki, &kid))
|
|
{
|
|
_SetSel(lnOld);
|
|
LFail:
|
|
pcmd->cid = cidNil; // don't record
|
|
return fTrue;
|
|
}
|
|
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
_SetSel(lnNil, &cki, &kid);
|
|
_ShowSel();
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/****************************************
|
|
Adopt Chunk dialog
|
|
****************************************/
|
|
enum
|
|
{
|
|
kiditOkAdopt,
|
|
kiditCancelAdopt,
|
|
kiditCtgParAdopt,
|
|
kiditCnoParAdopt,
|
|
kiditCtgChdAdopt,
|
|
kiditCnoChdAdopt,
|
|
kiditChidAdopt,
|
|
kiditLimAdopt
|
|
};
|
|
bool _FDlgAdoptChunk(PDLG pdlg, long *pidit, void *pv);
|
|
|
|
|
|
/***************************************************************************
|
|
Dialog proc for Adopt Chunk dialog.
|
|
***************************************************************************/
|
|
bool _FDlgAdoptChunk(PDLG pdlg, long *pidit, void *pv)
|
|
{
|
|
AssertPo(pdlg, 0);
|
|
AssertVarMem(pidit);
|
|
long lw;
|
|
CKI cki;
|
|
KID kid;
|
|
long ikid;
|
|
bool fEmpty;
|
|
PCFL pcfl = (PCFL)pv;
|
|
|
|
AssertPo(pcfl, 0);
|
|
switch (*pidit)
|
|
{
|
|
case kiditCancelAdopt:
|
|
return fTrue; //dismiss the dialog
|
|
|
|
case kiditOkAdopt:
|
|
if (!pdlg->FGetValues(0, kiditLimAdopt))
|
|
{
|
|
*pidit = ivNil;
|
|
return fTrue;
|
|
}
|
|
|
|
//check the parent
|
|
if (!_FGetCtg(pdlg, kiditCtgParAdopt, &cki.ctg))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Parent CTG is bad"), bkOk, cokStop);
|
|
pdlg->SelectDit(kiditCtgParAdopt);
|
|
return fFalse;
|
|
}
|
|
if (!pdlg->FGetLwFromEdit(kiditCnoParAdopt, &lw))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Parent CNO is bad"), bkOk, cokStop);
|
|
pdlg->SelectDit(kiditCnoParAdopt);
|
|
return fFalse;
|
|
}
|
|
cki.cno = lw;
|
|
if (!pcfl->FFind(cki.ctg, cki.cno))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Parent chunk doesn't exist"),
|
|
bkOk, cokStop);
|
|
pdlg->SelectDit(kiditCtgParAdopt);
|
|
return fFalse;
|
|
}
|
|
|
|
//check the child
|
|
if (!_FGetCtg(pdlg, kiditCtgChdAdopt, &kid.cki.ctg))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Child CTG is bad"), bkOk, cokStop);
|
|
pdlg->SelectDit(kiditCtgChdAdopt);
|
|
return fFalse;
|
|
}
|
|
if (!pdlg->FGetLwFromEdit(kiditCnoChdAdopt, &lw))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Child CNO is bad"), bkOk, cokStop);
|
|
pdlg->SelectDit(kiditCnoChdAdopt);
|
|
return fFalse;
|
|
}
|
|
kid.cki.cno = lw;
|
|
if (!pcfl->FFind(kid.cki.ctg, kid.cki.cno))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Child chunk doesn't exist"),
|
|
bkOk, cokStop);
|
|
pdlg->SelectDit(kiditCtgChdAdopt);
|
|
return fFalse;
|
|
}
|
|
|
|
//check the chid
|
|
if (!pdlg->FGetLwFromEdit(kiditChidAdopt, &lw, &fEmpty) && !fEmpty)
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Child ID value is bad"), bkOk, cokStop);
|
|
pdlg->SelectDit(kiditChidAdopt);
|
|
return fFalse;
|
|
}
|
|
kid.chid = lw;
|
|
|
|
//see if this child-parent relationship already exists
|
|
if (pcfl->FGetIkid(cki.ctg, cki.cno, kid.cki.ctg, kid.cki.cno,
|
|
kid.chid, &ikid) && !fEmpty)
|
|
{
|
|
vpappb->TGiveAlertSz(
|
|
PszLit("This parent/child relationship already exists."),
|
|
bkOk, cokStop);
|
|
pdlg->SelectDit(kiditChidAdopt);
|
|
return fFalse;
|
|
}
|
|
|
|
//see if a loop would be formed
|
|
if (pcfl->TIsDescendent(kid.cki.ctg, kid.cki.cno, cki.ctg, cki.cno))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Adopting this child would form a loop")
|
|
PszLit(" in the chunky file graph structure"), bkOk, cokStop);
|
|
return fFalse;
|
|
}
|
|
|
|
return fTrue;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Put up and handle the adopt dialog with the given initial values
|
|
(if not nil).
|
|
***************************************************************************/
|
|
bool DCD::_FDoAdoptChunkDlg(CKI *pcki, KID *pkid)
|
|
{
|
|
AssertThis(0);
|
|
AssertNilOrVarMem(pcki);
|
|
AssertNilOrVarMem(pkid);
|
|
long idit;
|
|
CKI cki;
|
|
KID kid;
|
|
long lnOld;
|
|
long lw1, lw2, lw3;
|
|
bool fEmptyChid;
|
|
PDLG pdlg = pvNil;
|
|
|
|
//put up the dialog
|
|
pdlg = DLG::PdlgNew(dlidAdoptChunk, _FDlgAdoptChunk, _pcfl);
|
|
if (pvNil == pdlg)
|
|
return fFalse;
|
|
|
|
//set the initial values
|
|
idit = kiditCtgParAdopt;
|
|
if (pvNil != pcki)
|
|
{
|
|
_PutCtgStn(pdlg, kiditCtgParAdopt, pcki->ctg);
|
|
pdlg->FPutLwInEdit(kiditCnoParAdopt, pcki->cno);
|
|
idit = kiditCtgChdAdopt;
|
|
}
|
|
if (pvNil != pkid)
|
|
{
|
|
_PutCtgStn(pdlg, kiditCtgChdAdopt, pkid->cki.ctg);
|
|
pdlg->FPutLwInEdit(kiditCnoChdAdopt, pkid->cki.cno);
|
|
pdlg->FPutLwInEdit(kiditChidAdopt, pkid->chid);
|
|
idit = kiditChidAdopt;
|
|
}
|
|
|
|
//save and clear the old sel
|
|
lnOld = _sel.Ln();
|
|
_SetSel(lnNil);
|
|
|
|
idit = pdlg->IditDo(idit);
|
|
if (idit != kiditOkAdopt)
|
|
goto LCancel;
|
|
|
|
if (!_FGetCtg(pdlg, kiditCtgParAdopt, &cki.ctg) ||
|
|
!pdlg->FGetLwFromEdit(kiditCnoParAdopt, &lw1) ||
|
|
!_FGetCtg(pdlg, kiditCtgChdAdopt, &kid.cki.ctg) ||
|
|
!pdlg->FGetLwFromEdit(kiditCnoChdAdopt, &lw2) ||
|
|
!pdlg->FGetLwFromEdit(kiditChidAdopt, &lw3, &fEmptyChid) && !fEmptyChid)
|
|
{
|
|
goto LFail;
|
|
}
|
|
ReleasePpo(&pdlg);
|
|
cki.cno = lw1;
|
|
kid.cki.cno = lw2;
|
|
kid.chid = lw3;
|
|
|
|
if (!_pcfl->FFind(cki.ctg, cki.cno) ||
|
|
!_pcfl->FFind(kid.cki.ctg, kid.cki.cno))
|
|
{
|
|
goto LFail;
|
|
}
|
|
if (!_pcfl->FAdoptChild(cki.ctg, cki.cno,
|
|
kid.cki.ctg, kid.cki.cno, kid.chid))
|
|
{
|
|
LFail:
|
|
vpappb->TGiveAlertSz(PszLit("Adopting chunk failed."),
|
|
bkOk, cokExclamation);
|
|
LCancel:
|
|
ReleasePpo(&pdlg);
|
|
_SetSel(lnOld);
|
|
return fFalse;
|
|
}
|
|
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
_SetSel(lnNil, &cki, &kid);
|
|
_ShowSel();
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle command to adopt a chunk.
|
|
***************************************************************************/
|
|
bool DCD::FCmdAdoptChunk(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
CKI cki;
|
|
CKI *pcki;
|
|
PDLG pdlg = pvNil;
|
|
|
|
if (fselCki & _sel.GrfselGetCkiKid(&cki, pvNil))
|
|
pcki = &cki;
|
|
else
|
|
pcki = pvNil;
|
|
|
|
if (!_FDoAdoptChunkDlg(pcki, pvNil))
|
|
pcmd->cid = cidNil;
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle command to unadopt a chunk.
|
|
***************************************************************************/
|
|
bool DCD::FCmdUnadoptChunk(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
CKI cki;
|
|
KID kid;
|
|
|
|
if (!(_sel.GrfselGetCkiKid(&cki, &kid) & fselKid))
|
|
{
|
|
pcmd->cid = cidNil; //don't record
|
|
return fTrue;
|
|
}
|
|
|
|
_pcfl->DeleteChild(cki.ctg, cki.cno, kid.cki.ctg, kid.cki.cno, kid.chid);
|
|
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
_ShowSel();
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handles commands to edit a chunk.
|
|
***************************************************************************/
|
|
bool DCD::FCmdEditChunk(PCMD pcmd)
|
|
{
|
|
CKI cki;
|
|
|
|
if (fselCki != _sel.GrfselGetCkiKid(&cki, pvNil))
|
|
return fFalse;
|
|
|
|
_EditCki(&cki, pcmd->cid);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
Opens a window onto the CKI's data.
|
|
***************************************************************************/
|
|
void DCD::_EditCki(CKI *pcki, long cid)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcki);
|
|
PDOCE pdoce;
|
|
long cls;
|
|
CTG ctg;
|
|
|
|
//check for a doce already open on the chunk.
|
|
if (pvNil != (pdoce = DOCE::PdoceFromChunk(_pdocb, _pcfl, pcki->ctg, pcki->cno)))
|
|
{
|
|
pdoce->ActivateDmd();
|
|
return;
|
|
}
|
|
|
|
switch (cid)
|
|
{
|
|
case cidEditNatural:
|
|
ctg = pcki->ctg;
|
|
|
|
//handle 4 character ctg's
|
|
switch (ctg)
|
|
{
|
|
case kctgPictNative:
|
|
goto LPic;
|
|
case kctgMbmp:
|
|
case kctgMask:
|
|
goto LMbmp;
|
|
case kctgWave:
|
|
case kctgMidi:
|
|
goto LSound;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//handle 3 character ctg's
|
|
ctg = ctg & 0xFFFFFF00L | 0x00000020L;
|
|
switch (ctg)
|
|
{
|
|
case kctgGst:
|
|
cls = kclsGST;
|
|
goto LDocg;
|
|
case kctgAst:
|
|
cls = kclsAST;
|
|
goto LDocg;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//handle 2 character ctg's
|
|
ctg = ctg & 0xFFFF0000L | 0x00002020L;
|
|
switch (ctg)
|
|
{
|
|
case kctgGl:
|
|
cls = kclsGL;
|
|
goto LDocg;
|
|
case kctgAl:
|
|
cls = kclsAL;
|
|
goto LDocg;
|
|
case kctgGg:
|
|
cls = kclsGG;
|
|
goto LDocg;
|
|
case kctgAg:
|
|
cls = kclsAG;
|
|
goto LDocg;
|
|
default:
|
|
break;
|
|
}
|
|
//fall through
|
|
case cidEditHex:
|
|
LHex:
|
|
cid = cidEditHex;
|
|
pdoce = DOCH::PdochNew(_pdocb, _pcfl, pcki->ctg, pcki->cno);
|
|
break;
|
|
|
|
case cidEditGL:
|
|
cls = kclsGL;
|
|
goto LDocg;
|
|
case cidEditAL:
|
|
cls = kclsAL;
|
|
goto LDocg;
|
|
case cidEditGG:
|
|
cls = kclsGG;
|
|
goto LDocg;
|
|
case cidEditAG:
|
|
cls = kclsAG;
|
|
goto LDocg;
|
|
case cidEditGST:
|
|
cls = kclsGST;
|
|
goto LDocg;
|
|
case cidEditAST:
|
|
cls = kclsAST;
|
|
LDocg:
|
|
pdoce = DOCG::PdocgNew(_pdocb, _pcfl, pcki->ctg, pcki->cno, cls);
|
|
break;
|
|
|
|
case cidEditPic:
|
|
LPic:
|
|
pdoce = DOCPIC::PdocpicNew(_pdocb, _pcfl, pcki->ctg, pcki->cno);
|
|
break;
|
|
case cidEditMbmp:
|
|
LMbmp:
|
|
pdoce = DOCMBMP::PdocmbmpNew(_pdocb, _pcfl, pcki->ctg, pcki->cno);
|
|
break;
|
|
|
|
case cidPlaySound:
|
|
LSound:
|
|
if ((pcki->ctg == kctgMidi || pcki->ctg == kctgWave) && pvNil != vpsndm)
|
|
{
|
|
// play once
|
|
PCRF pcrf;
|
|
|
|
if (pvNil == (pcrf = CRF::PcrfNew(_pcfl, 1)))
|
|
{
|
|
ReleasePpo(&pcrf);
|
|
// edit as hex
|
|
break;
|
|
}
|
|
|
|
vpsndm->SiiPlay(pcrf, pcki->ctg, pcki->cno);
|
|
ReleasePpo(&pcrf);
|
|
return;
|
|
}
|
|
|
|
// edit as hex
|
|
break;
|
|
|
|
default:
|
|
BugVar("unknown cid", &cid);
|
|
return;
|
|
}
|
|
|
|
if (pvNil == pdoce)
|
|
{
|
|
if (cid == cidEditNatural)
|
|
{
|
|
//our guess at a natural type may have been wrong, so just
|
|
//edit as hex
|
|
goto LHex;
|
|
}
|
|
else if (cid != cidEditHex)
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("This chunk doesn't fit that format."),
|
|
bkOk, cokInformation);
|
|
}
|
|
return;
|
|
}
|
|
|
|
pdoce->PdmdNew();
|
|
ReleasePpo(&pdoce);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle command to compile and add a script chunk.
|
|
***************************************************************************/
|
|
bool DCD::FCmdImportScript(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
SCCG sccg;
|
|
CKI cki;
|
|
long lnOld;
|
|
FNI fni;
|
|
bool fCreated;
|
|
MSFIL msfil;
|
|
PSCPT pscpt = pvNil;
|
|
|
|
//save and clear the sel
|
|
lnOld = _sel.Ln();
|
|
_SetSel(lnNil);
|
|
|
|
//get the fni of the file to add
|
|
Mac( FTG ftg = 'TEXT'; )
|
|
if (!FGetFniOpenMacro(&fni, &ftg, 1, PszLit("All files\0*.*\0"), vwig.hwndApp))
|
|
goto LCancel;
|
|
if (pvNil == (pscpt = sccg.PscptCompileFni(&fni,
|
|
pcmd->cid == cidCompileInScript, &msfil)))
|
|
{
|
|
//if the error file isn't empty, open it
|
|
vpappb->TGiveAlertSz(PszLit("Compiling script failed"),
|
|
bkOk, cokExclamation);
|
|
pcmd->cid = cidNil; //don't record
|
|
_SetSel(lnOld);
|
|
OpenSinkDoc(&msfil);
|
|
return fTrue;
|
|
}
|
|
|
|
//add the chunk and write the data
|
|
if (!_FAddChunk(kctgScript, &cki, &fCreated))
|
|
goto LCancel;
|
|
if (!pscpt->FSaveToChunk(_pcfl, cki.ctg, cki.cno))
|
|
{
|
|
if (fCreated)
|
|
_pcfl->Delete(cki.ctg, cki.cno);
|
|
vpappb->TGiveAlertSz(PszLit("Writing chunk failed"), bkOk, cokExclamation);
|
|
LCancel:
|
|
ReleasePpo(&pscpt);
|
|
pcmd->cid = cidNil; //don't record
|
|
_SetSel(lnOld);
|
|
return fTrue;
|
|
}
|
|
ReleasePpo(&pscpt);
|
|
|
|
InvalAllDcd(_pdocb, _pcfl, &cki);
|
|
_SetSel(lnNil, &cki);
|
|
_ShowSel();
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Draw routine for a test-script gob - just erase the gob.
|
|
***************************************************************************/
|
|
void TSCG::Draw(PGNV pgnv, RC *prcClip)
|
|
{
|
|
pgnv->FillRc(prcClip, kacrWhite);
|
|
}
|
|
|
|
|
|
enum
|
|
{
|
|
kiditOkScript,
|
|
kiditCancelScript,
|
|
kiditSizeScript,
|
|
kiditLimScript
|
|
};
|
|
|
|
|
|
/***************************************************************************
|
|
Open a new window and run a script in it.
|
|
***************************************************************************/
|
|
bool DCD::FCmdTestScript(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
CKI cki;
|
|
long cbCache;
|
|
|
|
if (fselCki != _sel.GrfselGetCkiKid(&cki, pvNil))
|
|
return fFalse;
|
|
|
|
if (pcmd->cid == cidRunScriptCache)
|
|
{
|
|
// get the cache size from the user
|
|
PDLG pdlg;
|
|
|
|
// get the cache size
|
|
pdlg = DLG::PdlgNew(dlidScriptCache);
|
|
if (pvNil == pdlg)
|
|
return fTrue;
|
|
|
|
// put up the initial values
|
|
pdlg->FPutLwInEdit(kiditSizeScript, 3072);
|
|
if (pdlg->IditDo(kiditSizeScript) != kiditOkScript)
|
|
goto LCancel;
|
|
if (!pdlg->FGetLwFromEdit(kiditPixelMbmp, &cbCache) ||
|
|
!FIn(cbCache, 0, kcbMax / 1024))
|
|
{
|
|
LCancel:
|
|
ReleasePpo(&pdlg);
|
|
return fTrue;
|
|
}
|
|
cbCache *= 1024;
|
|
ReleasePpo(&pdlg);
|
|
}
|
|
else
|
|
cbCache = 0x00300000L;
|
|
|
|
FTestScript(cki.ctg, cki.cno, cbCache);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Command handler to Edit a WAVE chunk
|
|
***************************************************************************/
|
|
bool DCD::FCmdStopSound(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
|
|
if (pvNil != vpsndm)
|
|
vpsndm->StopAll();
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Command handler to pack or unpack (toggle) a chunk. Also handle just
|
|
toggling the packed flag.
|
|
***************************************************************************/
|
|
bool DCD::FCmdPack(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
CKI cki;
|
|
bool fPack;
|
|
|
|
if (fselCki != _sel.GrfselGetCkiKid(&cki, pvNil))
|
|
return fFalse;
|
|
|
|
fPack = !_pcfl->FPacked(cki.ctg, cki.cno);
|
|
if (cidPack == pcmd->cid)
|
|
{
|
|
// actually pack or unpack the data
|
|
if (fPack ? _pcfl->FPackData(cki.ctg, cki.cno) :
|
|
_pcfl->FUnpackData(cki.ctg, cki.cno))
|
|
{
|
|
InvalAllDcd(_pdocb, _pcfl, &cki);
|
|
}
|
|
else
|
|
{
|
|
vpappb->TGiveAlertSz(
|
|
fPack ?
|
|
PszLit("Packing failed - chunk may be incompressible...") :
|
|
PszLit("Unpacking failed - chunk may be corrupt"),
|
|
bkOk, cokExclamation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// just toggle the packed flag
|
|
_pcfl->SetPacked(cki.ctg, cki.cno, fPack);
|
|
InvalAllDcd(_pdocb, _pcfl, &cki);
|
|
}
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Run a script. Make the crf cache cbCache large.
|
|
***************************************************************************/
|
|
bool DCD::FTestScript(CTG ctg, CNO cno, long cbCache)
|
|
{
|
|
AssertThis(0);
|
|
AssertIn(cbCache, 0, kcbMax);
|
|
STN stn;
|
|
PTSCG ptscg;
|
|
PSCPT pscpt = pvNil;
|
|
PSCEG psceg = pvNil;
|
|
PCRF pcrf = pvNil;
|
|
|
|
GCB gcb(khidMdi, GOB::PgobScreen());
|
|
if (pvNil == (ptscg = NewObj TSCG(&gcb)))
|
|
goto LFail;
|
|
vpcex->FAddCmh(ptscg, 0);
|
|
|
|
stn.FFormatSz(PszLit("Run Script: %f %08x"), ctg, cno);
|
|
if (!ptscg->FCreateAndAttachMdi(&stn) ||
|
|
pvNil == (pcrf = CRF::PcrfNew(_pcfl, cbCache)) ||
|
|
pvNil == (psceg = ptscg->PscegNew(pcrf, ptscg)) ||
|
|
pvNil == (pscpt = (PSCPT)pcrf->PbacoFetch(ctg, cno, SCPT::FReadScript)) ||
|
|
!psceg->FRunScript(pscpt))
|
|
{
|
|
LFail:
|
|
vpappb->TGiveAlertSz(PszLit("Running script failed"),
|
|
bkOk, cokExclamation);
|
|
}
|
|
|
|
ReleasePpo(&psceg);
|
|
ReleasePpo(&pcrf);
|
|
ReleasePpo(&pscpt);
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Disassemble a script and display it in a new window.
|
|
***************************************************************************/
|
|
bool DCD::FCmdDisasmScript(PCMD pcmd)
|
|
{
|
|
CKI cki;
|
|
PSCPT pscpt;
|
|
SCCG sccg;
|
|
FNI fni;
|
|
MSFIL msfil, msfilError;
|
|
|
|
if (fselCki != _sel.GrfselGetCkiKid(&cki, pvNil))
|
|
return fFalse;
|
|
|
|
if (pvNil == (pscpt = SCPT::PscptRead(_pcfl, cki.ctg, cki.cno)))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Error reading script (or it's not a script)"),
|
|
bkOk, cokExclamation);
|
|
return fTrue;
|
|
}
|
|
|
|
if (!sccg.FDisassemble(pscpt, &msfil, &msfilError))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Error disassembling script"),
|
|
bkOk, cokExclamation);
|
|
OpenSinkDoc(&msfilError);
|
|
}
|
|
else
|
|
OpenSinkDoc(&msfil);
|
|
ReleasePpo(&pscpt);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Copy the selection to a new document.
|
|
***************************************************************************/
|
|
bool DCD::_FCopySel(PDOCB *ppdocb)
|
|
{
|
|
AssertNilOrVarMem(ppdocb);
|
|
CKI cki;
|
|
PDOC pdoc;
|
|
|
|
if (fselCki != _sel.GrfselGetCkiKid(&cki, pvNil))
|
|
return fFalse;
|
|
|
|
if (pvNil == ppdocb)
|
|
return fTrue;
|
|
|
|
if (pvNil != (pdoc = DOC::PdocNew(pvNil)))
|
|
{
|
|
if (!_pcfl->FCopy(cki.ctg, cki.cno, pdoc->Pcfl(), &cki.cno))
|
|
ReleasePpo(&pdoc);
|
|
}
|
|
|
|
*ppdocb = pdoc;
|
|
return pvNil != *ppdocb;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Delete the current selection.
|
|
***************************************************************************/
|
|
void DCD::_ClearSel(void)
|
|
{
|
|
ulong grfsel;
|
|
CMD cmd;
|
|
|
|
grfsel = _sel.GrfselGetCkiKid(pvNil, pvNil);
|
|
if (!(grfsel & fselCki))
|
|
return;
|
|
ClearPb(&cmd, size(cmd));
|
|
cmd.pcmh = this;
|
|
if (grfsel & fselKid)
|
|
cmd.cid = cidUnadoptChunk;
|
|
else
|
|
cmd.cid = cidDeleteChunk;
|
|
FDoCmd(&cmd);
|
|
ReleasePpo(&cmd.pgg);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Paste all non-child chunk of the given document into the current document.
|
|
REVIEW shonk: should this delete the current selection?
|
|
REVIEW shonk: is there an easy way to make this atomic?
|
|
***************************************************************************/
|
|
bool DCD::_FPaste(PCLIP pclip, bool fDoIt, long cid)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pclip, 0);
|
|
PDOC pdoc;
|
|
PCFL pcfl;
|
|
long icki;
|
|
CKI cki, ckiSel;
|
|
bool fFailed = fFalse;
|
|
|
|
if (!pclip->FGetFormat(kclsDOC))
|
|
return fFalse;
|
|
|
|
if (!fDoIt)
|
|
return fTrue;
|
|
|
|
if (!pclip->FGetFormat(kclsDOC, (PDOCB *)&pdoc))
|
|
return fFalse;
|
|
|
|
if (pvNil == (pcfl = pdoc->Pcfl()) || pcfl->Ccki() <= 0)
|
|
{
|
|
ReleasePpo(&pdoc);
|
|
return fTrue;
|
|
}
|
|
|
|
_SetSel(lnNil);
|
|
for (icki = 0; pcfl->FGetCki(icki, &cki); icki++)
|
|
{
|
|
if (!pcfl->FLoner(cki.ctg, cki.cno))
|
|
continue;
|
|
if (cid == cidPasteSpecial)
|
|
fFailed |= !pcfl->FClone(cki.ctg, cki.cno, _pcfl, &ckiSel.cno);
|
|
else
|
|
fFailed |= !pcfl->FCopy(cki.ctg, cki.cno, _pcfl, &ckiSel.cno);
|
|
ckiSel.ctg = cki.ctg;
|
|
}
|
|
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
ReleasePpo(&pdoc);
|
|
|
|
if (fFailed)
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Couldn't paste everything"),
|
|
bkOk, cokExclamation);
|
|
}
|
|
else
|
|
{
|
|
_SetSel(lnNil, &ckiSel);
|
|
_ShowSel();
|
|
}
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Use the selected chunk as the current color table.
|
|
***************************************************************************/
|
|
bool DCD::FCmdSetColorTable(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
CKI cki;
|
|
BLCK blck;
|
|
PGL pglclr;
|
|
|
|
if (fselCki != _sel.GrfselGetCkiKid(&cki, pvNil))
|
|
return fFalse;
|
|
if (!_pcfl->FFind(cki.ctg, cki.cno, &blck))
|
|
return fFalse;
|
|
|
|
if (pvNil != (pglclr = GL::PglRead(&blck)) && pglclr->CbEntry() == size(CLR))
|
|
GPT::SetActiveColors(pglclr, fpalIdentity);
|
|
|
|
ReleasePpo(&pglclr);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
|
|
enum
|
|
{
|
|
kiditOkFilter,
|
|
kiditCancelFilter,
|
|
kiditHideKidsFilter,
|
|
kiditHideListFilter,
|
|
kiditCtgEditFilter,
|
|
kiditLimFilter,
|
|
};
|
|
|
|
|
|
/***************************************************************************
|
|
Change the filtering.
|
|
***************************************************************************/
|
|
bool DCD::FCmdFilterChunk(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
STN stn;
|
|
STN stnT;
|
|
PDLG pdlg;
|
|
ulong grfsel;
|
|
CKI cki;
|
|
KID kid;
|
|
CTG ctg;
|
|
long ictg;
|
|
achar *prgch;
|
|
achar chQuote, *psz;
|
|
|
|
grfsel = _sel.GrfselGetCkiKid(&cki, &kid);
|
|
_SetSel(lnNil);
|
|
|
|
//put up the dialog
|
|
pdlg = DLG::PdlgNew(dlidFilter);
|
|
if (pvNil == pdlg)
|
|
goto LCancel;
|
|
|
|
stn.SetNil();
|
|
for (ictg = 0; _sel.FGetCtgFilter(ictg, &ctg); ictg++)
|
|
{
|
|
stnT.FFormatSz(PszLit("'%f'"), ctg);
|
|
if (stn.Cch() > 0)
|
|
stn.FAppendCh(kchSpace);
|
|
stn.FAppendStn(&stnT);
|
|
}
|
|
|
|
pdlg->FPutStn(kiditCtgEditFilter, &stn);
|
|
pdlg->PutCheck(kiditHideKidsFilter, _sel.FHideKids());
|
|
pdlg->PutCheck(kiditHideListFilter, _sel.FHideList());
|
|
|
|
if (kiditOkFilter != pdlg->IditDo(kiditCtgEditFilter))
|
|
goto LCancel;
|
|
|
|
// set the filtering on the sel
|
|
_sel.HideKids(pdlg->FGetCheck(kiditHideKidsFilter));
|
|
_sel.HideList(pdlg->FGetCheck(kiditHideListFilter));
|
|
|
|
pdlg->GetStn(kiditCtgEditFilter, &stn);
|
|
_sel.FreeFilterList();
|
|
for (psz = stn.Psz(); ; )
|
|
{
|
|
while (*psz == kchSpace)
|
|
psz++;
|
|
if (!*psz)
|
|
break;
|
|
|
|
stnT.SetNil();
|
|
chQuote = 0;
|
|
while (*psz && (chQuote != 0 || *psz != kchSpace))
|
|
{
|
|
if (chQuote == 0 && (*psz == ChLit('"') || *psz == ChLit('\'')))
|
|
chQuote = *psz;
|
|
if (*psz == chQuote)
|
|
chQuote = 0;
|
|
else
|
|
stnT.FAppendCh(*psz);
|
|
psz++;
|
|
}
|
|
|
|
if (stnT.Cch() == 0)
|
|
continue;
|
|
|
|
while (stnT.Cch() < 4)
|
|
stnT.FAppendCh(kchSpace);
|
|
prgch = stnT.Psz();
|
|
ctg = LwFromBytes((byte)prgch[0], (byte)prgch[1], (byte)prgch[2],
|
|
(byte)prgch[3]);
|
|
_sel.FAddCtgFilter(ctg);
|
|
}
|
|
|
|
LCancel:
|
|
ReleasePpo(&pdlg);
|
|
_InvalCkiKid();
|
|
_SetSel(lnNil, (grfsel & fselCki) ? &cki : pvNil,
|
|
(grfsel & fselKid) ? &kid : pvNil);
|
|
_ShowSel();
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Clone a chunk and its subgraph
|
|
***************************************************************************/
|
|
bool DCD::FCmdCloneChunk(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
CKI cki, ckiNew;
|
|
|
|
if (fselCki != _sel.GrfselGetCkiKid(&cki, pvNil))
|
|
goto LFail;
|
|
|
|
_SetSel(lnNil);
|
|
ckiNew.ctg = cki.ctg;
|
|
if (!_pcfl->FClone(cki.ctg, cki.cno, _pcfl, &ckiNew.cno))
|
|
{
|
|
_SetSel(lnNil, &cki);
|
|
vpappb->TGiveAlertSz(PszLit("Cloning failed"), bkOk, cokExclamation);
|
|
LFail:
|
|
pcmd->cid = cidNil; // don't record
|
|
return fTrue;
|
|
}
|
|
|
|
InvalAllDcd(_pdocb, _pcfl);
|
|
_SetSel(lnNil, &ckiNew);
|
|
_ShowSel();
|
|
return fTrue;
|
|
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Assert the validity of an object.
|
|
***************************************************************************/
|
|
void DCD::AssertValid(ulong grf)
|
|
{
|
|
DCD_PAR::AssertValid(0);
|
|
AssertPo(&_sel, 0);
|
|
AssertPo(_pcfl, 0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Mark memory for the DCD.
|
|
***************************************************************************/
|
|
void DCD::MarkMem(void)
|
|
{
|
|
AssertValid(0);
|
|
DCD_PAR::MarkMem();
|
|
_sel.MarkMem();
|
|
}
|
|
#endif //DEBUG
|
|
|
|
|
|
/***************************************************************************
|
|
Parses the stn as a ctg. Pads with spaces. Fails if pstn is longer
|
|
than 4 characters or empty.
|
|
***************************************************************************/
|
|
bool FGetCtgFromStn(CTG *pctg, PSTN pstn)
|
|
{
|
|
achar rgch[4];
|
|
|
|
AssertVarMem(pctg);
|
|
AssertPo(pstn, 0);
|
|
|
|
if (!FIn(pstn->Cch(), 1, 5))
|
|
{
|
|
TrashVar(pctg);
|
|
return fFalse;
|
|
}
|
|
rgch[0] = rgch[1] = rgch[2] = rgch[3] = kchSpace;
|
|
CopyPb(pstn->Psz(), rgch, pstn->Cch() * size(achar));
|
|
|
|
//first character becomes the high byte
|
|
*pctg = LwFromBytes((byte)rgch[0], (byte)rgch[1], (byte)rgch[2],
|
|
(byte)rgch[3]);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the indicated edit item from the dialog and convert it to a CTG.
|
|
Pads with spaces. Fails if the text in the edit item is longer
|
|
than 4 characters or empty.
|
|
***************************************************************************/
|
|
bool _FGetCtg(PDLG pdlg, long idit, CTG *pctg)
|
|
{
|
|
AssertPo(pdlg, 0);
|
|
AssertVarMem(pctg);
|
|
STN stn;
|
|
|
|
pdlg->GetStn(idit, &stn);
|
|
return FGetCtgFromStn(pctg, &stn);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Put the ctg into the indicated edit item.
|
|
***************************************************************************/
|
|
void _PutCtgStn(PDLG pdlg, long idit, CTG ctg)
|
|
{
|
|
AssertPo(pdlg, 0);
|
|
STN stn;
|
|
|
|
stn.FFormatSz(PszLit("%f"), ctg);
|
|
pdlg->FPutStn(idit, &stn);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Constructor for SEL class.
|
|
***************************************************************************/
|
|
SEL::SEL(PCFL pcfl)
|
|
{
|
|
AssertPo(pcfl, 0);
|
|
_pcfl = pcfl;
|
|
_lnLim = lnNil;
|
|
_pglctg = pvNil;
|
|
_SetNil();
|
|
AssertThis(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Constructor for a selection based on another selection. If the source
|
|
selection is filtered, this selection will share the same filter list.
|
|
***************************************************************************/
|
|
SEL::SEL(SEL &selT)
|
|
{
|
|
_pglctg = pvNil;
|
|
*this = selT;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Destructor for a selection. Release the GL of ctg's to filter on.
|
|
***************************************************************************/
|
|
SEL::~SEL(void)
|
|
{
|
|
ReleasePpo(&_pglctg);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Assignment operator from one selection to another. If the source
|
|
selection is filtered, this selection will share the same filter list.
|
|
***************************************************************************/
|
|
SEL & SEL::operator = (SEL &selT)
|
|
{
|
|
PGL pglctgOld = _pglctg;
|
|
|
|
SEL_PAR::operator=(selT);
|
|
CopyPb(PvAddBv(&selT, size(SEL_PAR)), PvAddBv(this, size(SEL_PAR)),
|
|
size(SEL) - size(SEL_PAR));
|
|
if (pvNil != _pglctg)
|
|
_pglctg->AddRef();
|
|
ReleasePpo(&pglctgOld);
|
|
return *this;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Set the selection to a nil selection.
|
|
***************************************************************************/
|
|
void SEL::_SetNil(void)
|
|
{
|
|
_icki = ivNil;
|
|
_ikid = ivNil;
|
|
_ln = lnNil;
|
|
AssertThis(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the cki and kid. Return which of the elements are valid. One or
|
|
both of pcki, pkid may be nil.
|
|
***************************************************************************/
|
|
ulong SEL::GrfselGetCkiKid(CKI *pcki, KID *pkid)
|
|
{
|
|
AssertThis(0);
|
|
AssertNilOrVarMem(pcki);
|
|
AssertNilOrVarMem(pkid);
|
|
|
|
TrashVar(pcki);
|
|
TrashVar(pkid);
|
|
if (ivNil == _icki)
|
|
return fselNil;
|
|
if (pvNil != pcki)
|
|
*pcki = _cki;
|
|
if (ivNil == _ikid)
|
|
return fselCki;
|
|
if (pvNil != pkid)
|
|
*pkid = _kid;
|
|
return fselCki | fselKid;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Set the selection to the given line. Return true iff the resulting
|
|
selection is not nil.
|
|
***************************************************************************/
|
|
bool SEL::FSetLn(long ln)
|
|
{
|
|
AssertThis(0);
|
|
Assert(ln == lnNil || ln >= 0 && ln < kcbMax, "bad ln");
|
|
|
|
if (ln == _ln)
|
|
return fTrue;
|
|
|
|
if (lnNil == ln || lnNil != _lnLim && ln >= _lnLim)
|
|
{
|
|
_SetNil();
|
|
return fFalse;
|
|
}
|
|
|
|
if (_ln > ln)
|
|
{
|
|
if (_ln - ln < ln)
|
|
{
|
|
// move backwards
|
|
SuspendAssertValid();
|
|
SuspendCheckPointers();
|
|
while (_ln > ln)
|
|
AssertDo(FRetreat(), 0);
|
|
ResumeAssertValid();
|
|
ResumeCheckPointers();
|
|
return fTrue;
|
|
}
|
|
_SetNil();
|
|
}
|
|
|
|
Assert(_ln < ln, "what?");
|
|
SuspendAssertValid();
|
|
SuspendCheckPointers();
|
|
while (_ln < ln)
|
|
{
|
|
if (!FAdvance())
|
|
return fFalse;
|
|
}
|
|
ResumeCheckPointers();
|
|
ResumeAssertValid();
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the number of active lines in the sel.
|
|
***************************************************************************/
|
|
long SEL::LnLim(void)
|
|
{
|
|
AssertThis(0);
|
|
|
|
if (lnNil == _lnLim)
|
|
{
|
|
SEL sel = *this;
|
|
|
|
_lnLim = (lnNil == _ln) ? 0 : _ln + 1;
|
|
SuspendAssertValid();
|
|
SuspendCheckPointers();
|
|
while (sel.FAdvance())
|
|
_lnLim++;
|
|
ResumeAssertValid();
|
|
ResumeCheckPointers();
|
|
}
|
|
return _lnLim;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Advance the selection to the next item. If the selection is nil,
|
|
advances it to the first item. Returns false and makes the selection
|
|
nil iff there is no next item.
|
|
***************************************************************************/
|
|
bool SEL::FAdvance(void)
|
|
{
|
|
AssertThis(0);
|
|
|
|
if (lnNil == _ln)
|
|
{
|
|
_ln = 0;
|
|
_icki = 0;
|
|
}
|
|
else
|
|
{
|
|
_ln++;
|
|
if (!_fHideKids)
|
|
{
|
|
// check for the next child
|
|
for (_ikid = (ivNil == _ikid) ? 0 : _ikid + 1;
|
|
_pcfl->FGetKid(_cki.ctg, _cki.cno, _ikid, &_kid); _ikid++)
|
|
{
|
|
if (_FFilter(_kid.cki.ctg, _kid.cki.cno))
|
|
return fTrue;
|
|
}
|
|
}
|
|
_icki++;
|
|
}
|
|
|
|
_ikid = ivNil;
|
|
for ( ; _pcfl->FGetCki(_icki, &_cki); _icki++)
|
|
{
|
|
if (_FFilter(_cki.ctg, _cki.cno))
|
|
return fTrue;
|
|
}
|
|
|
|
_SetNil();
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Move the selection to the previous item. If the selection is nil or
|
|
at the first item, this sets the selection nil and returns false.
|
|
***************************************************************************/
|
|
bool SEL::FRetreat(void)
|
|
{
|
|
AssertThis(0);
|
|
|
|
if (lnNil == _ln)
|
|
return fFalse;
|
|
if (0 == _ln)
|
|
goto LSetNil;
|
|
|
|
_ln--;
|
|
if (ivNil == _ikid)
|
|
{
|
|
// find the previous cki
|
|
do
|
|
{
|
|
if (_icki-- <= 0)
|
|
{
|
|
Bug("initial _ln was wrong");
|
|
LSetNil:
|
|
_SetNil();
|
|
return fFalse;
|
|
}
|
|
AssertDo(_pcfl->FGetCki(_icki, &_cki, &_ikid), 0);
|
|
}
|
|
while (!_FFilter(_cki.ctg, _cki.cno));
|
|
|
|
if (_ikid == 0 || _fHideKids)
|
|
{
|
|
_ikid = ivNil;
|
|
return fTrue;
|
|
}
|
|
}
|
|
|
|
//move to the previous child
|
|
while (--_ikid >= 0)
|
|
{
|
|
AssertDo(_pcfl->FGetKid(_cki.ctg, _cki.cno, _ikid, &_kid), 0);
|
|
if (_FFilter(_kid.cki.ctg, _kid.cki.cno))
|
|
return fTrue;
|
|
}
|
|
_ikid = ivNil;
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Set the selection to represent *pcki, *pkid. pkid may be nil. If
|
|
fExact is false, this sets the sel to the last item at or before
|
|
the given (pcki, pkid).
|
|
***************************************************************************/
|
|
bool SEL::FSetCkiKid(CKI *pcki, KID *pkid, bool fExact)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcki);
|
|
AssertNilOrVarMem(pkid);
|
|
|
|
_cki = *pcki;
|
|
_icki = 0;
|
|
if (pvNil == pkid)
|
|
_ikid = ivNil;
|
|
else
|
|
{
|
|
_kid = *pkid;
|
|
_ikid = 0;
|
|
}
|
|
_ln = 0;
|
|
|
|
Adjust(fExact);
|
|
AssertThis(0);
|
|
return ivNil != _icki;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Adjust the sel after an edit to the doc. Assume icki and ikid are wrong
|
|
(except as indicators of invalid cki and kid fields), and assume ln
|
|
is wrong. If fExact is false and the current (cki, kid) is no longer
|
|
in the CFL or our filtering on it, we select the item immediately before
|
|
where this one would be.
|
|
***************************************************************************/
|
|
void SEL::Adjust(bool fExact)
|
|
{
|
|
AssertPo(_pcfl, 0);
|
|
long icki, ikid;
|
|
|
|
if (ivNil == _icki)
|
|
goto LSetNil;
|
|
|
|
// get the icki and ikid
|
|
if (!_pcfl->FGetIcki(_cki.ctg, _cki.cno, &icki) ||
|
|
!_FFilter(_cki.ctg, _cki.cno))
|
|
{
|
|
if (fExact)
|
|
goto LSetNil;
|
|
ikid = ivNil;
|
|
}
|
|
else if (ivNil != (ikid = _ikid))
|
|
{
|
|
if (_fHideKids)
|
|
{
|
|
if (fExact)
|
|
goto LSetNil;
|
|
ikid = ivNil;
|
|
}
|
|
else if (!_pcfl->FGetIkid(_cki.ctg, _cki.cno, _kid.cki.ctg, _kid.cki.cno,
|
|
_kid.chid, &ikid) && fExact)
|
|
{
|
|
LSetNil:
|
|
_SetNil();
|
|
return;
|
|
}
|
|
}
|
|
|
|
// find the icki and ikid
|
|
_SetNil();
|
|
SEL sel = *this;
|
|
|
|
SuspendAssertValid();
|
|
SuspendCheckPointers();
|
|
while (sel.FAdvance())
|
|
{
|
|
if (sel._icki >= icki && (sel._icki > icki || sel._ikid > ikid))
|
|
break;
|
|
*this = sel;
|
|
}
|
|
ResumeAssertValid();
|
|
ResumeCheckPointers();
|
|
|
|
if (fExact && (_icki != icki || _ikid != ikid))
|
|
_SetNil();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Hide or show children according to fHide.
|
|
***************************************************************************/
|
|
void SEL::HideKids(bool fHide)
|
|
{
|
|
AssertThis(0);
|
|
|
|
if (FPure(fHide) == _fHideKids)
|
|
return;
|
|
_fHideKids = FPure(fHide);
|
|
Adjust();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Hide or show the filter list according to fHide.
|
|
***************************************************************************/
|
|
void SEL::HideList(bool fHide)
|
|
{
|
|
AssertThis(0);
|
|
|
|
if (FPure(fHide) == _fHideList)
|
|
return;
|
|
_fHideList = FPure(fHide);
|
|
Adjust();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the ictg'th ctg that we're filtering on.
|
|
***************************************************************************/
|
|
bool SEL::FGetCtgFilter(long ictg, CTG *pctg)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pctg);
|
|
|
|
if (pvNil == _pglctg || !FIn(ictg, 0, _pglctg->IvMac()))
|
|
return fFalse;
|
|
_pglctg->Get(ictg, pctg);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Reset the filter list to be empty.
|
|
***************************************************************************/
|
|
void SEL::FreeFilterList(void)
|
|
{
|
|
AssertThis(0);
|
|
|
|
if (pvNil != _pglctg)
|
|
{
|
|
ReleasePpo(&_pglctg);
|
|
Adjust();
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Add an element to the filter list.
|
|
***************************************************************************/
|
|
bool SEL::FAddCtgFilter(CTG ctg)
|
|
{
|
|
AssertThis(0);
|
|
|
|
if (pvNil == _pglctg && pvNil == (_pglctg = GL::PglNew(size(CTG), 1)))
|
|
return fFalse;
|
|
if (!_pglctg->FAdd(&ctg))
|
|
return fFalse;
|
|
Adjust();
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return true iff (ctg, cno) passes our filtering criteria.
|
|
***************************************************************************/
|
|
bool SEL::_FFilter(CTG ctg, CNO cno)
|
|
{
|
|
long cctg;
|
|
CTG *qctg;
|
|
|
|
if (pvNil == _pglctg || 0 == (cctg = _pglctg->IvMac()))
|
|
return fTrue;
|
|
|
|
for (qctg = (CTG *)_pglctg->QvGet(0); cctg-- > 0; qctg++)
|
|
{
|
|
if (*qctg == ctg)
|
|
return !_fHideList;
|
|
}
|
|
|
|
return _fHideList;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Assert the validity of the sel.
|
|
***************************************************************************/
|
|
void SEL::AssertValid(ulong grf)
|
|
{
|
|
SEL_PAR::AssertValid(0);
|
|
AssertPo(_pcfl, 0);
|
|
Assert((_ln == lnNil) == (_icki == ivNil && _ikid == ivNil),
|
|
"nil values not in sync");
|
|
AssertNilOrPo(_pglctg, 0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Mark memory for the SEL.
|
|
***************************************************************************/
|
|
void SEL::MarkMem(void)
|
|
{
|
|
AssertValid(0);
|
|
SEL_PAR::MarkMem();
|
|
MarkMemObj(_pglctg);
|
|
}
|
|
#endif //DEBUG
|