/* Copyright (c) Microsoft Corporation. Licensed under the MIT License. */ /*************************************************************************** Help authoring tool. ***************************************************************************/ #include "chelp.h" ASSERTNAME BEGIN_CMD_MAP(APP, APPB) ON_CID_GEN(cidNew, &APP::FCmdOpen, pvNil) ON_CID_GEN(cidOpen, &APP::FCmdOpen, pvNil) ON_CID_GEN(cidOpenText, &APP::FCmdOpen, pvNil) ON_CID_GEN(cidOpenRichText, &APP::FCmdOpen, pvNil) ON_CID_GEN(cidLoadResFile, &APP::FCmdLoadResFile, pvNil) ON_CID_GEN(cidChooseLanguage, &APP::FCmdChooseLanguage, &APP::FEnableChooseLanguage) END_CMD_MAP_NIL() BEGIN_CMD_MAP(LIG, GOB) ON_CID_ME(cidDoScroll, FCmdScroll, pvNil) ON_CID_ME(cidEndScroll, FCmdScroll, pvNil) END_CMD_MAP_NIL() APP vapp; RTCLASS(APP) RTCLASS(LIG) RTCLASS(LID) RTCLASS(CCG) RTCLASS(CCGT) STRG _strg; PSTRG vpstrg; SC_LID vsclid = ksclidAmerican; PSPLC vpsplc; /*************************************************************************** Main for a frame app. ***************************************************************************/ void FrameMain(void) { vpstrg = &_strg; vapp.Run(fappNil, fgobNil, kginDefault); ReleasePpo(&vpsplc); } #ifdef DEBUG /*************************************************************************** Assert the validity of a APP. ***************************************************************************/ void APP::AssertValid(ulong grf) { APP_PAR::AssertValid(0); AssertNilOrPo(_pcrm, 0); AssertNilOrPo(_plidPicture, 0); AssertNilOrPo(_plidButton, 0); } /*************************************************************************** Mark memory for the APP. ***************************************************************************/ void APP::MarkMem(void) { AssertValid(0); APP_PAR::MarkMem(); MarkMemObj(_pcrm); MarkMemObj(_plidPicture); MarkMemObj(_plidButton); MarkMemObj(&_strg); MarkMemObj(vpsplc); } #endif //DEBUG /*************************************************************************** Initialize the app. Add some stuff to the menus and do the command line parsing thing. ***************************************************************************/ bool APP::_FInit(ulong grfapp, ulong grfgob, long ginDef) { static long _rgdypFont[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 28, 32, 36, 0 }; struct LANG { PSZ psz; long sclid; }; static LANG _rglang[] = { { PszLit("American"), ksclidAmerican }, { PszLit("Australian"), ksclidAustralian }, { PszLit("British"), ksclidBritish }, { PszLit("German"), ksclidGerman }, { PszLit("Swiss German"), ksclidSwissGerman }, { PszLit("French"), ksclidFrench }, { PszLit("French Canadian"), ksclidFrenchCanadian }, { PszLit("Spanish"), ksclidSpanish }, { PszLit("Catalan"), ksclidCatalan }, { PszLit("Italian"), ksclidItalian }, { PszLit("Other..."), 0 }, }; long iv, dyp; STN stn; if (!APP_PAR::_FInit(grfapp, grfgob, ginDef)) return fFalse; vpmubCur->FRemoveAllListCid(cidChooseFontSize); stn = PszLit("Other..."); vpmubCur->FAddListCid(cidChooseFontSize, 0, &stn); for (iv = 0; (dyp = _rgdypFont[iv]) != 0; iv++) { stn.FFormatSz(PszLit("%d"), dyp); vpmubCur->FAddListCid(cidChooseFontSize, dyp, &stn); } for (iv = 0; iv < CvFromRgv(_rglang); iv++) { stn = _rglang[iv].psz; vpmubCur->FAddListCid(cidChooseLanguage, _rglang[iv].sclid, &stn); } #ifdef WIN //parse the command line and load any resource files and help files FNI fni; bool fQuote, fRes, fSkip; PSZ psz = vwig.pszCmdLine; // skip the first token since it is the path fSkip = fTrue; fRes = fFalse; for (;;) { while (*psz == kchSpace) psz++; if (!*psz) break; stn.SetNil(); fQuote = fFalse; while (*psz && (fQuote || *psz != kchSpace)) { if (*psz == ChLit('"')) fQuote = !fQuote; else stn.FAppendCh(*psz); psz++; } if (stn.Cch() == 0) continue; if (fSkip) { fSkip = fFalse; continue; } if (stn.Cch() == 2 && (stn.Psz()[0] == ChLit('/') || stn.Psz()[0] == ChLit('-'))) { // command line switch switch (stn.Psz()[1]) { case ChLit('r'): case ChLit('R'): fRes = fTrue; break; } continue; } if (!fni.FBuildFromPath(&stn) || fni.Ftg() == kftgDir) { fRes = fFalse; continue; } if (fRes) FLoadResFile(&fni); else FOpenDocFile(&fni); fRes = fFalse; } #endif //WIN return fTrue; } /*************************************************************************** Get the name for the help editor app. ***************************************************************************/ void APP::GetStnAppName(PSTN pstn) { AssertThis(0); AssertPo(pstn, 0); #ifdef UNICODE STN stnDate; STN stnTime; stnDate.SetSzs(__DATE__); stnTime.SetSzs(__TIME__); pstn->FFormatSz(Debug(PszLit("Debug ")) PszLit("Chelp (Unicode; %s; %s)"), &stnDate, &stnTime); #else //!UNICODE *pstn = Debug("Debug ") "Chelp (Ansi; " __DATE__ "; " __TIME__ ")"; #endif //!UNICODE } /*************************************************************************** Update the given window. *prc is the bounding rectangle of the update region. ***************************************************************************/ void APP::UpdateHwnd(HWND hwnd, RC *prc, ulong grfapp) { AssertThis(0); PGOB pgob; if (pvNil == (pgob = GOB::PgobFromHwnd(hwnd))) return; //for text windows, do offscreen updating if (pgob->FIs(kclsDMD) && ((PDMD)pgob)->Pdocb()->FIs(kclsTXRD)) grfapp |= fappOffscreen; APP_PAR::UpdateHwnd(hwnd, prc, grfapp); } /*************************************************************************** Do a fast update of the gob and its descendents into the given gpt. ***************************************************************************/ void APP::_FastUpdate(PGOB pgob, PREGN pregnClip, ulong grfapp, PGPT pgpt) { AssertThis(0); //for text windows, do offscreen updating if (pgob->FIs(kclsDMD) && ((PDMD)pgob)->Pdocb()->FIs(kclsTXRD)) grfapp |= fappOffscreen; APP_PAR::_FastUpdate(pgob, pregnClip, grfapp, pgpt); } /*************************************************************************** Open an existing or new chunky file for editing. Handles cidNew and cidOpen. ***************************************************************************/ bool APP::FCmdOpen(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); FNI fni; FNI *pfni; pfni = pvNil; switch (pcmd->cid) { default: Bug("why are we here?"); return fTrue; case cidOpen: //do the standard dialog if (!FGetFniOpenMacro(&fni, pvNil, 0, PszLit("Kid Help Files\0*.khp;*.chk\0All Files\0*.*\0"), vwig.hwndApp)) { return fTrue; } pfni = &fni; break; case cidOpenText: //do the standard dialog if (!FGetFniOpenMacro(&fni, pvNil, 0, PszLit("Text files\0*.txt\0All Files\0*.*\0"), vwig.hwndApp)) { return fTrue; } pfni = &fni; break; case cidOpenRichText: //do the standard dialog if (!FGetFniOpenMacro(&fni, pvNil, 0, PszLit("Rich Text files\0*.rtx\0All Files\0*.*\0"), vwig.hwndApp)) { return fTrue; } pfni = &fni; break; case cidNew: break; } FOpenDocFile(pfni, pcmd->cid); return fTrue; } /*************************************************************************** Load a document file. ***************************************************************************/ bool APP::FOpenDocFile(PFNI pfni, long cid) { AssertThis(0); AssertNilOrPo(pfni, 0); bool fRet; PDOCB pdocb; PHEDO phedo; PTXRD ptxrd; if (pvNil != pfni && pvNil != (pdocb = DOCB::PdocbFromFni(pfni))) { pdocb->ActivateDmd(); return fTrue; } pdocb = pvNil; switch (cid) { case cidOpenText: if (pvNil == (ptxrd = TXRD::PtxrdNew(pvNil))) return fFalse; fRet = fFalse; if (pvNil != pfni) { FLO flo; if (pvNil == (flo.pfil = FIL::PfilOpen(pfni))) goto LFail; flo.fp = 0; flo.cb = flo.pfil->FpMac(); fRet = ptxrd->FReplaceFlo(&flo, fTrue, 0, 0); ReleasePpo(&flo.pfil); if (!fRet) { LFail: ReleasePpo(&ptxrd); return fFalse; } } pdocb = ptxrd; break; case cidOpenRichText: if (pvNil == (pdocb = TXRD::PtxrdNew(pfni))) return fFalse; break; default: if (pvNil == _pcrm && pvNil == (_pcrm = CRM::PcrmNew(1))) return fFalse; if (pvNil == _plidPicture && pvNil == (_plidPicture = LID::PlidNew(_pcrm, kctgMbmp))) { return fFalse; } if (pvNil == _plidButton && pvNil == (_plidButton = LID::PlidNew(_pcrm, kctgGokd, ChidFromSnoDchid(ksnoInit, 0)))) { return fFalse; } phedo = HEDO::PhedoNew(pfni, _pcrm); if (pvNil == phedo) return fFalse; pdocb = phedo; break; } fRet = (pdocb->PdmdNew() != pvNil); ReleasePpo(&pdocb); return fRet; } /*************************************************************************** Open an existing or new chunky file for editing. Handles cidNew and cidOpen. ***************************************************************************/ bool APP::FCmdLoadResFile(PCMD pcmd) { AssertThis(0); AssertVarMem(pcmd); FNI fni; if (!FGetFniOpenMacro(&fni, pvNil, 0, PszLit("Chunky Resource Files\0*.chk\0All Files\0*.*\0"), vwig.hwndApp)) { return fTrue; } FLoadResFile(&fni); return fTrue; } /*************************************************************************** Load a resource file. ***************************************************************************/ bool APP::FLoadResFile(PFNI pfni) { AssertThis(0); AssertPo(pfni, ffniFile); PCFL pcfl; long ipcrf; PCRF pcrf; BLCK blck; if (pvNil == _pcrm && pvNil == (_pcrm = CRM::PcrmNew(1))) return fFalse; if (pvNil == (pcfl = CFL::PcflOpen(pfni, fcflNil))) { vpappb->TGiveAlertSz(PszLit("Can't open that file"), bkOk, cokStop); return fFalse; } //see if it's already in the crm. for (ipcrf = _pcrm->Ccrf(); ipcrf-- > 0; ) { pcrf = _pcrm->PcrfGet(ipcrf); if (pcfl == pcrf->Pcfl()) return fTrue; } if (!_pcrm->FAddCfl(pcfl, 0x100000L)) { ReleasePpo(&pcfl); return fFalse; } if (pcfl->FGetCkiCtg(kctgColorTable, 0, pvNil, pvNil, &blck)) { PGL pglclr; if (pvNil != (pglclr = GL::PglRead(&blck)) && pglclr->CbEntry() == size(CLR)) { GPT::SetActiveColors(pglclr, fpalIdentity); } ReleasePpo(&pglclr); } ReleasePpo(&pcfl); if (pvNil != _plidPicture) _plidPicture->FRefresh(); if (pvNil != _plidButton) _plidButton->FRefresh(); return fTrue; } /*************************************************************************** Check or uncheck the language as appropriate. ***************************************************************************/ bool APP::FEnableChooseLanguage(PCMD pcmd, ulong *pgrfeds) { AssertThis(0); AssertPo(pcmd, 0); AssertVarMem(pgrfeds); *pgrfeds = fedsEnable | fedsUncheck; if (vsclid == pcmd->rglw[0]) *pgrfeds = fedsEnable | fedsCheck; return fTrue; } enum { kiditOkLang, kiditCancelLang, kiditCodeLang, kiditLimLang }; /*************************************************************************** Command to choose the language (for spelling). ***************************************************************************/ bool APP::FCmdChooseLanguage(PCMD pcmd) { AssertThis(0); AssertPo(pcmd, 0); if (pcmd->rglw[0] == 0) { // ask the user PDLG pdlg; bool fRet; if (pvNil == (pdlg = DLG::PdlgNew(dlidFontSize))) return fTrue; pdlg->FPutLwInEdit(kiditCodeLang, vsclid); if (kiditOkLang != pdlg->IditDo(kiditCodeLang)) { ReleasePpo(&pdlg); return fFalse; } fRet = pdlg->FGetLwFromEdit(kiditCodeLang, &pcmd->rglw[0]); ReleasePpo(&pdlg); if (!fRet) return fTrue; } if ((SC_LID)pcmd->rglw[0] == vsclid) return fTrue; ReleasePpo(&vpsplc); vsclid = (SC_LID)pcmd->rglw[0]; return fTrue; } /*************************************************************************** Create a new LIG for the given help text document. ***************************************************************************/ PLIG APP::PligNew(bool fButton, PGCB pgcb, PTXHD ptxhd) { PLID plid = fButton ? _plidButton : _plidPicture; if (pvNil == plid) return pvNil; return LIG::PligNew(plid, pgcb, ptxhd); } /*************************************************************************** Constructor for the list display gob. ***************************************************************************/ LID::LID(void) : LID_PAR() { } /*************************************************************************** Desctructor for the list display gob. ***************************************************************************/ LID::~LID(void) { ReleasePpo(&_pcrm); ReleasePpo(&_pglcach); } #ifdef DEBUG /*************************************************************************** Assert the validity of a LID. ***************************************************************************/ void LID::AssertValid(ulong grf) { LID_PAR::AssertValid(0); AssertPo(_pcrm, 0); AssertPo(_pglcach, 0); } /*************************************************************************** Mark memory for the LIG. ***************************************************************************/ void LID::MarkMem(void) { AssertValid(0); LID_PAR::MarkMem(); MarkMemObj(_pcrm); MarkMemObj(_pglcach); } #endif //DEBUG /*************************************************************************** Static method to create a new list document. ***************************************************************************/ PLID LID::PlidNew(PCRM pcrm, CTG ctg, CHID chid) { AssertPo(pcrm, 0); PLID plid; if (pvNil == (plid = NewObj LID)) return pvNil; if (!plid->_FInit(pcrm, ctg, chid)) ReleasePpo(&plid); return plid; } /*************************************************************************** Initialization for the list document. ***************************************************************************/ bool LID::_FInit(PCRM pcrm, CTG ctg, CHID chid) { AssertPo(pcrm, 0); GCB gcb; if (pvNil == (_pglcach = GL::PglNew(size(CACH)))) return fFalse; _pglcach->SetMinGrow(100); _pcrm = pcrm; _pcrm->AddRef(); _ctg = ctg; _chid = chid; return FRefresh(); } /*************************************************************************** Rebuild the list and update the DDGs. The pcrm has changed. ***************************************************************************/ bool LID::FRefresh(void) { AssertThis(0); long ipcrf, icki; CACH cach, cachT; PCRF pcrf; PCFL pcfl; CKI cki; long ivMin, ivLim, iv; KID kid; long ipddg; PDDG pddg; bool fRet = fFalse; _pglcach->FSetIvMac(0); for (ipcrf = 0; ipcrf < _pcrm->Ccrf(); ipcrf++) { pcrf = _pcrm->PcrfGet(ipcrf); pcfl = pcrf->Pcfl(); for (icki = 0; pcfl->FGetCkiCtg(_ctg, icki, &cki); icki++) { cach.pcrf = pcrf; cach.cno = cach.cnoMbmp = cki.cno; if (kctgMbmp != _ctg) { if (!pcfl->FGetKidChidCtg(_ctg, cki.cno, _chid, kctgMbmp, &kid)) continue; cach.cnoMbmp = kid.cki.cno; } // determine where this cno goes. for (ivMin = 0, ivLim = _pglcach->IvMac(); ivMin < ivLim; ) { iv = (ivMin + ivLim) / 2; _pglcach->Get(iv, &cachT); if (cachT.cno < cach.cno) ivMin = iv + 1; else ivLim = iv; } if (ivMin < _pglcach->IvMac()) { _pglcach->Get(ivMin, &cachT); if (cachT.cno == cach.cno) continue; } if (!_pglcach->FInsert(ivMin, &cach)) goto LFail; } } fRet = fTrue; LFail: //invalidate the LIGs for (ipddg = 0; pvNil != (pddg = PddgGet(ipddg)); ipddg++) { Assert(pddg->FIs(kclsLIG), 0); ((PLIG)pddg)->Refresh(); } return fTrue; } /*************************************************************************** Return the number of items in the list. ***************************************************************************/ long LID::Ccki(void) { AssertThis(0); return _pglcach->IvMac(); } /*************************************************************************** Get the CKI for the indicated item. ***************************************************************************/ void LID::GetCki(long icki, CKI *pcki, PCRF *ppcrf) { AssertThis(0); AssertIn(icki, 0, _pglcach->IvMac()); AssertVarMem(pcki); AssertNilOrVarMem(ppcrf); CACH cach; _pglcach->Get(icki, &cach); pcki->ctg = _ctg; pcki->cno = cach.cno; if (pvNil != ppcrf) *ppcrf = cach.pcrf; } /*************************************************************************** Get an MBMP for the indicated item. ***************************************************************************/ PMBMP LID::PmbmpGet(long icki) { AssertThis(0); AssertIn(icki, 0, _pglcach->IvMac()); CACH cach; _pglcach->Get(icki, &cach); return (PMBMP)cach.pcrf->PbacoFetch(kctgMbmp, cach.cnoMbmp, MBMP::FReadMbmp); } /*************************************************************************** Constructor for the list display gob. ***************************************************************************/ LIG::LIG(PLID plid, GCB *pgcb) : LIG_PAR(plid, pgcb) { } #ifdef DEBUG /*************************************************************************** Assert the validity of a LIG. ***************************************************************************/ void LIG::AssertValid(ulong grf) { LIG_PAR::AssertValid(0); AssertPo(_pscb, 0); AssertPo(_ptxhd, 0); AssertIn(_dypCell, 1, kswMax); } /*************************************************************************** Mark memory for the LIG. ***************************************************************************/ void LIG::MarkMem(void) { AssertValid(0); LIG_PAR::MarkMem(); MarkMemObj(_ptxhd); } #endif //DEBUG /*************************************************************************** Static method to create a new list display gob. ***************************************************************************/ PLIG LIG::PligNew(PLID plid, GCB *pgcb, PTXHD ptxhd, long dypCell) { AssertPo(plid, 0); AssertVarMem(pgcb); AssertPo(ptxhd, 0); AssertIn(dypCell, 1, kswMax); PLIG plig; if (pvNil == (plig = NewObj LIG(plid, pgcb))) return pvNil; if (!plig->_FInit(ptxhd, dypCell)) ReleasePpo(&plig); return plig; } /*************************************************************************** Return the LID for this LIG. ***************************************************************************/ PLID LIG::Plid(void) { AssertPo(_pdocb, 0); Assert(_pdocb->FIs(kclsLID), 0); return (PLID)_pdocb; } /*************************************************************************** Initialization for the list display gob. ***************************************************************************/ bool LIG::_FInit(PTXHD ptxhd, long dypCell) { AssertPo(ptxhd, 0); AssertIn(dypCell, 1, kswMax); GCB gcb; if (!LIG_PAR::_FInit()) return fFalse; _ptxhd = ptxhd; _dypCell = dypCell; gcb.Set(khidVScroll, this); gcb._rcRel.Set(krelOne, 0, krelOne, krelOne); gcb._rcAbs.Set(-SCB::DxpNormal(), -1, 0, 1 - kdxpFrameCcg); if (pvNil == (_pscb = SCB::PscbNew(&gcb, fscbVert, 0, 0, Plid()->Ccki() - 1))) { return fFalse; } AssertThis(0); return fTrue; } /*************************************************************************** The LID has changed, reset the scroll bounds and invalidate the display area. ***************************************************************************/ void LIG::Refresh(void) { AssertThis(0); long val; InvalRc(pvNil); val = LwMax(0, LwMin(_pscb->Val(), Plid()->Ccki() - 1)); _pscb->SetValMinMax(val, 0, Plid()->Ccki() - 1); } /*************************************************************************** Draw the list. ***************************************************************************/ void LIG::Draw(PGNV pgnv, RC *prcClip) { AssertThis(0); AssertPo(pgnv, 0); AssertVarMem(prcClip); RC rc, rcT, rcCell, rcClip; long icki; PMBMP pmbmp; PLID plid; long ccki; plid = Plid(); ccki = plid->Ccki(); GetRc(&rc, cooLocal); rcT = rc; rc.ypBottom = rcT.ypTop = rcT.ypBottom - kdxpFrameCcg; pgnv->FillRc(&rcT, kacrBlack); _pscb->GetRc(&rcT, cooParent); rc.xpRight = rcT.xpLeft; rcCell = rc; if (!rc.FIntersect(prcClip)) return; pgnv->FillRc(&rc, kacrWhite); rcCell.ypTop = LwRoundToward(rc.ypTop, _dypCell); icki = _pscb->Val() + rcCell.ypTop / _dypCell; for ( ; rcCell.ypTop < rc.ypBottom && icki < ccki; rcCell.ypTop += _dypCell, icki++) { rcCell.ypBottom = rcCell.ypTop + _dypCell; pmbmp = plid->PmbmpGet(icki); if (pvNil == pmbmp) continue; pmbmp->GetRc(&rcT); rcT.CenterOnRc(&rcCell); if (rcClip.FIntersect(&rc, &rcCell)) { pgnv->ClipRc(&rcClip); pgnv->DrawMbmp(pmbmp, &rcT); } ReleasePpo(&pmbmp); } } /*************************************************************************** Handles a scroll command. ***************************************************************************/ bool LIG::FCmdScroll(PCMD pcmd) { long dval, val; RC rc, rcT; GetRc(&rc, cooLocal); rc.ypBottom -= kdxpFrameCcg; _pscb->GetRc(&rcT, cooParent); rc.xpRight = rcT.xpLeft; val = _pscb->Val(); switch (pcmd->cid) { case cidDoScroll: switch (pcmd->rglw[1]) { default: Bug("unknown sca"); return fTrue; case scaLineUp: dval = -1; break; case scaPageUp: dval = -LwMax(1, rc.Dyp() / _dypCell - 1); break; case scaLineDown: dval = 1; break; case scaPageDown: dval = LwMax(1, rc.Dyp() / _dypCell - 1); break; case scaToVal: dval = pcmd->rglw[2] - val; break; } break; case cidEndScroll: dval = pcmd->rglw[1] - val; break; } dval = LwMax(0, LwMin(dval + val, _pscb->ValMax())) - val; if (dval == 0) return fTrue; _pscb->SetVal(val + dval); Scroll(&rc, 0, -dval * _dypCell, kginDraw); return fTrue; } /*************************************************************************** The mouse was clicked in the LIG. Insert the object in the active DDG. ***************************************************************************/ void LIG::MouseDown(long xp, long yp, long cact, ulong grfcust) { AssertThis(0); long icki; CKI cki; RC rc, rcT; PHETG phetg; PCRF pcrf; PLID plid; plid = (PLID)_pdocb; Assert(plid->FIs(kclsLID), 0); AssertPo(plid, 0); GetRc(&rc, cooLocal); _pscb->GetRc(&rcT, cooParent); rc.xpRight = rcT.xpLeft; if (!rc.FPtIn(xp, yp)) return; icki = _pscb->Val() + yp / _dypCell; if (!FIn(icki, 0, plid->Ccki())) return; phetg = (PHETG)_ptxhd->PddgActive(); if (pvNil == phetg || !phetg->FIs(kclsHETG)) return; plid->GetCki(icki, &cki, &pcrf); switch (cki.ctg) { case kctgMbmp: phetg->FInsertPicture(pcrf, cki.ctg, cki.cno); break; case kctgGokd: phetg->FInsertButton(pcrf, cki.ctg, cki.cno); break; } } /*************************************************************************** Constructor for the CCG. ***************************************************************************/ CCG::CCG(GCB *pgcb, PTXHD ptxhd, bool fForeColor, long cacrRow) : CCG_PAR(pgcb) { AssertPo(ptxhd, 0); AssertIn(cacrRow, 1, 257); _ptxhd = ptxhd; _cacrRow = cacrRow; _fForeColor = FPure(fForeColor); } /*************************************************************************** Handle mousedown in a CCG. Set the foreground or background color of the text in the active of DDG of the ptxhd. ***************************************************************************/ void CCG::MouseDown(long xp, long yp, long cact, ulong grfcust) { AssertThis(0); PHETG phetg; ACR acr; if (!_FGetAcrFromPt(xp, yp, &acr)) return; phetg = (PHETG)_ptxhd->PddgActive(); if (pvNil != phetg && phetg->FIs(kclsHETG)) phetg->FSetColor(_fForeColor ? &acr : pvNil, _fForeColor ? pvNil : &acr); } /*************************************************************************** Draw the Color chooser gob. ***************************************************************************/ void CCG::Draw(PGNV pgnv, RC *prcClip) { AssertThis(0); AssertPo(pgnv, 0); AssertVarMem(prcClip); long crcHeight, ircHeight, ircWidth; long iscr; RC rc, rcT; ACR acr; GetRc(&rc, cooLocal); rc.ypTop -= kdxpFrameCcg; rc.xpLeft -= kdxpFrameCcg; pgnv->SetPenSize(kdxpFrameCcg, kdxpFrameCcg); pgnv->FrameRc(&rc, kacrBlack); rc.Inset(kdxpFrameCcg, kdxpFrameCcg); pgnv->FillRc(&rc, kacrWhite); rc.Inset(kdxpFrameCcg, kdxpFrameCcg); crcHeight = LwDivAway(257, _cacrRow); for (iscr = 0, ircHeight = 0; ircHeight < crcHeight; ircHeight++) { for (ircWidth = 0; ircWidth < _cacrRow; ircWidth++, iscr++) { rcT.SetToCell(&rc, _cacrRow, crcHeight, ircWidth, ircHeight); switch (iscr) { default: acr.SetToIndex((byte)iscr); pgnv->FillRc(&rcT, acr); break; case 0: pgnv->FillRc(&rcT, kacrBlack); break; case 256: if (!_fForeColor) pgnv->FillRcApt(&rcT, &vaptGray, kacrBlack, kacrWhite); return; } } } } /*************************************************************************** Map the given point to a color. ***************************************************************************/ bool CCG::_FGetAcrFromPt(long xp, long yp, ACR *pacr, RC *prc, long *piscr) { AssertThis(0); AssertVarMem(pacr); AssertNilOrVarMem(prc); AssertNilOrVarMem(piscr); RC rc; long iscr; long ircWidth, ircHeight; GetRc(&rc, cooLocal); rc.ypTop += kdxpFrameCcg; rc.xpLeft += kdxpFrameCcg; rc.ypBottom -= 2 * kdxpFrameCcg; rc.xpRight -= 2 * kdxpFrameCcg; if (!rc.FMapToCell(xp, yp, _cacrRow, LwDivAway(257, _cacrRow), &ircWidth, &ircHeight)) { TrashVar(prc); TrashVar(piscr); return fFalse; } iscr = LwMul(ircHeight, _cacrRow) + ircWidth; switch (iscr) { default: if (!FIn(iscr, 1, 256)) return fFalse; pacr->SetToIndex((byte)iscr); break; case 0: *pacr = kacrBlack; break; case 256: if (_fForeColor) return fFalse; pacr->SetToClear(); break; } if (pvNil != prc) { prc->SetToCell(&rc, _cacrRow, LwDivAway(257, _cacrRow), ircWidth, ircHeight); } if (pvNil != piscr) *piscr = iscr; return fTrue; } /*************************************************************************** Put up the CCG's tool tip. ***************************************************************************/ bool CCG::FEnsureToolTip(PGOB *ppgobCurTip, long xpMouse, long ypMouse) { AssertThis(0); AssertVarMem(ppgobCurTip); AssertNilOrPo(*ppgobCurTip, 0); RC rc; ACR acr; ReleasePpo(ppgobCurTip); GCB gcb(khidToolTip, this, fgobNil, kginMark); *ppgobCurTip = NewObj CCGT(&gcb, kacrBlack); return fTrue; } /*************************************************************************** When the mouse moves over the CCG, update the tool tip. ***************************************************************************/ bool CCG::FCmdMouseMove(PCMD_MOUSE pcmd) { AssertThis(0); AssertVarMem(pcmd); PCCGT pccgt; RC rc, rcOld; ACR acr; STN stn; long iscr; if (pvNil == (pccgt = (PCCGT)PgobFromHid(khidToolTip)) || !pccgt->FIs(kclsCCGT)) { return fTrue; } if (!_FGetAcrFromPt(pcmd->xp, pcmd->yp, &acr, &rc, &iscr)) { rc.Zero(); acr = kacrBlack; } else { rc.ypBottom = rc.ypTop; rc.ypTop -= 30; rc.Inset(-20, 0); if (acr == kacrClear) stn = PszLit(" Clear "); else stn.FFormatSz(PszLit(" %d "), iscr); } if (rc.ypTop < 0 && pcmd->yp < rc.Dyp()) rc.Offset(0, 60); GetRc(&rcOld, cooLocal); rcOld.ypBottom -= kdxpFrameCcg; rcOld.xpRight -= kdxpFrameCcg; rc.PinToRc(&rcOld); pccgt->GetPos(&rcOld, pvNil); if (rcOld != rc) pccgt->SetPos(&rc); pccgt->SetAcr(acr, &stn); return fTrue; } #ifdef DEBUG /*************************************************************************** Assert the validity of a CCG. ***************************************************************************/ void CCG::AssertValid(ulong grf) { CCG_PAR::AssertValid(0); AssertPo(_ptxhd, 0); AssertIn(_cacrRow, 1, 257); } #endif //DEBUG /*************************************************************************** Constructor for color chooser tool tip. ***************************************************************************/ CCGT::CCGT(PGCB pgcb, ACR acr, PSTN pstn) : CCGT_PAR(pgcb) { AssertBaseThis(0); _acr = acr; if (pvNil != pstn) _stn = *pstn; } /*************************************************************************** Set the color for the tool tip. ***************************************************************************/ void CCGT::SetAcr(ACR acr, PSTN pstn) { AssertThis(0); AssertPo(&acr, 0); AssertNilOrPo(pstn, 0); if (_acr != acr || pvNil == pstn && _stn.Cch() > 0 || !_stn.FEqual(pstn)) { _acr = acr; if (pvNil == pstn) _stn.SetNil(); else _stn = *pstn; InvalRc(pvNil, kginMark); } } /*************************************************************************** Draw the color tool tip. ***************************************************************************/ void CCGT::Draw(PGNV pgnv, RC *prcClip) { AssertThis(0); AssertPo(pgnv, 0); AssertVarMem(prcClip); RC rc; ACR acr; GetRc(&rc, cooLocal); pgnv->SetPenSize(1, 1); pgnv->FrameRc(&rc, kacrBlack); rc.Inset(1, 1); pgnv->FrameRc(&rc, kacrWhite); rc.Inset(1, 1); if (_acr == kacrClear) pgnv->FillRcApt(&rc, &vaptGray, kacrBlack, kacrWhite); else pgnv->FillRc(&rc, _acr); if (_stn.Cch() > 0) { pgnv->ClipRc(&rc); pgnv->SetFont(vpappb->OnnDefVariable(), fontBold, 12, tahCenter, tavCenter); if (_acr == kacrClear) { pgnv->DrawStn(&_stn, rc.XpCenter(), rc.YpCenter(), kacrBlack, kacrWhite); } else pgnv->DrawStn(&_stn, rc.XpCenter(), rc.YpCenter(), _acr, kacrInvert); } }