Milán Major

netscape-revival

1 branch
Code

lib/mac/TX/CTXTextView.cp

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	CTXTextView.cp						  ©1995 Netscape. All rights reserved.
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

#include "CTXTextView.h"

#include "CTXTextEngine.h"
#include "CTXStyleSet.h"

#include <LTextModel.h>
#include <LTextSelection.h>
#include <LTextEditHandler.h>
#include <LTextElemAEOM.h>

#include <StClasses.h>
#include <UCursor.h>

//#include "Textension.h"

#pragma global_optimizer off

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥¥¥ 	Construction/Destruction
#pragma mark --- Construction/Destruction ---


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

CTXTextView* CTXTextView::CreateTXTextViewStream(LStream* inStream)
{
	return new CTXTextView(inStream);
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

CTXTextView::CTXTextView()
{
	Assert_(false);	//	Must use parameters
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

CTXTextView::CTXTextView(LStream *inStream)
	:	LSelectHandlerView(inStream)
{
	mTextModel = NULL;
	mTextEngine = NULL;
	mHasActiveTextView = false;
	mOldSelectionIsCaret = false;
	mCaretOn = false;
	mCaretTime = TickCount();
	mTextParms = NULL;
	
	mScaleNumer.h = 1;
	mScaleNumer.v = 1;
	mScaleDenom.h = 1;
	mScaleDenom.v = 1;

	try
		{
		// This is the first run at a new text scheme.
		// The streaming parameters will probably change
		mTextParms = new SSimpleTextParms;
		inStream->ReadData(&mTextParms->attributes, sizeof(Uint16));
		inStream->ReadData(&mTextParms->wrappingMode, sizeof(Uint16));
		inStream->ReadData(&mTextParms->traitsID, sizeof(ResIDT));
		inStream->ReadData(&mTextParms->textID, sizeof(ResIDT));
		inStream->ReadData(&mTextParms->pageWidth, sizeof(Int32));
		inStream->ReadData(&mTextParms->pageHeight, sizeof(Int32));
		inStream->ReadData(&mTextParms->margins, sizeof(Rect));
		}
	catch (ExceptionCode inErr)
		{
		// this is either a streaming error or we couldn't get the memory for
		// a text parm structure, in which case you're totally screwed.
		delete mTextParms;
		throw inErr;
		}
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

CTXTextView::~CTXTextView()
{
	if (mTextEngine && (mTextEngine->GetHandlerView() == this))
		mTextEngine->SetHandlerView(NULL);	//	The HandlerView is going away
	
	SetTextEngine(NULL);
	SetTextModel(NULL);
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::FinishCreateSelf(void)
{
	//	¥	Make objects that haven't been made by subclasses...
	if (mTextEngine == NULL)
		ReplaceSharable_(mTextEngine, new CTXTextEngine, this);

	if (mTextModel == NULL)
		SetTextModel(new LTextModel(mTextEngine));

	if (mSelection == NULL)
		SetSelection(new LTextSelection(mTextEngine));

	if (mEventHandler == NULL)
		{
		FocusDraw();	//	set current qd port for handler...
		SetEventHandler(new LTextEditHandler);
		}

	Assert_(mTextParms != NULL);

	//	text attributes
	CTXTextEngine* theTextEngine = (CTXTextEngine*)mTextEngine;

	// Text style.  Important to do first because it sets the default style
	// set of the text engine
	SetInitialTraits(mTextParms->traitsID);

	theTextEngine->SetAttributes(mTextParms->attributes);
	theTextEngine->SetWrapMode(mTextParms->wrappingMode);

	LSelectHandlerView::FinishCreateSelf();

	//	¥	Build links
	mTextEngine->SetHandlerView(this);
	mTextEngine->AddListener(this);
	mTextModel->SetSelection(mSelection);
	
	((LTextSelection *)mSelection)->SetTextModel(mTextModel);
	((LTextSelection *)mSelection)->SetSuperModel(mTextModel);
	((LTextEditHandler *)mEventHandler)->SetCommander(this);
	((LTextEditHandler *)mEventHandler)->SetSelection(mSelection);
	((LTextEditHandler *)mEventHandler)->SetTextEngine(mTextEngine);
	((LTextEditHandler *)mEventHandler)->SetHandlerView(this);
	((LTextEditHandler *)mEventHandler)->SetTextModel(mTextModel);

	//	text image size
	if (mTextParms->wrappingMode == wrapMode_WrapToFrame)
		{
		Rect			r;
		SDimension32	size;
		
		if (!CalcLocalFrameRect(r))
			Throw_(paramErr);
	
		size.width = r.right - r.left;
		size.height = 0;

		theTextEngine->SetPageFrameSize(size);
		}
	else
		{
		SDimension32 thePageDims;
		thePageDims.width = mTextParms->pageWidth;
		thePageDims.height = mTextParms->pageHeight;
		theTextEngine->SetPageFrameSize(thePageDims);
		}

	if (mTextParms->textID != 0)
		SetInitialText(mTextParms->textID);
		
	mTextEngine->SetAttributes(mTextParms->attributes);	//	restore editable/selectable bits

	if (!(mTextParms->attributes & textAttr_Selectable))
		SetTextSelection(NULL);
		
	mTextEngine->SetTextMargins(mTextParms->margins);
	
	delete mTextParms;
	mTextParms = NULL;
}


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥¥¥ 	Text Object Access
#pragma mark --- Text Object Access ---


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

LTextEngine* CTXTextView::GetTextEngine(void)
{
	return mTextEngine;
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::SetTextEngine(LTextEngine *inTextEngine)
{
	if (mTextEngine != inTextEngine)
		{

		if (mTextEngine)
			mTextEngine->RemoveListener(this);
	
		ReplaceSharable_(mTextEngine, inTextEngine, this);
		
		if (mTextEngine)
			mTextEngine->AddListener(this);
	
		FixImage();
		}
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

LTextModel* CTXTextView::GetTextModel(void)
{
	return mTextModel;
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::SetTextModel(LTextModel *inTextModel)
{
	ReplaceSharable_(mTextModel, inTextModel, this);
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

LTextSelection*	CTXTextView::GetTextSelection(void)
{
	if (mSelection)
		return (LTextSelection *) mSelection;
	else
		return NULL;
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::SetTextSelection(LTextSelection *inSelection)
{
	SetSelection(inSelection);
}


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥¥¥	Event Handler Overrides
#pragma mark --- Event Handler Overrides ---


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

LSelectableItem* CTXTextView::OverItem(Point inWhere)
{
	LSelectableItem	*rval = NULL;
	
	if (mTextEngine && mTextModel && mEventHandler)
		{
		FocusDraw();
		
		//	Find corresponding text offset
		TextRangeT		range;
		Boolean			leadingEdge;
		SPoint32		where;
		LocalToImagePoint(inWhere, where);
		mTextEngine->Image2Range(where, &leadingEdge, &range);
		if (leadingEdge)
			range.Front();
		else
			range.Back();
		range.Crop(mTextModel->GetRange());
		
		//	Determine part type to find
		DescType		findType = cChar;
		LTextElemAEOM	*oldElem = NULL;
		rval = inherited::OverItem(inWhere);
		if (rval)									//	inWhere is guaranteed to hit rval
			{
//			member(rval, LTextElemAEOM);
			oldElem = (LTextElemAEOM *)rval;
			findType = oldElem->GetModelKind();	//	in case count > 4
			}
			
		switch (mEventHandler->GetClickCount())
			{
			case 0:
			case 1:
				findType = cChar;
				break;
			case 2:
				findType = cWord;
				break;
			case 3:
				findType = cLine;
				break;
			case 4:
				findType = cParagraph;
				break;
			}
		
		//	Return old equivalent elem or make a new elem
		TextRangeT	foundRange = range;
		DescType	partFound = cChar;
		if (findType != cChar)
			{
			DescType type = mTextEngine->FindPart(LTextEngine::sTextAll, &foundRange, findType);
			if (type != typeNull)
				partFound = type;
			}
		if (!oldElem || (oldElem->GetRange() != foundRange))
			rval = mTextModel->MakeNewElem(foundRange, partFound);
		}
		
	return rval;
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

LSelectableItem* CTXTextView::OverReceiver(Point inWhere)
{
	LSelectableItem	*rval = NULL;
	
	do {
		if (mEventHandler)
			rval = mEventHandler->OverReceiverSelf(inWhere);
		
		if (rval)
			break;
		
		if (!mTextEngine || !mTextModel || !mEventHandler)
			break;
			
		FocusDraw();
	
		//	Find corresponding text offset
		TextRangeT		range;
		Boolean			leadingEdge;
		SPoint32		where;
		LocalToImagePoint(inWhere, where);
		mTextEngine->Image2Range(where, &leadingEdge, &range);
		if (leadingEdge)
			range.Front();
		else
			range.Back();
		range.Crop(mTextModel->GetRange());
		rval = mTextModel->MakeNewElem(range, cChar);
	} while (false);
	
	return rval;
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::NoteOverNewThing(LManipulator *inThing)
{
	if (inThing)
		{
		switch(inThing->ItemType())
			{
			case kManipulator:
				UCursor::Reset();	//	?
				break;

			case kSelection:
				if (mEventHandler && ((LDataDragEventHandler *)mEventHandler)->GetStartsDataDrags())
					{
					CursHandle theCursH = ::GetCursor(131);
					if (theCursH != nil)
						::SetCursor(*theCursH);
					break;
					}
				else
					{
					//	fall through
					}

			case kSelectableItem:
				UCursor::Tick(cu_IBeam);	//	?
				break;

			}
		}
	else
		{
		UCursor::Reset();
		}
}


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥¥¥	Commader Overrides
#pragma mark --- Commander Overrides ---


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

Boolean	CTXTextView::ObeyCommand(
	CommandT	inCommand,
	void*		ioParam)
{
	Boolean				cmdHandled = true;
	
	switch (inCommand)
		{
		case cmd_SelectAll:
			{
			if (mSelection)
				{
				LTextElemAEOM 	*newSelect = NULL;
				if (mTextModel)
					{
					newSelect = mTextModel->MakeNewElem(LTextEngine::sTextAll, cChar);
					}
				mSelection->SelectSimple(newSelect);
				}
			cmdHandled = true;
			break;
			}

		default:
			cmdHandled = LSelectHandlerView::ObeyCommand(inCommand, ioParam);
			break;
		}
	
	return cmdHandled;
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::FindCommandStatus(
	CommandT	inCommand,
	Boolean		&outEnabled,
	Boolean		&outUsesMark,
	Char16		&outMark,
	Str255		outName)
{
	switch (inCommand)
		{
case 1000:
		case cmd_SelectAll:
			outUsesMark = false;
			if (mSelection)
				outEnabled = true;
			break;
			
		default:
			LSelectHandlerView::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
			switch (inCommand)
				{
				case cmd_Clear:
				case cmd_Cut:
				case cmd_Paste:
					if (!mTextEngine || !(mTextEngine->GetAttributes() & textAttr_Editable))
						outEnabled = false;
					break;
				}
			break;
		}
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::BeTarget(void)
{
	Assert_(!mHasActiveTextView);
	
	FocusDraw();
	LSelectHandlerView::BeTarget();
	mHasActiveTextView = true;
	CaretOn();
	
	if (mTextModel)
		LModelObject::DoAESwitchTellTarget(mTextModel);
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::DontBeTarget(void)
{
	Assert_(mHasActiveTextView);

	FocusDraw();
	mHasActiveTextView = false;
	CaretOff();
	LSelectHandlerView::DontBeTarget();	
}


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥¥¥	Other PowerPlant Linkage
#pragma mark --- Other PowerPlant Linkage ---


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::ListenToMessage(MessageT inMessage, void* ioParam)
{
	LHandlerView	*handlerView = NULL;
	
	if ((inMessage == msg_BroadcasterDied) && (ioParam == mTextEngine))
		{
		mTextEngine = NULL;
		return;
		}

	if (mTextEngine)
		handlerView = mTextEngine->GetHandlerView();

	Try_
		{	//	If the handler view gets changed (through a FocusDraw)... boom

		switch (inMessage)
			{
	
			case msg_ModelScopeChanged:
				{
				FocusDraw();
				FixImage();
				break;
				}
	
			case msg_ModelAboutToChange:
				{
				FocusDraw();
				CaretOff();
				mOldSelectionChanged = false;
				break;
				}
				
			case msg_ModelChanged:
				{
				FocusDraw();
				if (mOldSelectionChanged)
					{
					Assert_(mTextEngine && (mTextEngine->GetNestingLevel() == 1));
					if (mOldSelectionIsSubstantive != (mSelection && mSelection->IsSubstantive()))
						SetUpdateCommandStatus(true);
			
					FocusDraw();
					MutateSelection(IsOnDuty());
					CheckSelectionScroll();
					}
				CaretOn();
				break;
				}
	
			case msg_InvalidateImage:
				{
				FocusDraw();
				Refresh();
				break;
				}
			
			case msg_UpdateImage:
				{
				if (!mTextEngine)
					return;

				ThrowIfNULL_(ioParam);
				TextUpdateRecordT *update = (TextUpdateRecordT *)ioParam;
				UpdateTextImage(update);
				break;
				}
			
			//	for multiview...
			case msg_SelectionAboutToChange:
				{
				mOldSelectionIsSubstantive = mSelection && mSelection->IsSubstantive();
				
				FocusDraw();
				if (mTextEngine && (mTextEngine->GetNestingLevel() == 0))
					{
					CaretOff();
					inherited::ListenToMessage(inMessage, ioParam);
					}
				break;
				}

			case msg_SelectionChanged:
				{
				FocusDraw();
				if (mTextEngine && (mTextEngine->GetNestingLevel() == 0))
					{
					CheckSelectionScroll();

					//	inherited::ListenToMessage(inMessage, ioParam);
					//
					//	Not!!!
					//
					//	The inherited method would always call SetUpdateCommandStatus(true)
					//	which would result in UpdateMenus being called for every typing
					//	event.  This would slow down typing drastically.  Instead,
					//	SetUpdateCommandStatus is called only when mSelection->IsSubstantive
					//	changes.
						{
						if (mOldSelectionIsSubstantive != (mSelection && mSelection->IsSubstantive()))
							SetUpdateCommandStatus(true);
				
						FocusDraw();
						MutateSelection(IsOnDuty());
						}
					CaretOn();
					}
				else
					{
					mOldSelectionChanged = true;
					}
				break;
				}

			default:
				{
				inherited::ListenToMessage(inMessage, ioParam);
				break;
				}
			}

		if (mTextEngine)
			mTextEngine->SetHandlerView(handlerView);
			
		OutOfFocus(this);

		if (handlerView)
			handlerView->FocusDraw();
		} 
	Catch_(inErr)
		{
		if (mTextEngine)
			mTextEngine->SetHandlerView(handlerView);
			
		OutOfFocus(this);

		if (handlerView)
			handlerView->FocusDraw();

		Throw_(inErr);
		}
	EndCatch_;
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::SpendTime(const EventRecord &inMacEvent)
{
	if (!mTextEngine)
		return;

	LHandlerView* handlerView = mTextEngine->GetHandlerView();

	Try_
		{	//	If the handler view gets changed (through a FocusDraw)... boom

		LSelectHandlerView::SpendTime(inMacEvent);
		
		if (IsOnDuty())
			{
			FocusDraw();
			CaretMaintenance();
			}

		mTextEngine->SetHandlerView(handlerView);
		OutOfFocus(this);
		}
	Catch_(inErr)
		{
		mTextEngine->SetHandlerView(handlerView);
		OutOfFocus(this);
		Throw_(inErr);
		}
	EndCatch_;
}


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥¥¥	View and Image
#pragma mark --- View and Image ---


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

Boolean CTXTextView::FocusDraw(void)
{
	Boolean			rval;
	
	rval = LSelectHandlerView::FocusDraw();
	
	if (mTextEngine == NULL)
		return rval;
	
	mTextEngine->SetHandlerView(this);
	mTextEngine->SetPort(UQDGlobals::GetCurrentPort());

	return rval;
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::DrawSelf(void)
{
	if (mTextEngine)
		{
		SPoint32		location;
		SDimension32	size;
		
		GetViewArea(&location, &size);		
		mTextEngine->DrawArea(location, size);
		}
	else
		{
		Rect	r;
	
		if (CalcLocalFrameRect(r))
			EraseRect(&r);	
		}
	
	LSelectHandlerView::DrawSelf();
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::DrawSelfSelection(void)
{
	if (mOldSelectionIsCaret)
		{
		if (mCaretOn)
			CaretUpdate();
		}
	else
		{
		inherited::DrawSelfSelection();
		}
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// FIX ME!!! we nned to add support for the wrap bindings.

void CTXTextView::ResizeFrameBy(
	Int16		inWidthDelta,
	Int16		inHeightDelta,
	Boolean		inRefresh)
{
	LSelectHandlerView::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);

	CTXTextEngine* theEngine = (CTXTextEngine*)GetTextEngine();
	if (theEngine != NULL)
		{

		Boolean bNeedsImageFix = true;
		switch (theEngine->GetWrapMode())
			{
			case wrapMode_WrapToFrame:
				{
				
				Rect theFrame;
				CalcLocalFrameRect(theFrame);
				
				SDimension32 theNewSize;
				theNewSize.width = theFrame.right - theFrame.left;
				theNewSize.height = 0; // means auto adjust in text engine			
				
				// FIX ME!!! eventually we'll want to call some method
				// that sets the PAGE size.  Our text engine's SetImageSize()
				// method actually sets the size of the page.  It also
				// takes care of managing the appropriate changes in farmat/display.
					
//				theGeometry->SetPageFrameDimensions(size);
				mTextEngine->SetImageSize(theNewSize);
				}
				break;
	
			case wrapMode_WrapWidestUnbreakable:
				{
				// get the wiest unbreakable run
				// set the page text width to that width
				Assert_(false);		// Not Yet Implemented
				}
				break;

			case wrapMode_FixedPage:
			case wrapMode_FixedPageWrap:
				bNeedsImageFix = false;	// dont need to change the page size
				break;		
			}
		
		if (bNeedsImageFix)
			FixImage();
		}
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// FIX ME!!! it appears that we wont need to worry about scrolling the image
// wrt the text engine since we removed all scrolling from it.

void	CTXTextView::ScrollImageBy(
	Int32		inLeftDelta,
	Int32		inTopDelta,
	Boolean		inRefresh)
{
	LSelectHandlerView::ScrollImageBy(inLeftDelta, inTopDelta, inRefresh);

	// FIX ME!!! in  multi view scenarios the MutateSelection() call is
	// different from the LSelectHandlerView implementation.
	//
	// Here's what would change from that of LSelectHandlerView
	//	if (inRefresh && (inLeftDelta || inTopDelta)) {
	//		MutateSelection(IsOnDuty() || mHasActiveTextView);
	//	}
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::GetPresentHiliteRgn(
	Boolean		inAsActive,
	RgnHandle	ioRegion,
	Int16		inOriginH,
	Int16		inOriginV)
{
	if (mSelection)
		{
		if (mSelection->IsSubstantive())
			{
			inherited::GetPresentHiliteRgn(inAsActive, ioRegion, inOriginH, inOriginV);
			}
		else
			{
			Point	origin;
			origin.h = inOriginH;
			origin.v = inOriginV;
			mSelection->MakeRegion(origin, &ioRegion);	//	don't make an outline
														//	because that would just be
														//	strange looking.
	
			//	Clip to visible area...
			Rect		r;
			if (CalcLocalFrameRect(r))
				{
				StRegion	tempRgn(r);
	
				SectRgn(ioRegion, tempRgn, ioRegion);
				ThrowIfOSErr_(QDError());
				}
			}
		}
	else
		{
		URegions::MakeEmpty(ioRegion);
		}
	
	mOldSelectionIsCaret = SelectionIsCaret(inAsActive);
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::SubtractSelfErasingAreas(RgnHandle inSourceRgn)
{
	StRegion	myRgn;
	Rect		r;
	
	if (CalcPortFrameRect(r))
		{
		::RectRgn(myRgn, &r);
		::DiffRgn(inSourceRgn, myRgn, inSourceRgn);
		}

//	NO!	This pane's entire region was already subtracted above!
//
//	inherited::SubtractSelfErasingAreas(inSourceRgn);
//
//	NO!
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// FIX ME!!! the text engine does not care about the view rect anymore

void CTXTextView::SavePlace(
	LStream		*outPlace)
{
//	SPoint32		location = {0, 0};
//	SDimension32	size = {0, 0};
//
//	if (mTextEngine)
//		mTextEngine->GetViewRect(&location, &size);

	LView::SavePlace(outPlace);
	
//	outPlace->WriteData(&location, sizeof(location));
//	outPlace->WriteData(&size, sizeof(size));
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::RestorePlace(
	LStream		*inPlace)
{
//	SPoint32		location;
//	SDimension32	size;

	LView::RestorePlace(inPlace);

//	inPlace->ReadData(&location, sizeof(location));
//	inPlace->ReadData(&size, sizeof(size));

//	if (mTextEngine)
//		mTextEngine->SetViewRect(location, size);
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// This should only be called when the page dimensions change!!!

void CTXTextView::FixImage(void)
{
	if (mTextEngine != NULL)
		{
		// FIX ME!!! eventually we'll want to call some method
		// that sets the PAGE size.  Our text engine's SetImageSize()
		// method actually sets the size of the page.  It also
		// takes care of managing the appropriate changes in farmat/display.
		SDimension32 theSize;
		mTextEngine->GetImageSize(&theSize); // actaully gets the page size

		SDimension32 theOldSize;
		GetImageSize(theOldSize);
		ResizeImageBy(theSize.width - theOldSize.width, theSize.height - theOldSize.height, false);
		}
}


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥¥¥	Printing
#pragma mark --- Printing ---


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::SetPrintRange(const TextRangeT &inRange)
{
	mPrintRange = inRange;
	if (mTextEngine)
		mPrintRange.Crop(mTextEngine->GetTotalRange());
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

const TextRangeT& CTXTextView::GetPrintRange(void) const
{
	return mPrintRange;
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

Boolean	CTXTextView::ScrollToPanel(const PanelSpec &inPanel)
{
	Boolean		panelInImage = false;
	
	if (mTextEngine) {
		Int32		panelTop = mTextEngine->GetRangeTop(mPrintRange),
					panelBottom,
					panelLeft;
		Int32		vertPanel;
		
		vertPanel = 0;
		
		do {
			vertPanel++;
		} while ((vertPanel < inPanel.vertIndex) && NextPanelTop(&panelTop));
		
		if (vertPanel == inPanel.vertIndex) {
			SDimension16	frameSize;
			GetFrameSize(frameSize);
			
			panelBottom = panelTop;
			NextPanelTop(&panelBottom);
			panelLeft = frameSize.width * (inPanel.horizIndex -1);
			
			OutOfFocus(this);
			FocusDraw();
			ScrollImageTo(panelLeft, panelTop, false);
			Rect	clipRect;
			if (CalcLocalFrameRect(clipRect)) {
				mRevealedRect.bottom = mRevealedRect.top + panelBottom - panelTop;
				clipRect.bottom = clipRect.top + panelBottom - panelTop;
				::ClipRect(&clipRect);
			}
			panelInImage = true;
		}
	}
	
	return panelInImage;
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::CountPanels(
	Uint32&		outHorizPanels,
	Uint32&		outVertPanels)
{
	SDimension32	imageSize;
	SDimension16	frameSize;

	GetImageSize(imageSize);
	GetFrameSize(frameSize);
	
	outHorizPanels = 1;
	if (mTextEngine && !(mTextEngine->GetAttributes() & textAttr_WordWrap))
		{
		outHorizPanels = 1;
		}
	else if (frameSize.width > 0  &&  imageSize.width > 0)
		{
		outHorizPanels = ((imageSize.width - 1) / frameSize.width) + 1;
		}
	
	outVertPanels = 1;

	if (mTextEngine)
		{
		//	Find the real number of vertical panels
		Int32		panelTop = mTextEngine->GetRangeTop(mPrintRange);
		while (NextPanelTop(&panelTop))
			outVertPanels++;
		}
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

Boolean	CTXTextView::NextPanelTop(Int32 *ioPanelTop) const
/*
	ioPanelTop is assumed correct on entry
*/
{
	Int32	oldTop = *ioPanelTop;
	Boolean	anotherExists = false;
	
	do {
		if (!mTextEngine)
			break;
		
		//	trivial reject if ioPanelTop is already past mPrintRange bottom
		Range32T	printV(mTextEngine->GetRangeTop(mPrintRange));
		printV.SetLength(mTextEngine->GetRangeHeight(mPrintRange));
		if (*ioPanelTop >= printV.End())
			break;
		
		//	get frame lower left image point
		SDimension16	frameSize;
		GetFrameSize(frameSize);
		SPoint32	llPt;
		llPt.h = 0;
		llPt.v = *ioPanelTop + frameSize.height;
		
		//	get vertical range of last partially(?) visible line
		TextRangeT	llRange;
		Boolean		leadingEdge;
		mTextEngine->Image2Range(llPt, &leadingEdge, &llRange);
		Range32T	llV(mTextEngine->GetRangeTop(llRange));
		llV.SetLength(mTextEngine->GetRangeHeight(llRange));

		*ioPanelTop = URange32::Min(printV.End(), llV.Start());
		
		if (*ioPanelTop <= oldTop)
			{
			//	Then a line is so tall it couldn't fit in a single panel so go aghead and split it
			*ioPanelTop = oldTop + frameSize.height;
			}
		
		if (*ioPanelTop >= printV.End())
			break;
			
		anotherExists = true;

		if (oldTop >= *ioPanelTop)
			{
			Assert_(false);
			anotherExists = false;
			}
	} while (false);
	
	return anotherExists;
}


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥¥¥	Initialization
#pragma mark --- Initialization ---

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::SetInitialTraits(ResIDT inTextTraitsID)
{
	TextTraitsRecord	traits;
	TextTraitsH			traitsH = UTextTraits::LoadTextTraits(inTextTraitsID);

	if (traitsH)
		traits = **traitsH;
	else
		UTextTraits::LoadSystemTraits(traits);

	CTXStyleSet	*defaultStyle = new CTXStyleSet;

	Assert_(mTextModel);
	defaultStyle->SetSuperModel(mTextModel);
	defaultStyle->SetTextTraits(traits);
	mTextEngine->SetDefaultStyleSet(defaultStyle);
	
	UTextTraits::SetPortTextTraits(&traits);
	FontInfo theInfo;
	::GetFontInfo(&theInfo);
	
	SPoint32 theScrollUnit;
	theScrollUnit.v = theInfo.ascent + theInfo.descent + theInfo.leading;
	theScrollUnit.h = theScrollUnit.v;
	SetScrollUnit(theScrollUnit);
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::SetInitialText(ResIDT inTextID)
{
	StResource	textRsrc('TEXT', inTextID, false);
	if (textRsrc.mResourceH != nil)
		{
		mTextEngine->TextReplaceByHandle(LTextEngine::sTextAll, textRsrc.mResourceH);
		((LTextSelection *)mSelection)->SetSelectionRange(LTextEngine::sTextStart);
		}
}


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥¥¥	Selection Maintenance
#pragma mark --- Selection Maintenance ---


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::MutateSelection(Boolean inAsActive)
{
	Boolean		oldIsCaret = mOldSelectionIsCaret;
	StRegion	oldRegion(mOldSelectionRgn);
	
	GetPresentHiliteRgn(inAsActive, mOldSelectionRgn);
	mOldSelectionInvalid = false;
	
	MutateSelectionSelf(oldIsCaret, oldRegion, mOldSelectionIsCaret, mOldSelectionRgn);
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::MutateSelectionSelf(
	Boolean			inOldIsCaret,
	const RgnHandle	inOldRegion,
	Boolean			inNewIsCaret,
	const RgnHandle	inNewRegion) const
{
	if (!inOldIsCaret && !inNewIsCaret)
		{
		StRegion	tempRgn(inOldRegion);
		
		XorRgn(tempRgn, inNewRegion, tempRgn);
		ThrowIfOSErr_(QDError());
		
		URegions::Hilite(tempRgn);
		}
	else if (!inOldIsCaret && inNewIsCaret)
		{
	
		URegions::Hilite(inOldRegion);
		
		}
	else if (inOldIsCaret && !inNewIsCaret)
		{
		
		URegions::Hilite(inNewRegion);

		}
	else
		{
		//	nada
		}
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::CaretUpdate(void)
{
	if (mOldSelectionIsCaret)
		{
		if (IsActiveView())
			{
			StColorPenState	savePen;
		
			PenPat(&UQDGlobals::GetQDGlobals()->black);
			PenMode(srcXor);
			InvertRgn(mOldSelectionRgn.mRgn);
			}
		}
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::CaretOn(void)
{
	if (mOldSelectionIsCaret)
		{
		if (!mCaretOn)
			CaretUpdate();
		
		mCaretOn = IsActiveView();
		mCaretTime = TickCount();
		}
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::CaretOff(void)
{
	if (mOldSelectionIsCaret)
		{
		if (mCaretOn)
			CaretUpdate();
	
		mCaretOn = false;
		mCaretTime = TickCount();
		}
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::CaretMaintenance(void)
{
	if (mOldSelectionIsCaret)
		{
		if ((TickCount() - mCaretTime) > GetCaretTime())
			{
			if (mCaretOn)
				CaretOff();
			else
				CaretOn();
			}
		}
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// FIX ME!!! we could handle this here instead of passing it to the text engine
// we may also nee to override LTextEngine::GetRangeScrollVector() to accout
// for scale

void CTXTextView::CheckSelectionScroll(void)
{
	if ((mOnDuty == triState_On) || (mOnDuty == triState_Latent))
		{
		if (mSelection && mTextEngine)
			{
			TextRangeT	range = ((LTextSelection*)mSelection)->GetSelectionRange();
			mTextEngine->ScrollToRange(range);
			}
		}
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

Boolean CTXTextView::SelectionIsCaret(Boolean inIsActive) const
{
	return (mSelection
					&& 	inIsActive
					&&	!mSelection->IsSubstantive()
					&&	(mSelection->ListCount() == 1));
}


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥¥¥	Internal View Maintenance
#pragma mark --- Internal View Maintenance ---

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::UpdateTextImage(TextUpdateRecordT* inUpdate)
{
	FocusDraw();

	Range32T frameInterval;			//	in image y-pixels
	frameInterval = TextRangeT(mFrameLocation.v - mImageLocation.v);
	frameInterval.SetLength(mFrameSize.height);				

	if (!frameInterval.Intersects(inUpdate->gap))
		{
	
		//	¥	Then lets not so trivially handle this...
		if (inUpdate->gap.Start() > frameInterval.Start())
			{
			//	change is completely below this frame
			}
		else if (inUpdate->scrollAmount < 0)
			{
			Range32T	zappedBit(inUpdate->scrollStart, inUpdate->scrollStart - inUpdate->scrollAmount);
			
			if (zappedBit.Contains(frameInterval))
				{
				inherited::ScrollImageBy(0, mImageLocation.v - mFrameLocation.v + inUpdate->gap.Start(), false);
				FocusDraw();
				DrawSelf();
				}
			else if (frameInterval.Contains(Range32T(inUpdate->scrollStart - inUpdate->scrollAmount)))
				{
				inherited::ScrollImageBy(0, mImageLocation.v - mFrameLocation.v + inUpdate->gap.End(), false);
				FocusDraw();
				DrawSelf();
				}
			else
				{
				//	view is below changes.
				inherited::ScrollImageBy(0, inUpdate->scrollAmount, false);
				}
			} 
		else
			{
			//	view is below changes.
			inherited::ScrollImageBy(0, inUpdate->scrollAmount, false);
			}
		MutateSelection(IsActiveView());
		
		}
	else
		{

		//	in local coords...
		Rect		rFrame,
					rGap,
					rAbove,		//	region in frame above gap
					rScroll;	//	scrolled rect pre-scroll location

								//	rGap in 32bit! local coords
		Int32		rgTop = inUpdate->gap.Start() + mPortOrigin.v + mImageLocation.v,
					rgLeft = 0 + mFrameLocation.h + mPortOrigin.h,
					rgRight = rgLeft + mFrameSize.width, 
					rgBottom = inUpdate->gap.End() + mPortOrigin.v + mImageLocation.v;

		if (CalcLocalFrameRect(rFrame))
			{
			rGap.top = URange32::Max(rFrame.top, rgTop);
			rGap.left = URange32::Max(rFrame.left, rgLeft);
			rGap.right = URange32::Min(rFrame.right, rgRight);
			rGap.bottom = URange32::Min(rFrame.bottom, rgBottom);
			}
		else
			{
			Assert_(false);	//	huh?
			}
			
		rAbove = rFrame;
		rAbove.bottom = rGap.top;
		
		Boolean		oldSelectionIsCaret = mOldSelectionIsCaret;
		StRegion	rOld(mOldSelectionRgn.mRgn),
					rScreen,
					rTemp,
					rMask;
		StRegion	rgn;
		
		GetPresentHiliteRgn(IsActiveView(), mOldSelectionRgn);
	
		//	¥	Scroll
		if (inUpdate->scrollAmount && frameInterval.Contains(Range32T(inUpdate->scrollStart)))
			{
			Rect	r;
	
			RectRgn(rMask, &rAbove);
			SectRgn(rOld, rMask, rScreen);

			r.top = inUpdate->scrollStart + mPortOrigin.v + mImageLocation.v;
			r.left = mFrameLocation.h + mPortOrigin.h;
			r.right = r.left + mFrameSize.width;
			r.bottom = mFrameLocation.v + mFrameSize.height + mPortOrigin.v;

			if (inUpdate->scrollAmount < (r.bottom - r.top))
				{
				ScrollRect(&r, 0, inUpdate->scrollAmount, rgn);
				
				//	old selection...
				rScroll = r;
				if (inUpdate->scrollAmount > 0)
					rScroll.bottom -= inUpdate->scrollAmount;
				else
					rScroll.top -= inUpdate->scrollAmount;
				RectRgn(rMask, &rScroll);
				SectRgn(rOld, rMask, rTemp);
				OffsetRgn(rTemp, 0, inUpdate->scrollAmount);
				UnionRgn(rScreen, rTemp, rScreen);
				}
			if (inUpdate->scrollAmount < 0)
				{
				//	(offscreening this section would be a waste)
//				RGBColor	green = {0, 0xffff, 0};	RGBForeColor(&green);	PaintRgn(rgn);
				StClipRgnState	clipMe(rgn);
				DrawSelf();

				//	old selection...
				SectRgn(mOldSelectionRgn, rgn, rTemp);
				UnionRgn(rScreen, rTemp, rScreen);
				}
			}
		else
			{
			CopyRgn(rOld, rScreen);
			}
	
		//	¥	Gap
		// convert the revealed rect from port to local so that we can check
		// to see if it intersects the gap rect
		Rect rReveal;			
		GetRevealedRect(rReveal);
		PortToLocalPoint(topLeft(rReveal));
		PortToLocalPoint(botRight(rReveal));

		if (!EmptyRect(&rGap) && IsVisible() && ::SectRect(&rGap, &rReveal, &rGap))
			{
			RectRgn(rgn, &rGap);
//			RGBColor	green = {0, 0xffff, 0};	RGBForeColor(&green);	PaintRgn(rgn);
			Boolean	didit = false;

			try
				{
				StOffscreenGWorld	smoothit(rGap, 0, useTempMem);
				mTextEngine->SetPort(UQDGlobals::GetCurrentPort());
				DrawSelf();
				didit = true;
				}
			catch (ExceptionCode inErr)
				{
				// something went wrong in the allocation of the offscreen
				// drawing world, draw on screen
				}

			mTextEngine->SetPort(UQDGlobals::GetCurrentPort());

			if (!didit)
				{
				StClipRgnState		clipMe(rgn);
				DrawSelf();
				}

			//	knock out gap area and update selection
			DiffRgn(rScreen, rgn, rScreen);
			DiffRgn(mOldSelectionRgn, rgn, rTemp);
			MutateSelectionSelf(oldSelectionIsCaret, rScreen, mOldSelectionIsCaret, rTemp);
			}
		else
			{
			MutateSelectionSelf(oldSelectionIsCaret, rScreen, mOldSelectionIsCaret, mOldSelectionRgn);
			}
		}
}



// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CTXTextView::GetViewArea(SPoint32 *outOrigin, SDimension32 *outSize)
{
	Rect			r;

	if (!CalcLocalFrameRect(r))
		Throw_(paramErr);

	GetScrollPosition(*outOrigin);
	outSize->width = r.right - r.left;
	outSize->height = URange32::Min(r.bottom - r.top, mImageSize.height - outOrigin->v);
}



#pragma global_optimizer reset