|
|
/*
* @doc INTERNAL * * @module _RUNPTR.H -- Text run and run pointer class defintion | * * Original Author: <nl> * Christian Fortini * * History: <nl> * 6/25/95 alexgo Commenting and Cleanup * * Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved. */
#ifndef _RUNPTR_H
#define _RUNPTR_H
#include "_array.h"
#include "_doc.h"
typedef CArray<CTxtRun> CRunArray;
/*
* CRunPtrBase * * @class Base run pointer functionality. Keeps a position within an array * of text runs. * * @devnote Run pointers go through three different possible states : * * NULL: there is no data and no array (frequently a startup condition) <nl> * <mf CRunPtrBase::SetRunArray> will transition from this state to * the Empty state. It is typically up to the derived class to * define when that method should be called. IsValid() fails. <nl> * * <md CRunPtrBase::_pRuns> == NULL <nl> * <md CRunPtrBase::_iRun> == 0 <nl> * <md CRunPtrBase::_ich> == 0 <nl> * * Empty: an array class exists, but there is no data (can happen if all * of the elements in the array are deleted). IsValid() fails.<nl> * <md CRunPtrBase::_pRuns> != NULL <nl> * <md CRunPtrBase::_iRun> == 0 <nl> * <md CRunPtrBase::_ich> <gt>= 0 <nl> * <md CRunPtrBase::_pRuns-<gt>Count()> == 0 <nl> * * Normal: the array class exists and has data; IsValid() succeeds and * <md CRunPtrBase::_pRuns-<gt>Elem[] is defined <nl> * <md CRunPtrBase::_pRuns> != NULL <nl> * <md CRunPtrBase::_iRun> >= 0 <nl> * <md CRunPtrBase::_ich> >= 0 <nl> * <md _pRuns>-<gt>Count() > 0 <nl> * * Note that in order to support the empty and normal states, the actual * array element at <md CRunPtrBase::_iRun> must be explicitly fetched in * any method that may need it. * * Currently, there is no way to transition to the NULL state from any of * the other states. If we needed to, we could support that by explicitly * fetching the array from the document on demand. * * Note that only <md CRunPtrBase::_iRun> is kept. We could also keep * a pointer to the actual run (i.e. _pRun). Earlier versions of this * engine did in fact do this. I've opted to not do this for several * reasons: <nl> * 1. If IsValid(), _pRun is *always* available by calling Elem(_iRun). * Therefore, there is nominally no need to keep both _iRun and _pRun.<nl> * 2. Run pointers are typically used to either just move around * and then fetch data or move and fetch data every time (like during * a measuring loop). In the former case, there is no need to always * bind _pRun; you can just do it on demand. In the latter case, the * two models are equivalent. */
class CRunPtrBase { friend class CDisplayML; friend class CDisplaySL;
//@access Public methods
public:
#ifdef DEBUG
BOOL Invariant() const; //@cmember Invariant tests
void ValidatePtr(void *pRun) const; //@cmember Validate <p pRun>
LONG CalcTextLength() const; //@cmember Get total cch in runs
#define VALIDATE_PTR(pRun) ValidatePtr(pRun)
#else
#define VALIDATE_PTR(pRun)
#endif // DEBUG
CRunPtrBase(CRunArray *pRuns); //@cmember Constructor
CRunPtrBase(CRunPtrBase& rp); //@cmember Constructor
// Run Control
void SetRunArray(CRunArray *pRuns) //@cmember Set run array for this
{ // run ptr
_pRuns = pRuns; } BOOL SetRun(LONG iRun, LONG ich); //@cmember Set this runptr to run
// <p iRun> & char offset <p ich>
BOOL NextRun(); //@cmember Advance to next run
BOOL PrevRun(); //@cmember Go back to prev run
BOOL ChgRun(LONG cRun) //@cmember Move <p cRun> runs
{ // returning TRUE if successful
return SetRun(_iRun + cRun, 0); } //@cmember Count <p cRun> runs
LONG CountRuns(LONG &cRun, // returning cch counted and
LONG cchMax, // updating <p cRun>
LONG cp, LONG cchText) const; //@cmember Find run range limits
void FindRun (LONG *pcpMin, LONG *pcpMost, LONG cpMin, LONG cch, LONG cchText) const;
CTxtRun * GetRun(LONG cRun) const; //@cmember Retrieve run element at
// offset <p cRun> from this run
LONG Count() const //@cmember Get count of runs
{ return _pRuns->Count(); } BOOL SameRuns(CRunPtrBase *prp) //@cmember Return TRUE iff same runs
{ return _pRuns == prp->_pRuns; } BOOL SameRun(CRunPtrBase *prp) { return SameRuns(prp) && _iRun == prp->_iRun; }
// Character position control
//@cmember Set cp for this run ptr = <p cp>
LONG BindToCp(LONG cp, LONG cchText = tomForward); LONG CalculateCp() const;//@cmember Add _cch's up to _iRun, _ich
LONG Move(LONG cch); //@cmember Move cp by <p cch> chars
void AdjustBackward(); //@cmember If on the edge of two runs,
// adjust to end of left (previous) run
void AdjustForward(); //@cmember If at the edge of two runs,
// adjust to start of right (next) run
LONG GetIch() const //@cmember Return <md CRunPtrBase::_ich>
{Assert(IsValid()); return _ich;} LONG GetIRun() const //@cmember Return <md CRunPtrBase::_iRun>
{Assert(IsValid()); return _iRun;} void SetIch(LONG ich) //@cmember Set <md CRunPtrBase::_ich>
{Assert(IsValid()); _ich = ich;} LONG GetCchLeft() const; //@cmember Return GetRun(0)->_cch - GetIch()
inline BOOL IsValid() const //@cmember Return FALSE if run ptr is in
{ // empty or NULL states. TRUE otherwise
return _pRuns && _pRuns->Count(); }
void SetToNull(); //@cmember Clears data from run pointer
//@access Protected Data
protected: CRunArray * _pRuns; //@cmember Pointer to CTxtRun array
LONG _iRun; //@cmember Index of current run in array
LONG _ich; //@cmember Char offset inside current run
};
/*
* CRunPtr (template) * * @class a template over CRunPtrBase allowing for type-safe versions of * run pointers * * @tcarg class | CElem | run array class to be used * * @base public | CRunPtrBase */ template <class CElem> class CRunPtr : public CRunPtrBase { public: CRunPtr (void) //@cmember Constructor
: CRunPtrBase (0) {} CRunPtr (CRunArray *pRuns) //@cmember Constructor
: CRunPtrBase (pRuns) {} CRunPtr (CRunPtrBase& rp) //@cmember Constructor
: CRunPtrBase (rp) {}
// Array management
CElem * Add (LONG cRun, LONG *pielIns) //@cmember Add <p cRun>
{ // elements at end of array
return (CElem *)_pRuns->Add(cRun, pielIns); } CElem * Insert (LONG cRun) //@cmember Insert <p cRun>
{ // elements at current pos
return (CElem *)_pRuns->Insert(_iRun, cRun); } void Remove (LONG cRun) //@cmember Remove <p cRun>
{ // elements at current pos
_pRuns->Remove (_iRun, cRun); } //@cmember Replace <p cRun> elements
// at current position with those
// from <p parRun>
BOOL Replace (LONG cRun, CArrayBase *parRun) { return _pRuns->Replace(_iRun, cRun, parRun); }
CElem * Elem(LONG iRun) const //@cmember Get ptr to run <p iRun>
{ return (CElem *)_pRuns->Elem(iRun); } CElem * GetRun(LONG cRun) const //@cmember Get ptr <p cRun> runs
{ // away from current run
return Elem(_iRun + cRun); }
void IncPtr(CElem *&pRun) const //@cmember Increment ptr <p pRun>
{ VALIDATE_PTR(pRun); // Allow invalid ptr after ++ for
pRun++; // for loops
} CElem * GetPtr(CElem *pRun, LONG cRun) const//@cmember Get ptr <p cRun>
{ // runs away from ptr <p pRun>
VALIDATE_PTR(pRun + cRun); return pRun + cRun; } };
#endif
|