home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-10-30 | 27.4 KB | 990 lines | [TEXT/PJMM] |
- unit WELowLevelEditing;
-
- { WASTE PROJECT: }
- { Low-Level Editing Routines }
-
- { Copyright © 1993-1994 Marco Piovanelli }
- { All Rights Reserved }
-
- interface
- uses
- WESelecting;
-
- { routines for implementing intelligent cut-and-paste rules }
-
- function _WEIsWordRange (rangeStart, rangeEnd: LongInt;
- hWE: WEHandle): Boolean;
- procedure _WEIntelligentCut (var rangeStart, rangeEnd: LongInt;
- hWE: WEHandle);
- function _WEIntelligentPaste (rangeStart, rangeEnd: LongInt;
- hWE: WEHandle): Integer;
-
- { low-level editing routines }
-
- function _WEDeleteRange (rangeStart, rangeEnd: LongInt;
- hWE: WEHandle): OSErr;
- function _WEInsertText (offset: LongInt;
- textPtr: Ptr;
- textLength: LongInt;
- hWE: WEHandle): OSErr;
- function _WEApplyStyleScrap (rangeStart, rangeEnd: LongInt;
- hStyles: StScrpHandle;
- hWE: WEHandle): OSErr;
- function _WEApplySoup (offset: LongInt;
- hSoup: Handle;
- hWE: WEHandle): OSErr;
- function _WESetStyleRange (rangeStart, rangeEnd: LongInt;
- mode: Integer;
- var ts: WETextStyle;
- hWE: WEHandle): OSErr;
- function _WERedraw (rangeStart, rangeEnd: LongInt;
- hWE: WEHandle): OSErr;
-
- implementation
-
- function _WEIsWordRange (rangeStart, rangeEnd: LongInt;
- hWE: WEHandle): Boolean;
-
- { _WEIsWordRange returns TRUE if the specified range is a word range, }
- { i.e. if it would be possible to select it by double-clicking and (optionally) dragging. }
-
- var
- wordStart, wordEnd: LongInt;
- begin
- _WEIsWordRange := false;
-
- { determine if rangeStart is at the beginning of a word }
- WEFindWord(rangeStart, kLeadingEdge, wordStart, wordEnd, hWE);
- if (rangeStart = wordStart) then
- begin
-
- { determine if rangeEnd is at the end of a word }
- WEFindWord(rangeEnd, kTrailingEdge, wordStart, wordEnd, hWE);
- _WEIsWordRange := (rangeEnd = wordEnd);
- end;
- end; { _WEIsWordRange }
-
- function _WEIsPunct (offset: LongInt;
- hWE: WEHandle): Boolean;
- var
- cType: Integer;
- begin
- _WEIsPunct := false;
- cType := WECharType(offset, hWE);
- if (BitAnd(cType, smcTypeMask) = smCharPunct) then
- begin
- cType := BitAnd(cType, smcClassMask);
- if (cType = smPunctNormal) or (cType = smPunctBlank) then
- _WEIsPunct := true;
- end;
- end; { _WEIsPunct }
-
- procedure _WEIntelligentCut (var rangeStart, rangeEnd: LongInt;
- hWE: WEHandle);
-
- { _WEIntelligentCut is called by other WASTE routines to determine the actual }
- { range to be deleted when weFIntCutAndPaste is enabled. }
- { On entry, rangeStart and rangeEnd specify the selection range visible to the user. }
- { On exit, rangeStart and rangeEnd specify the actual range to be removed. }
-
- begin
-
- { do nothing if the intelligent cut-and-paste feature is disabled }
- if (not BTST(hWE^^.flags, weFIntCutAndPaste)) then
- Exit(_WEIntelligentCut);
-
- { intelling cut-&-paste rules should be applied only to word ranges... }
- if (_WEIsWordRange(rangeStart, rangeEnd, hWE) = false) then
- Exit(_WEIntelligentCut);
-
- { ...without punctuation characters at the beginning or end }
- if (_WEIsPunct(rangeStart, hWE)) then
- Exit(_WEIntelligentCut);
- if (_WEIsPunct(rangeEnd - 1, hWE)) then
- Exit(_WEIntelligentCut);
-
- { if the character preceding the selection range is a space, discard it }
- if (WEGetChar(rangeStart - 1, hWE) = CHR(32)) then
- rangeStart := rangeStart - 1
-
- { else, if the character following the selection range is a space, discard it }
- else if (WEGetChar(rangeEnd, hWE) = CHR(32)) then
- rangeEnd := rangeEnd + 1;
-
- end; { _WEIntelligentCut }
-
- function _WEIntelligentPaste (rangeStart, rangeEnd: LongInt;
- hWE: WEHandle): Integer;
-
- { _WEIntelligentPaste is called by other WASTE routines to determine whether }
- { an additional space character should be added (before or after) after inserting }
- { new text (usually from the Clipboard or from a drag). }
-
- begin
- _WEIntelligentPaste := weDontAddSpaces;
-
- { do nothing unless the intelligent cut-and-paste feature is enabled }
- if (not BTST(hWE^^.flags, weFIntCutAndPaste)) then
- Exit(_WEIntelligentPaste);
-
- { extra spaces will be added only if the pasted text looks like a word range, }
- { without punctuation characters at the beginning or at the end }
- if _WEIsPunct(rangeStart, hWE) then
- Exit(_WEIntelligentPaste);
- if _WEIsPunct(rangeEnd - 1, hWE) then
- Exit(_WEIntelligentPaste);
-
- { if the character on the left of the pasted text is a punctuation character }
- { and the character on the right isn't, then add a space on the right, and vice versa }
- if _WEIsPunct(rangeStart - 1, hWE) then
- begin
- if (_WEIsPunct(rangeEnd, hWE) = false) then
- _WEIntelligentPaste := weAddSpaceOnRightSide;
- end
- else if _WEIsPunct(rangeEnd, hWE) then
- _WEIntelligentPaste := weAddSpaceOnLeftSide;
-
- end; { _WEIntelligentPaste }
-
- function _WEInsertRun (runIndex: LongInt;
- offset, styleIndex: LongInt;
- pWE: WEPtr): OSErr;
-
- { Insert a new element in the style run array, at the specified runIndex position. }
- { The new element consists of the pair <offset, styleIndex>. }
-
- var
- element: RunArrayElement;
- err: OSErr;
- begin
- _WEInsertRun := noErr;
-
- { prepare the element record to be inserted in the array }
- element.runStart := offset;
- element.styleIndex := styleIndex;
-
- { do the insertion }
- err := _WEInsertSlot(pWE^.hRuns, @element, runIndex + 1, SizeOf(element));
- if (err <> noErr) then
- begin
- _WEInsertRun := err;
- Exit(_WEInsertRun);
- end;
-
- { increment style run count }
- pWE^.nRuns := pWE^.nRuns + 1;
-
- { increment the reference count field of the style table element }
- { referenced by the newly inserted style run }
- with pWE^.hStyles^^[styleIndex] do
- refCount := refCount + 1;
-
- end; { _WEInsertRun }
-
- function _WERemoveRun (runIndex: LongInt;
- pWE: WEPtr): OSErr;
-
- { remove the specified element from the style run array }
-
- var
- styleIndex: LongInt;
- begin
-
- styleIndex := pWE^.hRuns^^[runIndex].styleIndex;
-
- { do the removal (errors returned by _WERemoveSlot can be safely ignored) }
- _WERemoveRun := _WERemoveSlot(pWE^.hRuns, runIndex, SizeOf(RunArrayElement));
-
- { decrement style run count }
- pWE^.nRuns := pWE^.nRuns - 1;
-
- { decrement the reference count field of the style table element }
- { that was referenced by the style run we have just removed }
- with pWE^.hStyles^^[styleIndex] do
- begin
- refCount := refCount - 1;
-
- { dispose of embedded object, if any }
- if (refCount = 0) then
- if (_WEFreeObject(WEObjectDescHandle(info.runStyle.tsObject)) <> noErr) then
- ;
- end;
-
- end; { _WERemoveRun }
-
- procedure _WEChangeRun (runIndex: LongInt;
- newStyleIndex: LongInt;
- keepOld: Boolean;
- pWE: WEPtr);
-
- { change the styleIndex field of the specified element of the style run array }
-
- var
- oldStyleIndex: LongInt;
- hObjectDesc: WEObjectDescHandle;
- begin
-
- { do the change }
- with pWE^.hRuns^^[runIndex] do
- begin
- oldStyleIndex := styleIndex;
- styleIndex := newStyleIndex;
- end;
-
- { increment the reference count field of the new style table element }
- with pWE^.hStyles^^[newStyleIndex] do
- begin
- refCount := refCount + 1;
- hObjectDesc := WEObjectDescHandle(info.runStyle.tsObject);
- end;
-
- { decrement the reference count field of the old style table element }
- with pWE^.hStyles^^[oldStyleIndex] do
- begin
- refCount := refCount - 1;
-
- { dispose of embedded object, if any, unless it is again referenced in the new style }
- if ((refCount = 0) and (keepOld = false)) then
- if (WEObjectDescHandle(info.runStyle.tsObject) <> hObjectDesc) then
- if (_WEFreeObject(WEObjectDescHandle(info.runStyle.tsObject)) <> noErr) then
- ;
-
- end;
- end; { _WEChangeRun }
-
- function _WENewStyle (var ts: WERunAttributes;
- var styleIndex: LongInt;
- pWE: WEPtr): OSErr;
-
- { given the specified WERunAttributes record, find the corresponding entry }
- { in the style table (create a new entry if necessary), and return its index }
-
- var
- pTable: StyleTablePtr;
- element: StyleTableElement;
- index, unusedIndex: LongInt;
- err: OSErr;
- begin
- _WENewStyle := noErr;
- pTable := pWE^.hStyles^;
-
- { see if the given style already exists in the style table }
- { while scanning the table, also remember the position of the first unused style, if any }
- index := 0;
- unusedIndex := -1;
- while (index < pWE^.nStyles) do
- begin
-
- { perform a bitwise comparison between the current element and the specified style }
- if _WEBlockCmp(@pTable^[index].info, @ts, SizeOf(ts)) then
- begin
- styleIndex := index; { found: style already present }
- Exit(_WENewStyle);
- end;
-
- { check for entries which aren't referenced and can be recycled }
- if (pTable^[index].refCount = 0) then
- unusedIndex := index;
-
- index := index + 1;
- end; { while }
-
- { the specified style doesn't exist in the style table }
- { see if we can recycle an unused entry }
- if (unusedIndex >= 0) then
- begin
- index := unusedIndex;
- pTable^[index].info := ts;
- end
- else
- begin
-
- { no reusable entry: we have to append a new element to the table }
- element.refCount := 0;
- element.info := ts;
- err := _WEInsertSlot(pWE^.hStyles, @element, index, SizeOf(element));
- if (err <> noErr) then
- begin
- _WENewStyle := err;
- Exit(_WENewStyle);
- end;
-
- { update style count in the WE record }
- pWE^.nStyles := index + 1;
-
- end;
-
- { return the index to the new element }
- styleIndex := index;
-
- end; { _WENewStyle }
-
- function _WERedraw (rangeStart, rangeEnd: LongInt;
- hWE: WEHandle): OSErr;
-
- { the WE record is guaranteed to be already locked }
-
- label
- 1;
- var
- pWE: WEPtr;
- pLines: LineArrayPtr;
- startLine, endLine: LongInt;
- oldTextHeight, newTextHeight: LongInt;
- r: LongRect;
- viewRect, updateRect: Rect;
- saveClip: RgnHandle;
- savePort: GrafPtr;
- err: OSErr;
- begin
- pWE := hWE^;
-
- { do nothing if recalculation has been inhibited }
- if (not BTST(pWE^.flags, weFInhibitRecal)) then
- begin
-
- { hide the caret }
- if BTST(pWE^.flags, weFCaretVisible) then
- _WEBlinkCaret(hWE);
-
- { remember total text height }
- oldTextHeight := pWE^.destRect.bottom - pWE^.destRect.top;
-
- { find line range affected by modification }
- startLine := WEOffsetToLine(rangeStart, hWE);
- endLine := WEOffsetToLine(rangeEnd, hWE);
-
- { recalculate line breaks starting from startLine }
- err := _WERecalBreaks(startLine, endLine, hWE);
- if (err <> noErr) then
- goto 1;
-
- { recalculate slops }
- _WERecalSlops(startLine, endLine, hWE);
-
- { calculate new total text height }
- newTextHeight := pWE^.destRect.bottom - pWE^.destRect.top;
-
- { calculate the rectangle to redraw (in long coordinates) }
- r.left := -maxint;
- r.right := maxint;
- pLines := pWE^.hLines^;
- r.top := pLines^[startLine].lineOrigin;
-
- { if total text height hasn't changed, it's enough to redraw lines up to endLine }
- { otherwise we must redraw all lines from startLine on }
- if ((newTextHeight = oldTextHeight) and (endLine < pWE^.nLines - 1)) then
- r.bottom := pLines^[endLine + 1].lineOrigin
- else if (newTextHeight < oldTextHeight) then
- r.bottom := oldTextHeight
- else
- r.bottom := newTextHeight;
-
- WEOffsetLongRect(r, 0, pWE^.destRect.top);
-
- { calculate the intersection between this rectangle and the view rectangle }
- WELongRectToRect(r, updateRect);
- WELongRectToRect(pWE^.viewRect, viewRect);
-
- if SectRect(updateRect, viewRect, updateRect) then
- begin
-
- { set up the port and the clip region }
- GetPort(savePort);
- SetPort(pWE^.port);
-
- { set the clip region to updateRect }
- saveClip := NewRgn;
- GetClip(saveClip);
- ClipRect(updateRect);
-
- { we only really need to redraw the visible lines }
- startLine := _WEPixelToLine(updateRect.top - pWE^.destRect.top, hWE);
- endLine := _WEPixelToLine(updateRect.bottom - pWE^.destRect.top - 1, hWE);
-
- { redraw the lines (pass TRUE in the doErase parameter) }
- _WEDrawLines(startLine, endLine, true, hWE);
-
- { erase the portion of the update rectangle below the last line (if any) }
- pLines := pWE^.hLines^;
- updateRect.top := pWE^.destRect.top + pLines^[endLine + 1].lineOrigin;
- if (updateRect.top < updateRect.bottom) then
- EraseRect(updateRect);
-
- { restore the clip region }
- SetClip(saveClip);
- DisposeRgn(saveClip);
-
- { restore the port }
- SetPort(savePort);
-
- { redraw the caret or the selection range }
- if (pWE^.selStart < pWE^.selEnd) then
- _WEHiliteRange(pWE^.selStart, pWE^.selEnd, hWE)
- else
- _WEBlinkCaret(hWE);
-
- end; { if SectRect }
-
- { scroll the selection range into view }
- WESelView(hWE);
-
- end; { if recal not inhibited }
-
- { clear result code }
- err := noErr;
-
- 1:
- { return result code }
- _WERedraw := err;
-
- end; { _WERedraw }
-
- function _WESetStyleRange (rangeStart, rangeEnd: LongInt;
- mode: Integer;
- var ts: WETextStyle;
- hWE: WEHandle): OSErr;
-
- { alter the style attributes of the specified text range according to ts and mode }
- { the WE record is guaranteed to be already locked }
-
- label
- 1;
- var
- pWE: WEPtr;
- hRuns: RunArrayHandle;
- offset: LongInt;
- runIndex: LongInt;
- oldStyleIndex, newStyleIndex: LongInt;
- runInfo: WERunInfo;
- temp: Integer;
- continuousStyles: SignedByte;
- err: OSErr;
- begin
- pWE := hWE^;
- hRuns := pWE^.hRuns;
-
- { if mode contains weDoToggleFace, we need to determine which QuickDraw styles }
- { are continuous over the specified text range: those styles must be turned off }
- if BTST(mode, kModeToggleFace) then
- begin
- temp := weDoFace;
- _WEContinuousStyleRange(rangeStart, rangeEnd, temp, runInfo.runAttrs.runStyle, hWE);
- continuousStyles := runInfo.runAttrs.runStyle.tsFace;
- end
- else
- continuousStyles := 0;
-
- { find the index to the first style run in the specified range }
- offset := rangeStart;
- runIndex := _WEOffsetToRun(offset, hWE);
-
- { run thru all the style runs that encompass the selection range }
- repeat
-
- { find style index for this run and retrieve corresponding style attributes }
- oldStyleIndex := hRuns^^[runIndex].styleIndex;
- _WEGetIndStyle(runIndex, runInfo, hWE);
-
- { _WEGetIndStyle returns textLength + 1 in runInfo.runEnd for the last style run: }
- { correct this anomaly (which is useful for other purposes, anyway) }
- if (runInfo.runEnd > pWE^.textLength) then
- runInfo.runEnd := pWE^.textLength;
-
- { apply changes to existing style attributes as requested }
- _WECopyStyle(ts, runInfo.runAttrs.runStyle, continuousStyles, mode);
-
- { recalculate font metrics, if necessary }
- if (BitAnd(mode, weDoFont + weDoSize + weDoFace + weDoAddSize) <> 0) then
- _WEFillFontInfo(pWE^.port, runInfo.runAttrs);
-
- { get a style index for the new attributes }
- err := _WENewStyle(runInfo.runAttrs, newStyleIndex, pWE);
- if (err <> noErr) then
- goto 1;
-
- { if offset falls on a style boundary and this style run has become identical }
- { to the previous one, merge the two runs together }
- if (offset = runInfo.runStart) & (runIndex > 0) & (hRuns^^[runIndex - 1].styleIndex = newStyleIndex) then
- begin
- err := _WERemoveRun(runIndex, pWE);
- if (err <> noErr) then
- goto 1;
- runIndex := runIndex - 1;
- end;
-
- { style index changed? }
- if (oldStyleIndex <> newStyleIndex) then
- begin
-
- { if offset is in the middle of a style run, insert a new style run in the run array }
- if (offset > runInfo.runStart) then
- begin
- err := _WEInsertRun(runIndex, offset, newStyleIndex, pWE);
- if (err <> noErr) then
- goto 1;
- runIndex := runIndex + 1;
- end
- else
-
- { otherwise just change the styleIndex field of the current style run element }
- _WEChangeRun(runIndex, newStyleIndex, rangeEnd < runInfo.runEnd, pWE);
-
- { if specified range ends in the middle of a style run, insert yet another element }
- if (rangeEnd < runInfo.runEnd) then
- begin
- err := _WEInsertRun(runIndex, rangeEnd, oldStyleIndex, pWE);
- if (err <> noErr) then
- goto 1;
- end;
-
- end; { if oldStyle <> newStyle }
-
- { go to next style run }
- runIndex := runIndex + 1;
- offset := runInfo.runEnd;
-
- until (offset >= rangeEnd);
-
- { if the last style run ends exactly at the end of the specified range, }
- { see if we can merge it with the following style run }
- if ((offset = rangeEnd) & (runIndex < pWE^.nRuns) & (hRuns^^[runIndex].styleIndex = newStyleIndex)) then
- begin
- err := _WERemoveRun(runIndex, pWE);
- if (err <> noErr) then
- goto 1;
- end;
-
- { clear result code }
- err := noErr;
-
- 1:
- { return result code }
- _WESetStyleRange := err;
-
- end; { _WESetStyleRange }
-
- function _WEApplyStyleScrap (rangeStart, rangeEnd: LongInt;
- hStyles: StScrpHandle;
- hWE: WEHandle): OSErr;
-
- { apply the given style scrap to the specified text range }
- { the WE record is guaranteed to be already locked }
-
- var
- pWE: WEPtr;
- pElement: TEStyleScrapPeek;
- runStart, runEnd: LongInt;
- index, lastElement: Integer;
- ts: WETextStyle;
- err: OSErr;
- begin
- _WEApplyStyleScrap := noErr;
- pWE := hWE^;
-
- { loop through each element of the style scrap }
- lastElement := hStyles^^.scrpNStyles - 1;
- for index := 0 to lastElement do
- begin
-
- { get a pointer to the current scrap element }
- pElement := @hStyles^^.scrpStyleTab[index];
-
- { calculate text run to which this element is to be applied }
- runStart := rangeStart + pElement^.first.scrpStartChar;
- if (index < lastElement) then
- runEnd := rangeStart + pElement^.second.scrpStartChar
- else
- runEnd := rangeEnd;
-
- { perform some range checking }
- if (runEnd > rangeEnd) then
- runEnd := rangeEnd;
- if (runStart >= runEnd) then
- Cycle;
-
- { copy TextEdit style to a local variable in case memory moves }
- ts.tsTEStyle := pElement^.first.scrpTEAttrs.runTEStyle;
-
- { apply the specified style to the range }
- err := _WESetStyleRange(runStart, runEnd, weDoAll + weDoReplaceFace, ts, hWE);
- if (err <> noErr) then
- begin
- _WEApplyStyleScrap := err;
- Exit(_WEApplyStyleScrap);
- end;
-
- end; { for }
- end; { _WEApplyStyleScrap }
-
- function _WEApplySoup (offset: LongInt;
- hSoup: Handle;
- hWE: WEHandle): OSErr;
- label
- 1;
- var
- pSoup: WESoupPtr;
- pSoupEnd: LongInt;
- ts: WETextStyle;
- hObjectData: Handle;
- objectOffset: LongInt;
- saveWELock: Boolean;
- err: OSErr;
- begin
- _WEBlockClr(@ts, SizeOf(ts));
- hObjectData := nil;
-
- { lock the WE record }
- saveWELock := _WESetHandleLock(hWE, true);
-
- { lock the soup in high heap }
- HLockHi(hSoup);
- pSoup := WESoupPtr(hSoup^);
- pSoupEnd := LongInt(pSoup) + %_GetHandleSize(hSoup);
-
- { loop through each object descriptor in the soup }
- while (LongInt(pSoup) < pSoupEnd) do
- begin
-
- { create a new relocatable block the hold the object data }
- err := _WEAllocate(pSoup^.soupDataSize, kAllocTemp, hObjectData);
- if (err <> noErr) then
- goto 1;
-
- { copy the object data to this block }
- %_BlockMoveData(Ptr(LongInt(pSoup) + SizeOf(WESoup)), hObjectData^, pSoup^.soupDataSize);
-
- { create a new object out of the tagged data }
- err := _WENewObject(pSoup^.soupType, hObjectData, hWE, WEObjectDescHandle(ts.tsObject));
- if (err <> noErr) then
- goto 1;
-
- { record a reference to the object descriptor in the style table }
- objectOffset := pSoup^.soupOffset + offset;
- err := _WESetStyleRange(objectOffset, objectOffset + 1, weDoObject, ts, hWE);
- hObjectData := nil;
- ts.tsObject := kNullObject;
- if (err <> noErr) then
- goto 1;
-
- { advance soup pointer }
- pSoup := WESoupPtr(LongInt(pSoup) + SizeOf(WESoup) + pSoup^.soupDataSize);
-
- end; { while }
-
- { clear result code }
- err := noErr;
-
- 1:
- { return result code }
- _WEApplySoup := err;
-
- { clean up }
- HUnlock(hSoup);
- _WEForgetHandle(ts.tsObject);
- _WEForgetHandle(hObjectData);
-
- { unlock the WE record }
- IgnoreBoolean(_WESetHandleLock(hWE, saveWELock));
-
- end; { _WEApplySoup }
-
- procedure _WEBumpRunStart (runIndex: LongInt;
- deltaRunStart: LongInt;
- pWE: WEPtr);
-
- { add deltaLineStart to the lineStart field of all line records }
- { starting from lineIndex }
-
- var
- pStart: LongIntPtr;
- nRuns: LongInt;
- begin
- pStart := @pWE^.hRuns^^[runIndex].runStart;
- nRuns := pWE^.nRuns;
-
- { loop through the style run array adjusting the runStart fields }
- while (runIndex <= nRuns) do
- begin
- pStart^ := pStart^ + deltaRunStart;
- pStart := LongIntPtr(LongInt(pStart) + SizeOf(RunArrayElement));
- runIndex := runIndex + 1;
- end;
- end; { _WEBumpRunStart }
-
- function _WERemoveRunRange (rangeStart, rangeEnd: LongInt;
- hWE: WEHandle): OSErr;
-
- { the range of text between rangeStart and rangeEnd is being deleted }
- { update the style run array (and the style table) accordingly }
- { the WE handle must be locked on entry }
-
- label
- 1;
- var
- pWE: WEPtr;
- pRuns: RunArrayPeek;
- startRun, endRun: LongInt;
- err: OSErr;
- begin
- pWE := hWE^;
-
- { find the index to the first and last style runs in the specified range }
- startRun := _WEOffsetToRun(rangeStart, hWE);
- endRun := _WEOffsetToRun(rangeEnd, hWE) - 1;
-
- { remove all style runs between startRun and endRun }
- while (endRun > startRun) do
- begin
- err := _WERemoveRun(endRun, pWE);
- if (err <> noErr) then
- goto 1;
- endRun := endRun - 1;
- end;
-
- { move back all subsequent style runs }
- _WEBumpRunStart(startRun + 1, rangeStart - rangeEnd, pWE);
-
- if (endRun = startRun) and (endRun < pWE^.nRuns - 1) then
- begin
- pRuns := @pWE^.hRuns^^[endRun];
- pRuns^.second.runStart := rangeStart;
- end;
-
- { remove the first style run if is has become zero length }
- pRuns := @pWE^.hRuns^^[startRun];
- if (pRuns^.first.runStart = pRuns^.second.runStart) then
- begin
- err := _WERemoveRun(startRun, pWE);
- if (err <> noErr) then
- goto 1;
- startRun := startRun - 1;
- end;
-
- { merge the first and last runs if they have the same style index }
- if (startRun >= 0) then
- begin
- pRuns := @pWE^.hRuns^^[startRun];
- if (pRuns^.first.styleIndex = pRuns^.second.styleIndex) then
- begin
- err := _WERemoveRun(startRun + 1, pWE);
- if (err <> noErr) then
- goto 1;
- end;
- end;
-
- { clear result code }
- err := noErr;
-
- 1:
- { return result code }
- _WERemoveRunRange := err;
-
- end; { _WERemoveRunRange }
-
- procedure _WEBumpLineStart (lineIndex: LongInt;
- deltaLineStart: LongInt;
- pWE: WEPtr);
-
- { add deltaLineStart to the lineStart field of all line records }
- { starting from lineIndex }
-
- var
- pStart: LongIntPtr;
- nLines: LongInt;
- begin
- pStart := @pWE^.hLines^^[lineIndex].lineStart;
- nLines := pWE^.nLines;
-
- { loop through the line array adjusting the lineStart fields }
- while (lineIndex <= nLines) do
- begin
- pStart^ := pStart^ + deltaLineStart;
- pStart := LongIntPtr(LongInt(pStart) + SizeOf(LineRec));
- lineIndex := lineIndex + 1;
- end;
- end; { _WEBumpLineStart }
-
- function _WERemoveLineRange (rangeStart, rangeEnd: LongInt;
- hWE: WEHandle): OSErr;
-
- { the range of text between rangeStart and rangeEnd is being deleted }
- { update the line array accordingly }
- { the WE handle must be locked on entry }
-
- var
- pWE: WEPtr;
- startLine, endLine: LongInt;
- err: OSErr;
- begin
- _WERemoveLineRange := noErr;
- pWE := hWE^;
-
- { remove all line records between rangeStart and rangeEnd }
- startLine := WEOffsetToLine(rangeStart, hWE) + 1;
- endLine := WEOffsetToLine(rangeEnd, hWE);
- while (endLine >= startLine) do
- begin
- err := _WERemoveLine(endLine, pWE);
- if (err <> noErr) then
- begin
- _WERemoveLineRange := err;
- Exit(_WERemoveLineRange);
- end;
- endLine := endLine - 1;
- end; { while }
-
- { update the lineStart field of all the line records that follow }
- _WEBumpLineStart(startLine, rangeStart - rangeEnd, pWE);
-
- end; { _WERemoveLineRange }
-
- function _WEDeleteRange (rangeStart, rangeEnd: LongInt;
- hWE: WEHandle): OSErr;
-
- { used internally to delete a text range }
- { if saveNullStyle is TRUE, the first style in the range is saved in nullStyle }
- { the WE record is guaranteed to be already locked }
-
- label
- 0, 1;
- var
- pWE: WEPtr;
- runInfo: WERunInfo;
- oldTextLength, newTextLength: LongInt;
- pText: LongInt;
- err: OSErr;
- begin
- pWE := hWE^;
-
- { do nothing if the specified range is empty }
- if (rangeStart = rangeEnd) then
- goto 0;
-
- { save the first style in the specified range in nullStyle }
- WEGetRunInfo(rangeStart, runInfo, hWE);
- pWE^.nullStyle := runInfo.runAttrs;
- BSET(pWE^.flags, weFUseNullStyle);
-
- { special case: if we're deleting up to the end of the text, see whether }
- { there's an embedded object at the very end and remove it }
- if (rangeEnd = pWE^.textLength) then
- begin
- WEGetRunInfo(rangeEnd - 1, runInfo, hWE);
- if (runInfo.runAttrs.runStyle.tsObject <> kNullObject) then
- begin
- runInfo.runAttrs.runStyle.tsObject := kNullObject;
- err := _WESetStyleRange(rangeEnd - 1, rangeEnd, weDoObject, runInfo.runAttrs.runStyle, hWE);
- if (err <> noErr) then
- goto 1;
- end;
- end;
-
- { remove all line records between rangeStart and rangeEnd }
- err := _WERemoveLineRange(rangeStart, rangeEnd, hWE);
- if (err <> noErr) then
- goto 1;
-
- { remove all style runs between rangeStart and rangeEnd }
- err := _WERemoveRunRange(rangeStart, rangeEnd, hWE);
- if (err <> noErr) then
- goto 1;
-
- { calculate old and new text length }
- oldTextLength := pWE^.textLength;
- newTextLength := oldTextLength - (rangeEnd - rangeStart);
-
- { move the end of the text backwards over the old selection range }
- pText := LongInt(pWE^.hText^);
- %_BlockMoveData(Ptr(pText + rangeEnd), Ptr(pText + rangeStart), oldTextLength - rangeEnd);
-
- { compact the text handle }
- err := %_SetHandleSize(pWE^.hText, newTextLength);
- if (err <> noErr) then
- goto 1;
-
- { update textLength field }
- pWE^.textLength := newTextLength;
-
- 0:
- { clear result code }
- err := noErr;
-
- 1:
- { return result code }
- _WEDeleteRange := err;
-
- end; { _WEDeleteRange }
-
- function _WEInsertText (offset: LongInt;
- textPtr: Ptr;
- textLength: LongInt;
- hWE: WEHandle): OSErr;
-
- { this routine assumes that the WE record is already locked }
-
- label
- 0, 1;
- var
- pWE: WEPtr;
- oldTextLength, newTextLength: LongInt;
- pInsPoint: LongInt;
- mode: Integer;
- err: OSErr;
- begin
- pWE := hWE^;
-
- { do nothing if textLength is zero or negative }
- if (textLength <= 0) then
- goto 0;
-
- { calculate old and new length of text handle }
- oldTextLength := pWE^.textLength;
- newTextLength := oldTextLength + textLength;
-
- { lengthen the raw text handle }
- err := %_SetHandleSize(pWE^.hText, newTextLength);
- if (err <> noErr) then
- goto 1;
-
- { calculate ptr to insertion point }
- pInsPoint := LongInt(pWE^.hText^) + offset;
-
- { make room for the new text }
- %_BlockMoveData(Ptr(pInsPoint), Ptr(pInsPoint + textLength), oldTextLength - offset);
-
- { insert new text at the insertion point }
- %_BlockMoveData(textPtr, Ptr(pInsPoint), textLength);
-
- { update the lineStart fields of all lines following the insertion point }
- _WEBumpLineStart(WEOffsetToLine(offset, hWE) + 1, textLength, pWE);
-
- { update the runStart fields of all style runs following the insertion point }
- _WEBumpRunStart(_WEOffsetToRun(offset - 1, hWE) + 1, textLength, pWE);
-
- { update various fields in the WE record }
- pWE^.textLength := newTextLength;
-
- { make sure the newly inserted text doesn't reference any embedded object }
- pWE^.nullStyle.runStyle.tsObject := kNullObject;
- mode := weDoObject;
-
- { if there is a valid null style, apply it to the newly inserted text }
- if BTST(pWE^.flags, weFUseNullStyle) then
- mode := mode + (weDoAll + weDoReplaceFace);
-
- err := _WESetStyleRange(offset, offset + textLength, mode, pWE^.nullStyle.runStyle, hWE);
- if (err <> noErr) then
- goto 1;
-
- 0:
- { clear result code }
- err := noErr;
-
- 1:
- { return result code }
- _WEInsertText := err;
-
- end; { _WEInsertText }
-
- end.