{UText4} {TEXT SELECTION TYPES AND COMMANDS} {changed 04/27/84 1307 Change to TTypingCmd.Perform} {changed 04/25/84 1406 Got rid of IF numParas = 1 in Adjust proc in InsertText} {changed 04/25/84 1250 Changed TStyleCmd.FilterAndDo back to filtering TParaImage for Compugraphic} {changed 04/19/84 1308 Set up fields for partial line erasing in KeyPause} {changed 04/17/84 1720 In TTextSelection.CutCopy, changed "IF firstLP >= 0" to "IF firstLP > 0"} {changed 04/16/84 1414 Set viewLRect origined at (0,0) in TTextSelection.CutCopy} {changed 04/16/84 1322 Set textImage.minHeight to 0 in TOnePara and TMultiPara.CopySelf} {changed 04/16/84 1024 Call recomputeImages in TOnePara and TMultiPara.CopySelf to set clipView size} {changed 04/13/84 1736 First parameter decremented in calls to TParagraph.StyleAt; No longer set unHighlightBefore[doPhase] to FALSE in typingCmd; Set TInsertionPoint.justReturned to FALSE in all Key methods (except KeyReturn); Call StyleFromContext in TStyleCmd.Perform} {changed 04/13/84 1531 TStyleCmd.FilterAndDo now filters a TEditPara rather than a TParaImage; Call StyleFromContext through a filter in TTextSelection.CREATE} {changed 04/13/84 1102 TInsertion.MousePress: Allow selecting of word when double click on last half of last character in word} {changed 04/13/84 0209 Changed all calls to TEditPara.CREATE to TTextImage.NewEditPara} {changed 04/09/84 1530 Set highlightAfter[doPhase] FALSE in TTypingCmd.CREATE} {changed 04/09/84 1337 Set deferUpdate TRUE in TTypingCmd.Perform (do phase)} {changed 04/09/84 1202 TInsertion.MousePress: Made sure all insertion points had their isPara flags set when triple click on an empty paragraph; TInsertionPoint.MouseMove: Don't unHighlight if isPara was TRUE} {$S SgTxtHot} METHODS OF TTextSelection; {$S SgTxtHot} FUNCTION TTextSelection.CREATE(object: TObject; heap: THeap; itsView: TView; itsTextImage: TTextImage; itsAnchorLPt: LPoint; beginPara: TEditPara; beginIndex: LONGINT; beginLP: INTEGER; endPara: TEditPara; endIndex: LONGINT; endLP: INTEGER ): TTextSelection; {Need to filter paragraph before asking about its type styles} PROCEDURE FindFilteredStyle(obj: TObject); BEGIN SELF.StyleFromContext; END; VAR range: TTextRange; BEGIN {$IFC fTrace}BP(9);{$ENDC} IF object = NIL THEN object := NewObject(heap, THISCLASS); SELF := TTextSelection(TSelection.CREATE(object, heap, itsView, somethingKind, itsAnchorLPt)); range := TTextRange.CREATE(NIL, heap, beginPara, beginIndex, beginLP, endPara, endIndex, endLP); WITH SELF DO BEGIN textImage := itsTextImage; textRange := range; isWordSelection := FALSE; isParaSelection := FALSE; amTyping := FALSE; viewTick := -1; { force recalculation of selection range } END; SELF.textImage.FilterAndDo(TParaImage(beginPara.images.First), FindFilteredStyle); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TTextSelection.Free; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.textRange.Free; SUPERSELF.Free; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtWrm} FUNCTION TTextSelection.Clone(heap: THeap): TObject; VAR textSel: TTextSelection; range: TTextRange; BEGIN {$IFC fTrace}BP(10);{$ENDC} range := TTextRange(SELF.textRange.Clone(heap)); textSel := TTextSelection(SUPERSELF.Clone(heap)); textSel.textRange := range; Clone := textSel; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} {$IFC fTextTrace} PROCEDURE TTextSelection.Fields(PROCEDURE Field(nameAndType: S255)); BEGIN SUPERSELF.Fields(Field); Field('textImage: TTextImage'); Field('textRange: TTextRange'); Field('isWordSelection: BOOLEAN'); Field('isParaSelection: BOOLEAN'); Field('viewTick: INTEGER'); Field('amTyping: BOOLEAN'); Field('onFaces: INTEGER'); Field('font: INTEGER'); Field(''); END; {$ENDC} {$S SgTxtHot} FUNCTION TTextSelection.BecomeInsertionPoint: TInsertionPoint; VAR insertionPt: TInsertionPoint; BEGIN {$IFC fTrace}BP(11);{$ENDC} insertionPt := TInsertionPoint(SELF.FreedAndReplacedBy( TInsertionPoint.CREATE(NIL, SELF.Heap, SELF.view, SELF.textImage, SELF.anchorLPt, SELF.textRange.firstPara, SELF.textRange.firstIndex, SELF.textRange.firstLP))); SELF.textImage.text.ChangeSelInOtherPanels(insertionPt); BecomeInsertionPoint := insertionPt; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtWrm} FUNCTION TTextSelection.CanDoCommand(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN; VAR typeStyle: TTypeStyle; BEGIN {$IFC fTrace}BP(10);{$ENDC} CASE cmdNumber OF uModern, uClassic: BEGIN CanDoCommand := TRUE; typeStyle := SELF.currTypeStyle; checkIt := (cmdNumber - uModern + 1) = typeStyle.font.fontFamily; END; u20Pitch, u15Pitch, u12Pitch, u10Pitch, u12Point, u14Point, u18Point, u24Point: BEGIN CanDoCommand := TRUE; typeStyle := SELF.currTypeStyle; checkIt := (cmdNumber - u20Pitch + 1) = typeStyle.font.fontSize; END; {$IFC LibraryVersion <= 20} uFnt0, uFnt1, uFnt2, uFnt3, uFnt4, uFnt5, uFnt6, uFnt7, uFnt8, uFnt9, uFnt10, uFnt11: BEGIN CanDoCommand := TRUE; WITH SELF.currTypeStyle.font DO CASE cmdNumber OF uFnt0: checkIt := fontFamily = famSystem; uFnt1: checkIt := (fontFamily = famModern) AND (fontSize = size15Pitch); uFnt2: checkIt := (fontFamily = famModern) AND (fontSize = size12Pitch); uFnt3: checkIt := (fontFamily = famClassic) AND (fontSize = size12Pitch); uFnt4: checkIt := (fontFamily = famModern) AND (fontSize = size10Pitch); uFnt5: checkIt := (fontFamily = famModern) AND (fontSize = size14Point); uFnt6: checkIt := (fontFamily = famModern) AND (fontSize = size12Point); uFnt7: checkIt := (fontFamily = famClassic) AND (fontSize = size12Point); uFnt8: checkIt := (fontFamily = famModern) AND (fontSize = size18Point); uFnt9: checkIt := (fontFamily = famClassic) AND (fontSize = size18Point); uFnt10: checkIt := (fontFamily = famModern) AND (fontSize = size24Point); uFnt11: checkIt := (fontFamily = famClassic) AND (fontSize = size24Point); END; END; {$ENDC} uPlain, uBold, uItalic, uUnderline, uShadow, uOutline: BEGIN CanDoCommand := TRUE; typeStyle := SELF.currTypeStyle; WITH typeStyle DO CASE cmdNumber OF uPlain: checkIt := onFaces=[]; uBold: checkIt := (bold in onFaces); uItalic: checkIt := (italic in onFaces); uUnderline: checkIt := (underlined in onFaces); uShadow: checkIt := (shadow in onFaces); uOutline: checkIt := (outline in onFaces); END; END; uCut, uCopy, uClear: CanDoCommand := TRUE; uPaste: BEGIN clipboard.Inspect; IF (clipboard.hasView) OR (clipBoard.hasUniversalText) THEN CanDoCommand := TRUE; END; OTHERWISE CanDoCommand := SUPERSELF.CanDoCommand(cmdNumber, checkIt); END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TTextSelection.ChangeStyle(cmdNumber: TCmdNumber); BEGIN {$IFC fTrace}BP(9);{$ENDC} Write(chr(7),'Change typestyle not implemented for this selection type. '); WriteLn ('(cmdNumber= ',cmdNumber:1,')'); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TTextSelection.ChangeText(PROCEDURE TextEdit; PROCEDURE Adjust); BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.MarkChanged; TextEdit; Adjust; IF NOT deferUpdate THEN BEGIN SELF.textImage.text.RecomputeImages; (*SELF.textImage.text.Invalidate;*) END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} FUNCTION TTextSelection.CopySelf(heap: THeap; view: TView): TMultiParaSelection; BEGIN {$IFC fTrace}BP(11);{$ENDC} CopySelf := NIL; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TTextSelection.CutCopy(clipSelection: TSelection; deleteOriginal: BOOLEAN); VAR clipHeap: THeap; clipPanel: TPanel; clipView: TTextView; viewLRect: LRect; text: TText; insPt: TInsertionPoint; clipTextSelection: TMultiParaSelection; selSize: INTEGER; checkLast: BOOLEAN; BEGIN {$IFC fTrace}BP(11);{$ENDC} clipHeap := clipSelection.heap; clipPanel := clipSelection.panel; viewLRect := SELF.textImage.extentLRect; SetLRect(viewLRect, 0, 0, viewLRect.right - viewLRect.left + 2 * cHorizMargin, viewLRect.bottom - viewLRect.top + 2 * cVertMargin); clipView := TTextView.CREATE(NIL, clipHeap, clipPanel, viewLRect); clipTextSelection := TMultiParaSelection(clipSelection.FreedAndReplacedBy( SELF.CopySelf(clipHeap, clipView))); clipView.valid := TRUE; clipTextSelection.isParaSelection := SELF.isParaSelection; clipTextSelection.isWordSelection := SELF.isWordSelection; {Intelligence!! Even if word flag not set, let's see if we qualify as a word selection anyway} IF NOT SELF.isWordSelection THEN WITH SELF.textRange DO {$H-} clipTextSelection.isWordSelection := firstPara.Qualifies(firstLP) AND lastPara.Qualifies(lastLP-1) AND NOT firstPara.Qualifies(firstLP-1) AND NOT lastPara.Qualifies(lastLP); {$H+} clipView.textImage := clipTextSelection.textImage; IF deleteOriginal THEN BEGIN {Intelligent Cut: Delete extra space} IF clipTextSelection.isWordSelection THEN WITH SELF.textRange DO BEGIN {$H-} checkLast := TRUE; IF firstLP > 0 THEN IF firstPara.At(firstLp) = ' ' THEN BEGIN firstLP := firstLP - 1; checkLast := FALSE; END; IF checkLast AND (lastLP < lastPara.size) THEN IF lastPara.At(lastLP + 1) = ' ' THEN lastLP := lastLP + 1; {$H+} END; SELF.DeleteAndFree; insPt := SELF.BecomeInsertionPoint; END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TTextSelection.DeleteAndFree; BEGIN {$IFC fTrace}BP(9);{$ENDC} {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} FUNCTION TTextSelection.DeleteButSave: TText; BEGIN {$IFC fTrace}BP(9);{$ENDC} DeleteButSave := NIL; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TTextSelection.DoChangeStyle(cmdNumber: TCmdNumber; paragraph: TParagraph; firstLP: INTEGER; lastLP: INTEGER; VAR newStyle: TTypeStyle); VAR onFaces: {$IFC LibraryVersion <= 20}TSeteface{$ELSEC}Style{$ENDC}; faceChange: BOOLEAN; BEGIN {$IFC fTrace}BP(10);{$ENDC} {$IFC fTextTrace} IF fTextTrace THEN BEGIN WriteLn('_+_ Entering TTextSelection.DoChangeStyle: firstLP = ', firstLP:1, ' lastLP = ', lastLP:1); END; {$ENDC} faceChange := TRUE; CASE cmdNumber OF uPlain: onFaces := []; uBold: onFaces := [bold]; uItalic: onFaces := [italic]; uUnderline: onFaces := [underlined]; uShadow: onFaces := [shadow]; uOutline: onFaces := [outline]; uModern, uClassic: BEGIN faceChange := FALSE; paragraph.ChgFontFamily(firstLP, lastLP, cmdNumber - uModern + 1, newStyle); END; {$IFC LibraryVersion <= 20} uFnt0, uFnt1, uFnt2, uFnt3, uFnt4, uFnt5, uFnt6, uFnt7, uFnt8, uFnt9, uFnt10, uFnt11: BEGIN faceChange := FALSE; CASE cmdNumber OF uFnt0: paragraph.ChgFontFamily(firstLP, lastLP, famSystem, newStyle); uFnt1: BEGIN paragraph.ChgFontFamily(firstLP, lastLP, famModern, newStyle); paragraph.ChgFontSize(firstLP, lastLP, size15Pitch, newStyle); END; uFnt2: BEGIN paragraph.ChgFontFamily(firstLP, lastLP, famModern, newStyle); paragraph.ChgFontSize(firstLP, lastLP, size12Pitch, newStyle); END; uFnt3: BEGIN paragraph.ChgFontFamily(firstLP, lastLP, famClassic, newStyle); paragraph.ChgFontSize(firstLP, lastLP, size12Pitch, newStyle); END; uFnt4: BEGIN paragraph.ChgFontFamily(firstLP, lastLP, famModern, newStyle); paragraph.ChgFontSize(firstLP, lastLP, size10Pitch, newStyle); END; uFnt5: BEGIN paragraph.ChgFontFamily(firstLP, lastLP, famModern, newStyle); paragraph.ChgFontSize(firstLP, lastLP, size14Point, newStyle); END; uFnt6: BEGIN paragraph.ChgFontFamily(firstLP, lastLP, famModern, newStyle); paragraph.ChgFontSize(firstLP, lastLP, size12Point, newStyle); END; uFnt7: BEGIN paragraph.ChgFontFamily(firstLP, lastLP, famClassic, newStyle); paragraph.ChgFontSize(firstLP, lastLP, size12Point, newStyle); END; uFnt8: BEGIN paragraph.ChgFontFamily(firstLP, lastLP, famModern, newStyle); paragraph.ChgFontSize(firstLP, lastLP, size18Point, newStyle); END; uFnt9: BEGIN paragraph.ChgFontFamily(firstLP, lastLP, famClassic, newStyle); paragraph.ChgFontSize(firstLP, lastLP, size18Point, newStyle); END; uFnt10: BEGIN paragraph.ChgFontFamily(firstLP, lastLP, famModern, newStyle); paragraph.ChgFontSize(firstLP, lastLP, size24Point, newStyle); END; uFnt11: BEGIN paragraph.ChgFontFamily(firstLP, lastLP, famClassic, newStyle); paragraph.ChgFontSize(firstLP, lastLP, size24Point, newStyle); END; END; END; {$ENDC} OTHERWISE BEGIN faceChange := FALSE; paragraph.ChgFontSize(firstLP, lastLP, cmdNumber - u20Pitch + 1, newStyle); END; END; IF faceChange THEN paragraph.ChgFace(firstLP, lastLP, onFaces, newStyle); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TTextSelection.GetHysteresis(VAR hysterPt: Point); BEGIN {$IFC fTrace}BP(6);{$ENDC} hysterPt := zeroPt; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TTextSelection.Highlight(highTransit: THighTransit); BEGIN {$IFC fTrace}BP(10);{$ENDC} {Note that this is called from TPanel.Highlight which does an OnAllPadsDo, thus we do not call TText.HiliteParagraphs, but rather we call TTextImage.HiliteText } IF SELF.textImage.imageList.size > 0 THEN WITH SELF.textRange DO {$H-} SELF.textImage.headTxtImg.HiliteText(highTransit, firstIndex, firstLP, lastIndex, lastLP, SELF.isParaSelection); {$H+} {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TTextSelection.Invalidate; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.textImage.text.Invalidate; {$IFC fTrace}EP;{$ENDC} END; (* This is now done automatically by the ToolKit {$S SgTxtHot} PROCEDURE TTextSelection.KeyClear; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.window.PerformCommand(TClearTextCmd.CREATE(NIL, SELF.Heap, uClear, SELF.textImage, SELF.textImage.text)); {$IFC fTrace}EP;{$ENDC} END; *) {$S SgTxtHot} PROCEDURE TTextSelection.KeyBack(fWord: BOOLEAN); BEGIN {$IFC fTrace}BP(10);{$ENDC} {This will create the typing command, which deletes any selected text} SELF.KeyText; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TTextSelection.KeyChar(ch: CHAR); BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.KeyText; SELF.KeyChar(ch); {!!! Assumes SELF was converted to insertion point} {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtWrm} PROCEDURE TTextSelection.KeyReturn; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.KeyText; SELF.KeyReturn; {!!! Assumes SELF was converted to insertion point} {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TTextSelection.KeyText; BEGIN {$IFC fTrace}BP(7);{$ENDC} IF NOT SELF.amTyping THEN SELF.window.PerformCommand(TTypingCmd.CREATE(NIL, SELF.Heap, SELF.textImage, SELF.textImage.text)); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TTextSelection.MarkChanged; BEGIN {$IFC fTrace}BP(10);{$ENDC} SUPERSELF.MarkChanged; SELF.textImage.text.MarkChanged(SELF.textRange); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TTextSelection.MousePress(mouseLPt: LPoint); BEGIN {$IFC fTrace}BP(10);{$ENDC} IF clickState.fShift THEN SELF.MouseMove(mouseLPt) ELSE SELF.textImage.MousePress(mouseLPt); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TTextSelection.MouseRelease; BEGIN {$IFC fTrace}BP(10);{$ENDC} ObscureCursor; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} FUNCTION TTextSelection.NewCommand(cmdNumber: TCmdNumber): TCommand; VAR heap: THeap; textImage: TTextImage; BEGIN {$IFC fTrace}BP(10);{$ENDC} NewCommand := NIL; heap := SELF.heap; textImage := SELF.textImage; CASE cmdNumber OF u20Pitch, u15Pitch, u12Pitch, u10Pitch, u12Point, u14Point, u18Point, u24Point, uModern, uClassic, uPlain, uBold, uItalic, uUnderline, uShadow, uOutline: NewCommand := SELF.NewStyleCmd(heap, cmdNumber, textImage); {$IFC LibraryVersion <= 20} uFnt0, uFnt1, uFnt2, uFnt3, uFnt4, uFnt5, uFnt6, uFnt7, uFnt8, uFnt9, uFnt10, uFnt11: NewCommand := SELF.NewStyleCmd(heap, cmdNumber, textImage); {$ENDC} uCut, uCopy: NewCommand := SELF.NewCutCopyCmd(heap, cmdNumber, textImage); uClear: NewCommand := TClearTextCmd.CREATE(NIL, SELF.Heap, uClear, textImage, textImage.text); uPaste: NewCommand := TTextPaste.CREATE(NIL, heap, textImage, textImage.text); {cFormatChanges:} OTHERWISE NewCommand := SUPERSELF.NewCommand(cmdNumber); END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} FUNCTION TTextSelection.NewCutCopyCmd(heap: THeap; cmdNumber: TCmdNumber; textImage: TTextImage): TCommand; BEGIN {$IFC fTrace}BP(10);{$ENDC} NewCutCopyCmd := TTextCutCopy.CREATE(NIL, heap, cmdNumber, textImage, cmdNumber=uCut, textImage.text); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} FUNCTION TTextSelection.NewStyleCmd(heap: THeap; cmdNumber: TCmdNumber; textImage: TTextImage): TCommand; BEGIN {$IFC fTrace}BP(10);{$ENDC} WITH SELF.textRange DO {$H-} NewStyleCmd := TStyleCmd.CREATE(NIL, heap, cmdNumber, textImage, firstIndex, lastIndex, firstLP, lastLP, SELF); {$H+} {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} FUNCTION TTextSelection.ReplicateForOtherPanel(itsTextImage: TTextImage): TTextSelection; VAR sel: TTextSelection; BEGIN {$IFC fTrace}BP(9);{$ENDC} WITH SELF.textRange DO {$H-} sel := itsTextImage.NewTextSelection(firstPara, firstIndex, firstLP, lastPara, lastIndex, lastLP); {$H+} sel.isParaSelection := SELF.isParaSelection; sel.isWordSelection := SELF.isWordSelection; ReplicateForOtherPanel := sel; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TTextSelection.StyleFromContext; BEGIN {$IFC fTrace}BP(9);{$ENDC} {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtIni} END; {METHODS OF TTextSelection} METHODS OF TInsertionPoint; {$S SgTxtHot} FUNCTION TInsertionPoint.CREATE(object: TObject; heap: THeap; itsView: TView; itsTextImage: TTextImage; itsAnchorLPt: LPoint; itsParagraph: TEditPara; itsIndex: LONGINT; itsLP: INTEGER): TInsertionPoint; VAR s: TListScanner; paragraph: TEditPara; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF object = NIL THEN object := NewObject(heap, THISCLASS); IF itsIndex <= 0 THEN BEGIN s := itsTextImage.text.paragraphs.Scanner; WHILE s.Scan(paragraph) DO IF paragraph = itsParagraph THEN BEGIN itsIndex := s.position; s.Done; END; END; SELF := TInsertionPoint(TTextSelection.CREATE(object, heap, itsView, itsTextImage, itsAnchorLPt, itsParagraph, itsIndex, itsLP, itsParagraph, itsIndex, itsLP)); itsParagraph.bsCount := 0; WITH SELF DO BEGIN typingCmd := NIL; styleCmdNumber := 0; newestLP := itsLP; nextHighTransit := hOnToOff; justReturned := FALSE; END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TInsertionPoint.Free; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF SELF.typingCmd <> NIL THEN WITH SELF, typingCmd.typingRange DO BEGIN lastPara := textrange.firstPara; lastIndex := textrange.firstIndex; lastLP := textrange.firstLP; END; (* SELF.textRange.firstPara.StopEdit; *) SUPERSELF.Free; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtWrm} FUNCTION TInsertionPoint.Clone(heap: THeap): TObject; VAR insPt: TInsertionPoint; BEGIN {$IFC fTrace}BP(10);{$ENDC} insPt := TInsertionPoint(SUPERSELF.Clone(heap)); insPt.typingCmd := NIL; insPt.amTyping := FALSE; Clone := insPt; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} {$IFC fTextTrace} PROCEDURE TInsertionPoint.Fields(PROCEDURE Field(nameAndType: S255)); BEGIN TTextSelection.Fields(Field); Field('typingCmd: TTypingCmd'); Field('styleCmdNumber: INTEGER'); Field('newestLP: INTEGER'); Field('justReturned: BOOLEAN'); Field('nextHighTransit: Byte'); Field('nextTransitTime: LONGINT'); Field(''); END; {$ENDC} {$S SgTxtHot} FUNCTION TInsertionPoint.BecomeInsertionPoint: TInsertionPoint; BEGIN {$IFC fTrace}BP(11);{$ENDC} BecomeInsertionPoint := SELF; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtWrm} FUNCTION TInsertionPoint.CanDoCommand(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN; BEGIN {$IFC fTrace}BP(10);{$ENDC} CASE cmdNumber OF uCut, uCopy: CanDoCommand := FALSE; OTHERWISE CanDoCommand := SUPERSELF.CanDoCommand(cmdNumber, checkIt); END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TInsertionPoint.CutCopy(clipSelection: TSelection; deleteOriginal: BOOLEAN); BEGIN {$IFC fTrace}BP(11);{$ENDC} (* Staged Alert *) {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TInsertionPoint.FinishPaste(clipSelection: TSelection; pic: PicHandle); VAR clipTextSelection: TMultiParaSelection; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF InClass(clipSelection, TMultiParaSelection) THEN BEGIN clipTextSelection := TMultiParaSelection(clipSelection); SELF.InsertText(clipTextSelection.textImage.text, clipTextSelection.isParaSelection, clipTextSelection.isWordSelection, FALSE); END {$IFC fUseUnivText} ELSE IF clipBoard.hasUniversalText THEN SELF.InsertText(NIL, FALSE, FALSE, TRUE) {$ENDC}; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TInsertionPoint.IdleBegin(centiSeconds: LONGINT); {Assumes highlighting is already on} BEGIN {$IFC fTrace}BP(6);{$ENDC} IF (SELF.kind = nothingKind) OR SELF.isParaSelection THEN SELF.nextHighTransit := hNone ELSE BEGIN SELF.textImage.text.HiliteRange(hOnToOff, SELF.textRange, FALSE); SELF.nextHighTransit := hOffTOOn; SELF.nextTransitTime := centiSeconds+blinkOffTime; END; SUPERSELF.IdleBegin(centiSeconds); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TInsertionPoint.IdleContinue(centiSeconds: LONGINT); BEGIN {$IFC fTrace}BP(6);{$ENDC} IF (SELF.nextHighTransit<>hNone) AND (centiSeconds > SELF.nextTransitTime) THEN BEGIN SELF.textImage.text.HiliteRange(SELF.nextHighTransit, SELF.textRange, FALSE); WITH SELF DO IF nextHighTransit = hOnToOff THEN BEGIN nextHighTransit := hOffToOn; nextTransitTime := centiSeconds+blinkOffCentiSecs; END ELSE BEGIN nextHighTransit := hOnToOff; nextTransitTime := centiSeconds+blinkOnCentiSecs; END; END; SUPERSELF.IdleContinue(centiSeconds); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TInsertionPoint.IdleEnd(centiSeconds: LONGINT); { end with highlighting on } BEGIN {$IFC fTrace}BP(6);{$ENDC} IF SELF.nextHighTransit=hOffToOn THEN SELF.textImage.text.HiliteRange(hOffToOn, SELF.textRange, FALSE); SELF.nextHighTransit := hNone; SUPERSELF.IdleEnd(centiSeconds); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TInsertionPoint.InsertText(text: TText; isParaSelection: BOOLEAN; isWordSelection: BOOLEAN; universalText: BOOLEAN); VAR s: TListScanner; prevPara: TEditPara; newPara: TEditPara; aParagraph: TEditPara; newLP: INTEGER; textImage: TTextImage; insertIt: BOOLEAN; done: BOOLEAN; newParaImage: TParaImage; paraIndex: LONGINT; delta: INTEGER; numParas: INTEGER; needSpRight: BOOLEAN; {$IFC fUseUnivText} readUnivText: TTKReadUnivText; univPara: TEditPara; univFormat: TParaFormat; {$ENDC} PROCEDURE StartPaste; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF universalText THEN BEGIN {$IFC fUseUnivText} univFormat := TParaFormat.CREATE(NIL, SELF.Heap, SELF.textImage.text.styleSheet); univPara := textImage.NewEditPara(0, prevPara.format); readUnivText := TTKReadUnivText.CREATE(NIL, SELF.Heap, NIL, 512, [UTCharacters, UTParagraphs]); numParas := 0; {$ENDC} END ELSE BEGIN numParas := text.paragraphs.size; s := text.paragraphs.Scanner; END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE EndPaste; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF universalText THEN BEGIN {$IFC fUseUnivText} univPara.Free; readUnivText.Free; {$ENDC} END; {$IFC fTrace}EP;{$ENDC} END; FUNCTION GetParagraph(VAR paragraph: TEditPara): BOOLEAN; VAR currPos: INTEGER; done: BOOLEAN; runSize: INTEGER; wasSomeText: BOOLEAN; ch: CHAR; typeStyle: TTypeStyle; BEGIN {$IFC fTrace}BP(10);{$ENDC} If universalText THEN BEGIN {$IFC fUseUnivText} univPara.ReplPString(0, univPara.Size, NIL); currPos := 0; wasSomeText := FALSE; done := FALSE; REPEAT readUnivText.ReadRun; runSize := readUnivText.data.size; IF runSize > 0 THEN BEGIN IF NOT wasSomeText THEN BEGIN WITH univFormat, readUnivText.paragraphDescriptor DO BEGIN firstIndent := firstLineMargin; leftIndent := bodyMargin; (* Can't use this because it's given as distance from left rather than indent from right and I don't know what value of right edge of paper is. rightIndent := rightMargin; *) spaceBelowPara := paraLeading; END; univPara.format := univFormat; END; wasSomeText := TRUE; ch := readUnivText.data.At(runSize); IF ORD(ch) = ascReturn THEN BEGIN readUnivText.data.DelAt(runSize); runSize := runSize - 1; numParas := numParas + 1; done := TRUE; END; univPara.ReplTString(currPos, 0, readUnivText.data, 0, runSize); typeStyle.onFaces := readUnivText.characterDescriptor.face; typeStyle.font.fontFamily := uvFont[readUnivText.characterDescriptor.font].fontFamily; typeStyle.font.fontSize := uvFont[readUnivText.characterDescriptor.font].fontSize; univPara.NewStyle(currPos, currPos+runSize, typeStyle); currPos := currPos + runSize; END ELSE BEGIN IF wasSomeText THEN numParas := numParas + 1; done := TRUE; END; UNTIL done; IF wasSomeText THEN paragraph := univPara ELSE paragraph := NIL; GetParagraph := wasSomeText; {$ELSEC} paragraph := NIL; GetParagraph := FALSE; {$ENDC} END ELSE GetParagraph := s.Scan(paragraph); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE InsText; BEGIN {$IFC fTrace}BP(10);{$ENDC} delta := 0; textImage := SELF.textImage; newLP := SELF.textRange.firstLP; newPara := SELF.textRange.firstPara; prevPara := newPara; insertIt := FALSE; IF isWordSelection THEN BEGIN needSpRight := newPara.Qualifies(newLP); IF newPara.Qualifies(newLP-1) THEN BEGIN newPara.InsertOneChar(' ', newLP); newLP := newLP + 1; delta := 1; END; END; (* {special case: if first paragraph in text is designated a whole paragraph (by isParaSelection) AND if the insertion point (SELF) is at the end of the paragraph then we want to make a new paragraph rather than append it to the current paragraph and consequently set the flag that was supposed to prevent the first paragraph from being inserted} IF isParaSelection AND (prevPara.size = newLP) THEN BEGIN newPara := textImage.NewEditPara(0, prevPara.format); newLP := 0; insertIt := TRUE; END; *) done := FALSE; StartPaste; IF GetParagraph(aParagraph) THEN BEGIN delta := delta + aParagraph.size; REPEAT newPara.ReplPara(newLP, 0, aParagraph, 0, aParagraph.size); newLP := newLP + aParagraph.size; IF insertIt THEN textImage.text.InsParaAfter(prevPara, newPara); insertIt := TRUE; prevPara := newPara; IF GetParagraph(aParagraph) THEN BEGIN newPara := textImage.NewEditPara(prevPara.size-newLP, TParaFormat(aParagraph.format.Clone(SELF.Heap))); {For now, so we don't get garbage (if aParagraph later deleted), put cloned format on to styleSheet list} SELF.textImage.text.styleSheet.formats.InsLast(newPara.format); newPara.StartEdit(newPara.GrowSize); newPara.ReplPara(0, 0, prevPara, newLp, prevPara.size - newLp); prevPara.ReplPString(newLp, prevPara.size-newLP, NIL); prevPara.StopEdit; newLP := 0; END ELSE done := TRUE; UNTIL done; END; IF isParaSelection THEN BEGIN newPara := textImage.NewEditPara(prevPara.size - newLP, prevPara.format); newPara.StartEdit(newPara.GrowSize); newPara.ReplPara(0, 0, prevPara, newLp, prevPara.size - newLp); prevPara.ReplPString(newLp, prevPara.size - newLP, NIL); prevPara.StopEdit; textImage.text.InsParaAfter(prevPara, newPara); newPara := TEditPara(textImage.text.paragraphs.At(SELF.textRange.firstIndex + numParas)); numParas := numParas+1; newLP := 0; END ELSE IF isWordSelection THEN IF needSpRight THEN BEGIN newPara.InsertOneChar(' ', newLP); newLP := newLP + 1; delta := delta + 1; END; EndPaste; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE Adjust; PROCEDURE AddDelta(paraImage: TParaImage); BEGIN paraImage.AdjustLineLPs(SELF.textRange.firstLP, delta); END; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.textRange.firstPara.EachImage(AddDelta); WITH SELF, textRange DO BEGIN firstPara := newPara; lastPara := newPara; firstLP := newLP; lastLP := newLP; firstIndex := firstIndex + numParas - 1; lastIndex := firstIndex; newestLP := newLP; amTyping := FALSE; END; {$IFC fTrace}EP;{$ENDC} END; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF (text <> NIL) OR universalText THEN SELF.ChangeText(InsText, Adjust); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TInsertionPoint.KeyBack(fWord: BOOLEAN); VAR paragraph: TEditPara; savedPara: TEditPara; lp: INTEGER; typingCmd: TTypingCmd; prevPara: TEditPara; textRange: TTextRange; PROCEDURE Adjust; VAR c: CHAR; PROCEDURE DelOne(paraImage: TParaImage); BEGIN paraImage.AdjustLineLPs(lp, -1); END; BEGIN {$IFC fTrace}BP(10);{$ENDC} paragraph := SELF.textRange.firstPara; lp := SELF.newestLP; IF fWord THEN {&&& Move textRange.firstLP back to start of word}; paragraph.BeginInsertion(lp, 0); IF (paragraph.holeStart < 1) AND (SELF.textRange.firstIndex = 1) THEN SELF.CantDoIt ELSE BEGIN prevPara := NIL; IF paragraph.holeStart < 1 THEN BEGIN {Backspacing over beginning of paragraph} textRange := SELF.textRange; textRange.firstIndex := textRange.firstIndex - 1; prevPara := TEditPara(SELF.textImage.text.paragraphs.At(textRange.firstIndex)); WITH textRange DO BEGIN firstPara := prevPara; firstLP := prevPara.size; lastIndex := firstIndex; lastPara := firstPara; lastLP := firstLP; SELF.newestLP := firstLP; END; prevPara.ReplPara(prevPara.size, 0, paragraph, 0, paragraph.size); SELF.textImage.text.DelPara(paragraph, FALSE); SELF.textImage.text.paragraphs.DelObject(paragraph, FALSE); END ELSE BEGIN paragraph.bsCount := paragraph.bsCount + 1; c := paragraph.At(paragraph.holeStart); paragraph.DelAt(paragraph.holeStart); paragraph.UpdateRuns(lp-1, 1, 0); SELF.newestLP := lp-1; END; typingCmd := SELF.typingCmd; IF prevPara = NIL THEN BEGIN typingCmd.newCharCount := typingCmd.newCharCount - 1; IF typingCmd.newCharCount < 0 THEN BEGIN typingCmd.typingRange.firstLP := typingCmd.typingRange.firstLP - 1; typingCmd.newCharCount := 0; savedPara := TEditPara(typingCmd.savedText.paragraphs.First); {$R-} savedPara.InsertOneChar(c, 0); {$IFC fRngText}{$R+}{$ENDC} END; END ELSE BEGIN typingCmd.newParaCount := typingCmd.newParaCount - 1; IF typingCmd.newParaCount < 0 THEN BEGIN typingCmd.typingRange.firstIndex := textRange.firstIndex; typingCmd.typingRange.firstPara := textRange.firstPara; typingCmd.typingRange.firstLP := textRange.firstLP; typingCmd.savedText.paragraphs.InsFirst(paragraph); paragraph.ReplPString(0, paragraph.size, NIL); typingCmd.newCharCount := 0; typingCmd.newParaCount := 0; END ELSE paragraph.Free; END; deferUpdate := TRUE; SELF.justReturned := FALSE; END; {$IFC fTrace}EP;{$ENDC} END; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.KeyText; Adjust; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TInsertionPoint.KeyChar(ch: CHAR); BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.KeyText; SELF.textRange.firstPara.InsertOneChar(ch, SELF.newestLP); IF SELF.styleCmdNumber <> 0 THEN BEGIN SELF.textRange.firstPara.NewStyle(SELF.newestLP, SELF.newestLP+1, SELF.currTypeStyle); SELF.styleCmdNumber := 0; END; WITH SELF.typingCmd DO newCharCount := newCharCount + 1; SELF.newestLP := SELF.newestLP + 1; SELF.justReturned := FALSE; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TInsertionPoint.KeyEnter; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.textImage.text.RecomputeImages; (*SELF.textImage.text.Invalidate;*) deferUpdate := FALSE; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TInsertionPoint.KeyForward(fWord: BOOLEAN); VAR paragraph: TEditPara; savedPara: TEditPara; lp: INTEGER; {NOTE: This first stab at KeyForward does NOT properly restore typestyles !!} PROCEDURE Adjust; PROCEDURE AddOne(paraImage: TParaImage); BEGIN paraImage.AdjustLineLPs(lp, 1); END; BEGIN paragraph := SELF.textRange.firstPara; lp := SELF.newestLP; IF (lp = paragraph.holeStart) AND (paragraph.bsCount > 0) THEN BEGIN IF fWord THEN {&&& Recover word}; WITH paragraph DO BEGIN bsCount := paragraph.bsCount - 1; holeStart := paragraph.holeStart + 1; holeSize := paragraph.holeSize - 1; size := size + 1; END; paragraph.UpdateRuns(lp-1, 0, 1); SELF.newestLP := lp+1; WITH SELF.typingCmd DO newCharCount := newCharCount + 1; deferUpdate := TRUE; END; SELF.justReturned := FALSE; END; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.KeyText; Adjust; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TInsertionPoint.KeyPause; {Called by ToolKit when there are no keystrokes pending} VAR text: TText; diff: INTEGER; lp: INTEGER; textImage: TTextImage; paraImage: TParaImage; startLine: INTEGER; startPixel: LONGINT; PROCEDURE AddDiff(paraImage: TParaImage); BEGIN paraImage.AdjustLineLPs(lp, diff); END; PROCEDURE AdjustOtherInsPts(obj: TObject); VAR insertPt: TInsertionPoint; BEGIN insertPt := TInsertionPoint(obj); paraImage := insertPt.textImage.ImageWith(SELF.textRange.firstPara, lp); IF paraImage <> NIL THEN BEGIN paraImage.LocateLP(lp, startLine, startPixel); insertPt.textImage.firstLinePixel := startPixel; insertPt.textImage.useFirstPixel := TRUE; END ELSE insertPt.textImage.useFirstPixel := FALSE; WITH SELF, insertPt.textRange DO BEGIN firstLP := newestLP; lastLP := newestLP; IF firstIndex <> textRange.firstIndex THEN BEGIN firstIndex := textRange.firstIndex; lastIndex := textRange.lastIndex; firstPara := textRange.firstPara; lastPara := textRange.lastPara; END; END; END; PROCEDURE HiliteOtherInsPts(obj: TObject); VAR insertPt: TInsertionPoint; BEGIN insertPt := TInsertionPoint(obj); IF insertPt.view.OKToDrawIn(insertPt.textImage.extentLRect) THEN insertPt.panel.Highlight(insertPt, hOffToOn); END; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF SELF.amTyping AND NOT SELF.justReturned THEN BEGIN textImage := SELF.textImage; text := textImage.text; diff := SELF.newestLP - SELF.textRange.firstLP; lp := Min(SELF.textRange.firstLP, SELF.newestLP); SELF.MarkChanged; SELF.textRange.firstPara.EachImage(AddDiff); {set up textImage fields for minimum rectangle erase of first update line} paraImage := textImage.ImageWith(SELF.textRange.firstPara, lp); IF paraImage <> NIL THEN BEGIN paraImage.LocateLP(lp, startLine, startPixel); textImage.firstLinePixel := startPixel; textImage.useFirstPixel := TRUE; END ELSE textImage.useFirstPixel := FALSE; SELF.textRange.firstLP := SELF.newestLP; SELF.textRange.lastLP := SELF.newestLP; IF SELF.typingCmd <> NIL THEN IF SELF.typingCmd.otherInsPts <> NIL THEN SELF.typingCmd.otherInsPts.Each(AdjustOtherInsPts); text.RecomputeImages; {If view.OKToDrawIn was TRUE then we won't be going through the update cycle and hence the ToolKit won't tell us to highlight, so we'll have to highlight ourselves} IF SELF.view.OKToDrawIn(SELF.textImage.extentLRect) THEN SELF.panel.Highlight(SELF, hOffToOn); IF SELF.typingCmd <> NIL THEN IF SELF.typingCmd.otherInsPts <> NIL THEN SELF.typingCmd.otherInsPts.Each(HiliteOtherInsPts); END; deferUpdate := FALSE; SELF.justReturned := FALSE; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtWrm} PROCEDURE TInsertionPoint.KeyReturn; VAR para1: TEditPara; newPara: TEditPara; selSize: INTEGER; PROCEDURE InsPara; VAR styleChange: TStyleChange; BEGIN {$IFC fTrace}BP(10);{$ENDC} para1 := SELF.textRange.firstPara; selSize := para1.size - SELF.textRange.firstLP; newPara := SELF.textImage.NewEditPara(selSize, para1.format); newPara.StartEdit(newPara.GrowSize); newPara.ReplPara(0, 0, para1, SELF.textRange.firstLP, selSize); IF TFakeTStyle(newPara.format.dfltTStyle) <> TFakeTStyle(SELF.currTypeStyle) THEN BEGIN styleChange.lp := -1; styleChange.newStyle := SELF.currTypeStyle; newPara.typeStyles.PutAt(1, @styleChange); END; para1.ReplPString(SELF.textRange.firstLP, selSize, NIL); para1.StopEdit; SELF.textImage.text.InsParaAfter(para1, newPara); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE Adjust; PROCEDURE AdjustOtherInsPts(obj: TObject); VAR insertPt: TInsertionPoint; BEGIN insertPt := TInsertionPoint(obj); WITH insertPt, textRange DO BEGIN firstLP := 0; lastLP := 0; firstIndex := SELF.textRange.firstIndex; lastIndex := firstIndex; firstPara := newPara; lastPara := newPara; END; END; BEGIN {$IFC fTrace}BP(10);{$ENDC} WITH SELF.textRange DO BEGIN firstPara := newPara; lastPara := newPara; firstIndex := firstIndex + 1; lastIndex := firstIndex; firstLP := 0; lastLP := 0; END; SELF.newestLP := 0; SELF.justReturned := TRUE; WITH SELF.typingCmd DO newParaCount := newParaCount + 1; IF SELF.typingCmd.otherInsPts <> NIL THEN SELF.typingCmd.otherInsPts.Each(AdjustOtherInsPts); deferUpdate := FALSE; SELF.textImage.useFirstPixel := FALSE; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE HiliteOtherInsPts(obj: TObject); VAR insertPt: TInsertionPoint; BEGIN insertPt := TInsertionPoint(obj); IF insertPt.view.OKToDrawIn(insertPt.textImage.extentLRect) THEN insertPt.panel.Highlight(insertPt, hOffToOn); END; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.KeyText; SELF.ChangeText(InsPara, Adjust); {If view.OKToDrawIn was TRUE then we won't be going through the update cycle and hence the ToolKit won't tell us to highlight, so we'll have to highlight ourselves} IF SELF.view.OKToDrawIn(SELF.textImage.extentLRect) THEN SELF.panel.Highlight(SELF, hOffToOn); IF SELF.typingCmd.otherInsPts <> NIL THEN SELF.typingCmd.otherInsPts.Each(HiliteOtherInsPts); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TInsertionPoint.KeyTab; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.KeyChar(' '); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TInsertionPoint.MarkChanged; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF SELF.newestLP < SELF.textRange.firstLP THEN BEGIN SELF.textRange.firstLP := SELF.newestLP; SELF.textRange.lastLP := SELF.newestLP; SUPERSELF.MarkChanged; END ELSE BEGIN SUPERSELF.MarkChanged; SELF.textRange.firstLP := SELF.newestLP; SELF.textRange.lastLP := SELF.newestLP; END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TInsertionPoint.MouseMove(mouseLPt: LPoint); VAR currPImage: TParaImage; currLP: INTEGER; multiParaSelection: TMultiParaSelection; oneParaSelection: TOneParaSelection; textImage: TTextImage; firstTxtImg: TTextImage; paraIndex: LONGINT; wasParaSel: BOOLEAN; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.currLPt := mouseLPt; IF NOT EqualLPt(mouseLPt, SELF.anchorLPt) THEN BEGIN textImage := SELF.textImage.FindTextImage(mouseLPt, firstTxtImg); textImage.FindParaAndLp(mouseLPt, currPImage, paraIndex, currLP); IF (currPImage.paragraph <> SELF.textRange.firstPara) THEN BEGIN {Turn insertion point off if necessary} wasParaSel := SELF.isParaSelection; IF NOT wasParaSel AND (paraIndex > SELF.textRange.firstIndex) THEN SELF.textImage.text.HiliteRange(hOnToOff, SELF.textRange, FALSE); {call new with same paragraph, followed by MouseMove so highlighting will work correctly and so MouseMove can figure out if currPImage is before of after SELF.textRange.firstPara} WITH SELF, textRange DO {$H-} {ought to be safe: no VAR params, etc} multiParaSelection := TMultiParaSelection(SELF.FreedAndReplacedBy( TMultiParaSelection.CREATE(NIL, SELF.Heap, view, firstTxtImg, anchorLPt, firstPara, firstIndex, firstLP, firstPara, firstIndex, firstLP, TRUE))); {$H+} multiParaSelection.isParaSelection := wasParaSel; multiParaSelection.MouseMove(mouseLPt); END ELSE IF (currLP <> SELF.textRange.firstLP) THEN BEGIN {Turn insertion point off first} SELF.textImage.text.HiliteRange(hOnToOff, SELF.textRange, FALSE); {call CREATE with same LP for begin and end, followed by MouseMove so highlighting will work correctly} WITH SELF, textRange DO {$H-} {ought to be safe: no VAR params, etc} oneParaSelection := TOneParaSelection(SELF.FreedAndReplacedBy( TOneParaSelection.CREATE(NIL, SELF.Heap, view, firstTxtImg, anchorLPt, firstPara, firstIndex, firstLP, firstLP))); {$H+} oneParaSelection.MouseMove(mouseLPt); END; END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtWrm} PROCEDURE TInsertionPoint.MousePress(mouseLPt: LPoint); VAR first, last: INTEGER; oneParaSelection: TOneParaSelection; funnnyInsPoint: TInsertionPoint; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF clickState.fShift THEN SELF.MouseMove(mouseLPt) ELSE IF clickState.clickCount = 2 THEN {double click} BEGIN {This check should solve the problem of double clicking on the last half of the last character of a word and not getting the word selected} WITH SELF.textRange DO BEGIN first := firstLP; {$H-} IF NOT firstPara.Qualifies(first) THEN IF first > 0 THEN first := first - 1; {$H+} END; SELF.textRange.firstPara.FindWordBounds(first, first, last); IF first <> last THEN BEGIN {Turn insertion point off first} SELF.textImage.text.HiliteRange(hOnToOff, SELF.textRange, FALSE); WITH SELF, textRange DO {$H-} oneParaSelection := TOneParaSelection(SELF.FreedAndReplacedBy( TOneParaSelection.CREATE(NIL, SELF.Heap, view, textImage, anchorLPt, firstPara, firstIndex, first, last))); {$H+} WITH oneParaSelection DO BEGIN anchorbegin := first; anchorEnd := last; isWordSelection := TRUE; END; oneParaSelection.textImage.text.HiliteRange(hOffToOn, oneParaSelection.textRange, FALSE); END; END ELSE IF clickState.clickCount = 3 THEN {triple click, happens if double click didn't select word} BEGIN {Turn insertion point off first} SELF.textImage.text.HiliteRange(hOnToOff, SELF.textRange, SELF.isParaSelection); IF SELF.textRange.firstPara.size = 0 THEN {This case precipitates the odd notion of an "insertion point" the width of the textImage; (ie. when one triple clicks on an empty paragraph) A special check in IdleBegin makes sure it doesn't blink.} BEGIN WITH SELF, textRange DO {$H-} funnnyInsPoint := TInsertionPoint(SELF.FreedAndReplacedBy( TInsertionPoint.CREATE(NIL, SELF.Heap, view, textImage, anchorLPt, firstPara, firstIndex, 0))); {$H+} WITH funnnyInsPoint DO BEGIN isParaSelection := TRUE; isWordSelection := FALSE; END; funnnyInsPoint.textImage.text.HiliteRange(hOffToOn, SELF.textRange, TRUE); END ELSE BEGIN WITH SELF, textRange DO {$H-} oneParaSelection := TOneParaSelection(SELF.FreedAndReplacedBy( TOneParaSelection.CREATE(NIL, SELF.Heap, view, textImage, anchorLPt, firstPara, firstIndex, 0, firstPara.size))); {$H+} WITH oneParaSelection DO BEGIN isParaSelection := TRUE; isWordSelection := FALSE; anchorBegin := 0; anchorEnd := textRange.lastLP; END; oneParaSelection.textImage.text.HiliteRange(hOffToOn, oneParaSelection.textRange, TRUE); END; END ELSE SELF.textImage.MousePress(mouseLPt); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} FUNCTION TInsertionPoint.NewStyleCmd(heap: THeap; cmdNumber: TCmdNumber; textImage: TTextImage): TCommand; BEGIN {$IFC fTrace}BP(10);{$ENDC} {Do stuff but set NewStyleCmd NIL so last cmd not committed}; SELF.styleCmdNumber := cmdNumber; WITH SELF.currTypeStyle, font DO CASE cmdNumber OF uPlain: onFaces := []; uBold: onFaces := onFaces + [bold]; uItalic: onFaces := onFaces + [italic]; uUnderline: onFaces := onFaces + [underlined]; uShadow: onFaces := onFaces + [shadow]; uOutline: onFaces := onFaces + [outline]; uModern, uClassic: font.fontFamily := cmdNumber - uModern + 1; {$IFC LibraryVersion <= 20} uFnt0, uFnt1, uFnt2, uFnt3, uFnt4, uFnt5, uFnt6, uFnt7, uFnt8, uFnt9, uFnt10, uFnt11: CASE cmdNumber OF uFnt0: fontFamily := famSystem; uFnt1: BEGIN fontFamily := famModern; fontSize := size15Pitch; END; uFnt2: BEGIN fontFamily := famModern; fontSize := size12Pitch; END; uFnt3: BEGIN fontFamily := famClassic; fontSize := size12Pitch; END; uFnt4: BEGIN fontFamily := famModern; fontSize := size10Pitch; END; uFnt5: BEGIN fontFamily := famModern; fontSize := size14Point; END; uFnt6: BEGIN fontFamily := famModern; fontSize := size12Point; END; uFnt7: BEGIN fontFamily := famClassic; fontSize := size12Point; END; uFnt8: BEGIN fontFamily := famModern; fontSize := size18Point; END; uFnt9: BEGIN fontFamily := famClassic; fontSize := size18Point; END; uFnt10: BEGIN fontFamily := famModern; fontSize := size24Point; END; uFnt11: BEGIN fontFamily := famClassic; fontSize := size24Point; END; END; {$ENDC} OTHERWISE font.fontSize := cmdNumber - u20Pitch + 1; END; NewStyleCmd := NIL; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} FUNCTION TInsertionPoint.NewCutCopyCmd(heap: THeap; cmdNumber: TCmdNumber; textImage: TTextImage): TCommand; BEGIN {$IFC fTrace}BP(10);{$ENDC} {don't create a new command object for insertion point style change} NewCutCopyCmd := NIL; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} FUNCTION TInsertionPoint.SelSize: INTEGER; BEGIN {$IFC fTrace}BP(9);{$ENDC} SelSize := 0; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TInsertionPoint.StyleFromContext; VAR typeStyle: TTypeSTyle; BEGIN {$IFC fTrace}BP(9);{$ENDC} SELF.textRange.firstPara.StyleAt(Max(SELF.textRange.firstLP - 1, 0), typeStyle); SELF.currTypeStyle := typeStyle; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtIni} BEGIN {temp patch to get fonts from universal text} uvFont[4].fontFamily := famModern; uvFont[5].fontFamily := famModern; uvFont[6].fontFamily := famModern; uvFont[7].fontFamily := famModern; uvFont[8].fontFamily := famModern; uvFont[9].fontFamily := famModern; uvFont[10].fontFamily := famClassic; uvFont[11].fontFamily := famClassic; uvFont[12].fontFamily := famClassic; uvFont[13].fontFamily := famClassic; uvFont[14].fontFamily := famClassic; uvFont[4].fontSize := 5; uvFont[5].fontSize := 7; uvFont[6].fontSize := 8; uvFont[7].fontSize := 2; uvFont[8].fontSize := 3; uvFont[9].fontSize := 4; uvFont[10].fontSize := 5; uvFont[11].fontSize := 7; uvFont[12].fontSize := 8; uvFont[13].fontSize := 3; uvFont[14].fontSize := 6; END; {Methods of TInsertionPoint} METHODS OF TOneParaSelection; {$S SgTxtHot} FUNCTION TOneParaSelection.CREATE(object: TObject; heap: THeap; itsView: TView; itsTextImage: TTextImage; itsAnchorLPt: LPoint; itsParagraph: TEditPara; itsIndex: LONGINT; oldLP: INTEGER; currLP: INTEGER): TOneParaSelection; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF object = NIL THEN object := NewObject(heap, THISCLASS); SELF := TOneParaSelection(TTextSelection.CREATE(object, heap, itsView, itsTextImage, itsAnchorLPt, itsParagraph, itsIndex, Min(oldLP, currLP), itsParagraph, itsIndex, Max(oldLP, currLP))); WITH SELF DO BEGIN anchorBegin := oldLP; anchorEnd := oldLP; viewTick := -1; { force recalculation of extent } END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} {$IFC fTextTrace} PROCEDURE TOneParaSelection.Fields(PROCEDURE Field(nameAndType: S255)); BEGIN TTextSelection.Fields(Field); Field('anchorBegin: INTEGER'); Field('anchorEnd: INTEGER'); Field(''); END; {$ENDC} {$S SgTxtCld} PROCEDURE TOneParaSelection.ChangeStyle(cmdNumber: TCmdNumber); VAR newTypeStyle: TTypeStyle; BEGIN {$IFC fTrace}BP(10);{$ENDC} WITH SELF.textRange DO {$H-} SELF.DoChangeStyle(cmdNumber, firstPara, firstLP, lastLP, newTypeStyle); {$H+} SELF.currTypeStyle := newTypeStyle; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} {CopySelf is used for copying to the clipboard} FUNCTION TOneParaSelection.CopySelf(heap: THeap; view: TView): TMultiParaSelection; VAR paragraph: TEditPara; selSize: INTEGER; newImage: TParaImage; lastLine: TLineInfo; textImage: TTextImage; text: TText; imageLRect: LRect; BEGIN {$IFC fTrace}BP(11);{$ENDC} text := TText.CREATE(NIL, heap, TStyleSheet.CREATE(NIL, heap)); imageLRect := view.extentLRect; InsetLRect(imageLRect, cHorizMargin, cVertMargin); textImage := SELF.textImage.TxtImgForClipBoard(heap, view, imageLRect, text, TRUE); textImage.minHeight := 0; text.txtImgList.InsLast(textImage); selSize := SELF.textRange.lastLP-SELF.textRange.firstLP; paragraph := textImage.NewEditPara(selSize, TParaFormat(SELF.textRange.firstPara.format.Clone(heap))); paragraph.ReplPara(0, 0, SELF.textRange.firstPara, SELF.textRange.firstLP, selSize); newImage := textImage.NewParaImage(paragraph, textImage.extentLRect, 0, 0); textImage.imageList.InsLast(newImage); textImage.text.paragraphs.InsLast(paragraph); { make view extentLRect exactly fit the lines } textImage.RecomputeImages(actionNone, TRUE); WITH textImage.extentLRect DO view.extentLRect.bottom := bottom - top + 2 * cVertMargin; CopySelf := TMultiParaSelection.CREATE(NIL, heap, view, textImage, zeroLPt, paragraph, 1, 0, paragraph, 1, selSize, TRUE); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtWrm} PROCEDURE TOneParaSelection.DeleteAndFree; VAR delta: INTEGER; PROCEDURE DelText; BEGIN IF SELF.isParaSelection AND (SELF.textRange.firstIndex <> SELF.textImage.text.paragraphs.size) THEN BEGIN SELF.textImage.text.DelPara(SELF.textRange.firstPara, FALSE); SELF.textImage.text.paragraphs.DelObject(SELF.textRange.firstPara, TRUE); END ELSE SELF.textRange.firstPara.ReplPString(SELF.textRange.firstLP, SELF.textRange.lastLP-SELF.textRange.firstLP, NIL); END; PROCEDURE Adjust; PROCEDURE Subtract(paraImage: TParaImage); BEGIN paraImage.AdjustLineLPs(SELF.textRange.firstLP, delta); END; BEGIN IF NOT SELF.isParaSelection THEN BEGIN delta := SELF.textRange.firstLP - SELF.textRange.lastLP; SELF.textRange.firstPara.EachImage(Subtract); END; WITH SELF.textRange DO BEGIN IF SELF.isParaSelection THEN BEGIN {$H-} firstPara := TEditPara(SELF.textImage.text.paragraphs.At(firstIndex)); {$H+} firstLP := 0; lastPara := firstPara; END; lastLP := firstLP; END; END; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.ChangeText(DelText, Adjust); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} FUNCTION TOneParaSelection.DeleteButSave: TText; VAR oldPara: TEditPara; selSize: INTEGER; newPara: TEditPara; text: TText; PROCEDURE DelText; BEGIN oldPara := SELF.textRange.firstPara; IF SELF.isParaSelection AND (SELF.textRange.firstIndex <> SELF.textImage.text.paragraphs.size) THEN BEGIN SELF.textImage.text.DelPara(oldPara, FALSE); SELF.textImage.text.paragraphs.DelObject(oldPara, FALSE); newPara := oldPara; END ELSE BEGIN selSize := SELF.textRange.lastLP-SELF.textRange.firstLP; newPara := SELF.textImage.NewEditPara(selSize, oldPara.format); newPara.ReplPara(0, 0, oldPara, SELF.textRange.firstLP, selSize); oldPara.ReplPString(SELF.textRange.firstLP, selSize, NIL); END; text := TText.CREATE(NIL, SELF.Heap, NIL); text.paragraphs.InsLast(newpara); END; PROCEDURE Adjust; PROCEDURE Subtract(paraImage: TParaImage); BEGIN paraImage.AdjustLineLPs(SELF.textRange.firstLP, -selSize); END; BEGIN WITH SELF.textRange DO BEGIN IF SELF.isParaSelection THEN BEGIN {$H-} firstPara := TEditPara(SELF.textImage.text.paragraphs.At(firstIndex)); {$H+} firstLP := 0; lastPara := firstPara; END; lastLP := firstLP; END; IF NOT SELF.isParaSelection THEN SELF.textRange.firstPara.EachImage(Subtract); END; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.ChangeText(DelText, Adjust); DeleteButSave := text; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TOneParaSelection.MouseMove(mouseLPt: LPoint); { assumes highlighting is ON } VAR currPImage: TParaImage; currLP: INTEGER; oldLP: INTEGER; { end (ie. not the anchor) of indication } multiParaSelection: TMultiParaSelection; textImage: TTextImage; firstTxtImg: TTextImage; first, last: INTEGER; paraSelect: BOOLEAN; paraIndex: LONGINT; PROCEDURE HiExtOnPads(highTransit: THighTransit; startLP,endLP: INTEGER); BEGIN SELF.textImage.text.HiliteParagraphs(highTransit, SELF.textRange.firstIndex, startLP, SELF.textRange.firstIndex, endLP, SELF.isParaSelection); END; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.currLPt := mouseLPt; textImage := SELF.textImage.FindTextImage(mouseLPt, firstTxtImg); textImage.FindParaAndLp(mouseLPt, currPImage, paraIndex, currLP); IF currPImage.paragraph <> SELF.textRange.firstPara THEN BEGIN {call new with same paraImage, followed by MouseMove so highlighting will work correctly} paraSelect := SELF.isParaSelection; first := SELF.anchorBegin; last := SELF.anchorEnd; WITH SELF, textRange DO {$H-} multiParaSelection := TMultiParaSelection(SELF.FreedAndReplacedBy( TMultiParaSelection.CREATE(NIL, SELF.Heap, view, firstTxtImg, anchorLPt, firstPara, firstIndex, firstLP, firstPara, firstIndex, lastLP, firstLP = anchorBegin))); {$H+} WITH multiParaSelection DO BEGIN isParaSelection := paraSelect; anchorBegin := first; anchorEnd := last; isWordSelection := NOT paraSelect AND (first <> last); END; multiParaSelection.MouseMove(mouseLPt); END ELSE IF NOT SELF.isParaSelection THEN BEGIN IF SELF.isWordSelection THEN BEGIN {So dragging over last half of last character of word doesn't select space} WITH SELF.textRange DO BEGIN {$H-} IF NOT firstPara.Qualifies(currLP) THEN IF currLP > 0 THEN currLP := currLP - 1; {$H+} END; SELF.textRange.firstPara.FindWordBounds(currLP, first, last); IF first <= SELF.anchorBegin THEN currLP := first ELSE currLP := last; END; IF currLP <= SELF.anchorBegin THEN BEGIN oldLP := SELF.textRange.firstLP; IF SELF.anchorEnd <> SELF.textRange.lastLP THEN HiExtOnPads(hOnToOff, SELF.anchorEnd, SELF.textRange.lastLP); SELF.textRange.firstLP := currLP; SELF.textRange.lastLP := SELF.anchorEnd; END ELSE BEGIN oldLP := SELF.textRange.lastLP; IF SELF.anchorBegin <> SELF.textRange.firstLP THEN HiExtOnPads(hOnToOff, SELF.textRange.firstLP, SELF.anchorBegin); SELF.textRange.firstLP := SELF.anchorBegin; SELF.textRange.lastLP := currLP; END; IF currLP <> oldLP THEN IF currLP < oldLP THEN HiExtOnPads(hOffToOn, currLP, oldLP) ELSE HiExtOnPads(hOffToOn, oldLP, currLP); END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TOneParaSelection.MousePress(mouseLPt: LPoint); VAR first, last: INTEGER; oneParaSelection: TOneParaSelection; multiParaSelection: TMultiParaSelection; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF clickState.fShift THEN SELF.MouseMove(mouseLPt) ELSE IF clickState.clickCount = 2 THEN {double click} BEGIN {should select words at beginning and end of current selection (later)} SELF.textRange.firstPara.FindWordBounds(SELF.anchorBegin, first, last); SELF.textImage.text.HiliteRange(hOnToOff, SELF.textRange, SELF.isParaSelection); WITH SELF, textRange DO {$H-} oneParaSelection := TOneParaSelection(SELF.FreedAndReplacedBy( TOneParaSelection.CREATE(NIL, SELF.Heap, view, textImage, anchorLPt, firstPara, firstIndex, first, last))); {$H+} WITH oneParaSelection DO BEGIN anchorBegin := first; anchorEnd := last; isWordSelection := TRUE; END; oneParaSelection.textImage.text.HiliteRange(hOnToOff, oneParaSelection.textRange, SELF.isParaSelection); END ELSE IF clickState.clickCount = 3 THEN {triple click} BEGIN {Turn current highlighting off first} SELF.textImage.text.HiliteRange(hOnToOff, SELF.textRange, SELF.isParaSelection); WITH SELF, textRange DO {$H-} oneParaSelection := TOneParaSelection(SELF.FreedAndReplacedBy( TOneParaSelection.CREATE(NIL, SELF.Heap, view, textImage, anchorLPt, firstPara, firstIndex, 0, firstPara.size))); {$H+} WITH oneParaSelection DO BEGIN isParaSelection := TRUE; isWordSelection := FALSE; anchorBegin := 0; anchorEnd := textRange.lastLP; END; oneParaSelection.textImage.text.HiliteRange(hOnToOff, oneParaSelection.textRange, TRUE); END ELSE SELF.textImage.MousePress(mouseLPt); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TOneParaSelection.MouseRelease; VAR insPt: TInsertionPoint; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF SELF.textRange.firstLP = SELF.textRange.lastLP THEN BEGIN insPt := SELF.BecomeInsertionPoint; insPt.textImage.text.HiliteRange(hOffToOn, insPt.textRange, SELF.isParaSelection); END ELSE SELF.textImage.text.ChangeSelInOtherPanels(SELF); SUPERSELF.MouseRelease; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} FUNCTION TOneParaSelection.SelSize: INTEGER; BEGIN {$IFC fTrace}BP(9);{$ENDC} SelSize := SELF.textRange.lastLP - SELF.textRange.firstLP; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtHot} PROCEDURE TOneParaSelection.StyleFromContext; VAR typeStyle: TTypeStyle; BEGIN {$IFC fTrace}BP(8);{$ENDC} SELF.textRange.firstPara.StyleAt(SELF.textRange.firstLP, typeStyle); SELF.currTypeStyle := typeStyle; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtIni} END; {Methods of TOneParaSelection} METHODS OF TMultiParaSelection; {$S SgTxtCld} FUNCTION TMultiParaSelection.CREATE(object: TObject; heap: THeap; itsView: TView; itsTextImage: TTextImage; itsAnchorLPt: LPoint; beginPara: TEditPara; beginIndex: LONGINT; beginLP: INTEGER; endPara: TEditPara; endIndex: LONGINT; endLP: INTEGER; beginIsAnchor: BOOLEAN): TMultiParaSelection; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF object = NIL THEN object := NewObject(heap, THISCLASS); SELF := TMultiParaSelection(TTextSelection.CREATE(object, heap, itsView, itsTextImage, itsAnchorLPt, beginPara, beginIndex, beginLP, endPara, endIndex, endLP)); WITH SELF DO BEGIN IF beginIsAnchor THEN BEGIN anchorPara := beginPara; anchorIndex := beginIndex; anchorBegin := beginLP; anchorEnd := beginLP; END ELSE BEGIN anchorPara := endPara; anchorIndex := endIndex; anchorBegin := endLP; anchorEnd := endLP; END; END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} {$IFC fTextTrace} PROCEDURE TMultiParaSelection.Fields(PROCEDURE Field(nameAndType: S255)); BEGIN TTextSelection.Fields(Field); Field('anchorPara: TEditPara'); Field('anchorIndex: LONGINT'); Field('anchorBegin: INTEGER'); Field('anchorEnd: INTEGER'); Field(''); END; {$ENDC} {$S SgTxtCld} PROCEDURE TMultiParaSelection.ChangeStyle(cmdNumber: TCmdNumber); VAR newTypeStyle: TTypeStyle; s: TListScanner; paragraph: TEditPara; lastPara: TEditPara; endRng: INTEGER; paraImage: TParaImage; BEGIN {$IFC fTrace}BP(10);{$ENDC} newTypeStyle := SELF.currTypeStyle; lastPara := SELF.textRange.lastPara; s := SELF.textImage.text.paragraphs.ScannerFrom(SELF.textRange.firstIndex-1, scanForward); WHILE s.Scan(paragraph) DO IF paragraph = SELF.textRange.firstPara THEN BEGIN SELF.DoChangeStyle(cmdNumber, paragraph, SELF.textRange.firstLP, paragraph.size, newTypeStyle); SELF.currTypeStyle := newTypeStyle; IF paragraph = lastPara THEN s.Done; END ELSE BEGIN IF paragraph = lastPara THEN BEGIN endRng := SELF.textRange.lastLP; s.Done; END ELSE endRng := paragraph.size; SELF.DoChangeStyle(cmdNumber, paragraph, 0, endRng, newTypeStyle); END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} {CopySelf is used for copying to the clipboard} FUNCTION TMultiParaSelection.CopySelf(heap: THeap; view: TView): TMultiParaSelection; VAR srcPara: TEditPara; cpyPara: TEditPara; cpyFirstPara: TEditPara; srcLastPara: TEditPara; cpyLastPara: TEditPara; selSize1: INTEGER; selSize2: INTEGER; textImage: TTextImage; s: TListScanner; text: TText; textRange: TTextRange; imageLRect: LRect; BEGIN {$IFC fTrace}BP(11);{$ENDC} text := TText.CREATE(NIL, heap, TStyleSheet.CREATE(NIL, heap)); imageLRect := view.extentLRect; InsetLRect(imageLRect, cHorizMargin, cVertMargin); textImage := SELF.textImage.TxtImgForClipBoard(heap, view, imageLRect, text, TRUE); textImage.minHeight := 0; text.txtImgList.InsLast(textImage); textRange := SELF.textRange; srcPara := textRange.firstPara; selSize1 := srcPara.size-textRange.firstLP; cpyPara := textImage.NewEditPara(selSize1, TParaFormat(srcPara.format.clone(heap))); cpyPara.ReplPara(0, 0, srcPara, textRange.firstLP, selSize1); cpyFirstPara := cpyPara; textImage.text.paragraphs.InsLast(cpyFirstPara); IF textRange.firstPara <> textRange.lastPara THEN BEGIN srcLastPara := textRange.lastPara; selSize2 := textRange.lastLP; cpyLastPara := textImage.NewEditPara(selSize2, TParaFormat(srcLastPara.format.clone(heap))); cpyLastPara.ReplPara(0, 0, srcLastPara, 0, selSize2); {skip first paragraph by not subtracting one from firstIndex} s := SELF.textImage.text.paragraphs.ScannerFrom(textRange.firstIndex, scanForward); WHILE s.Scan(srcPara) DO BEGIN IF srcPara = textRange.lastPara THEN BEGIN cpyPara := cpyLastPara; s.Done; END ELSE BEGIN cpyPara := textImage.NewEditPara(srcPara.size, TParaFormat(srcPara.format.clone(heap))); cpyPara.ReplPara(0, 0, srcPara, 0, srcPara.size); END; textImage.text.paragraphs.InsLast(cpyPara); END; END; textImage.RecomputeImages(actionNone, TRUE); WITH textImage.extentLRect DO view.extentLRect.bottom := bottom - top + 2 * cVertMargin; CopySelf := TMultiParaSelection.CREATE(NIL, heap, view, textImage, zeroLPt, TEditPara(textImage.text.paragraphs.First), 1, 0, TEditPara(textImage.text.paragraphs.Last), textRange.lastIndex - textRange.firstIndex + 1, selSize2, TRUE); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} FUNCTION TMultiParaSelection.Delete(saveIt: BOOLEAN): TText; VAR firstPara: TEditPara; lastPara: TEditPara; paragraph: TEditPara; text: TText; paraList: TList; s: TListScanner; selSize: INTEGER; textRange: TTextRange; numParas: INTEGER; PROCEDURE DelText; BEGIN {$IFC fTrace}BP(11);{$ENDC} {If saveIt is TRUE, we want to save the text we're deleting, so create a text object} IF saveIt THEN BEGIN text := TText.CREATE(NIL, SELF.Heap, NIL); paraList := text.paragraphs; END ELSE text := NIL; textRange := SELF.textRange; firstPara := textRange.firstPara; lastPara := textRange.lastPara; numParas := SELF.textImage.text.paragraphs.size; {If the last paragraph is selected, treat this like a non-para selection, so that one empty para will be left at the end after the delete} IF textRange.lastIndex = numParas THEN SELF.isParaSelection := FALSE; s := SELF.textImage.text.paragraphs.ScannerFrom(textRange.firstIndex-1, scanForward); WHILE s.Scan(paragraph) DO IF paragraph = firstPara THEN BEGIN IF SELF.isParaSelection THEN {If isParaSelection is TRUE then insert it in our save list and delete it from the textImage's list} BEGIN IF saveIt THEN paraList.InsLast(firstPara); SELF.textImage.text.DelPara(firstPara, FALSE); s.Delete(NOT saveIt); END ELSE {If the beginning of the selection is part of a paragraph, then save the characters in a new paragraph and delete them in the old} BEGIN selSize := firstPara.size - textRange.firstLP; IF saveIt THEN BEGIN paragraph := SELF.textImage.NewEditPara(selSize, firstPara.format); paragraph.ReplPara(0, 0, firstPara, textRange.firstLP, selSize); paraList.InsLast(paragraph); END; firstPara.ReplPString(textRange.firstLP, selSize, NIL); END; IF firstPara = lastPara THEN s.Done END ELSE BEGIN s.Delete(FALSE); IF paragraph = lastPara THEN BEGIN s.Done; IF NOT SELF.isParaSelection THEN {If the end of the selection is a part of a paragraph, then save the selected characters in a new paragraph and append the rest to the first paragraph. Finally, delete and free the last paragraph } BEGIN selSize := textRange.lastLP; IF saveIt THEN BEGIN paragraph := SELF.textImage.NewEditPara(selSize, lastPara.format); paragraph.ReplPara(0, 0, lastPara, 0, selSize); END; firstPara.ReplPara(firstPara.size, 0, lastPara, selSize, lastPara.size-selSize); SELF.textImage.text.DelPara(lastPara, TRUE); END ELSE SELF.textImage.text.DelPara(paragraph, NOT saveIt); END ELSE {Delete entire intermediate paragraphs from the textImage} SELF.textImage.text.DelPara(paragraph, NOT saveIt); IF saveIt THEN paraList.InsLast(paragraph); END; {$IFC fTrace}EP;{$ENDC} END; {DelText} PROCEDURE SetRange; BEGIN WITH SELF, textRange DO IF isParaSelection THEN BEGIN {$H-} firstPara := TEditPara(textImage.text.paragraphs.At(firstIndex)); {$H+} firstLP := 0; END; WITH SELF.textRange DO BEGIN lastPara := firstPara; lastIndex := firstIndex; lastLP := firstLP; END; END; BEGIN {$IFC fTrace}BP(11);{$ENDC} SELF.ChangeText(DelText, SetRange); Delete := text; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TMultiParaSelection.DeleteAndFree; VAR text: TText; {dummy var since Delete returns TText; will always be NIL} BEGIN {$IFC fTrace}BP(11);{$ENDC} text := SELF.Delete(FALSE); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} FUNCTION TMultiParaSelection.DeleteButSave: TText; BEGIN {$IFC fTrace}BP(11);{$ENDC} DeleteButSave := SELF.Delete(TRUE); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TMultiParaSelection.MouseMove(mouseLPt: LPoint); { assumes highlighting is ON } VAR endPara: TEditPara; currPara: TEditPara; currPImage: TParaImage; oldPImage: TParaImage; oldPara: TEditPara; paragraph: TEditPara; textrange: TTextRange; textImage: TTextImage; firstTxtImg: TTextImage; s: TListScanner; paraImage: TParaImage; newText: TText; currLP: INTEGER; oldLP: INTEGER; { end (ie. not the anchor) of indication } mouseBeforeAnchor: BOOLEAN; { is mouse LPt before the anchor LPt } oldBeforeCurr: BOOLEAN; { is old end LPt before curr LPt } beginIsAnchor: BOOLEAN; currIndex: LONGINT; oldIndex: LONGINT; startIndex: LONGINT; endIndex: LONGINT; startLP: INTEGER; endLP: INTEGER; first, last: INTEGER; selChanged: BOOLEAN; {$IFC fTextTrace} str1: STR255; str2: STR255; {$ENDC} PROCEDURE NextIndex(oldIndex: LONGINT; oldLP: INTEGER; VAR newIndex: LONGINT; VAR newLP: INTEGER); BEGIN IF oldIndex < SELF.textImage.text.paragraphs.size THEN BEGIN newIndex := oldIndex + 1; newLP := 0; END ELSE BEGIN newIndex := oldIndex; newLP := oldLP; END; END; PROCEDURE PrevIndex(oldIndex: LONGINT; oldLP: INTEGER; VAR newIndex: LONGINT; VAR newLP: INTEGER); BEGIN IF oldIndex > 1 THEN BEGIN newIndex := oldIndex - 1; newLP := TEditPara(SELF.textImage.text.paragraphs.At(newIndex)).size; END ELSE BEGIN newIndex := oldIndex; newLP := oldLP; END; END; PROCEDURE HiExtOnPads(highTransit: THighTransit; startIndex: LONGINT; startLP: INTEGER; endIndex: LONGINT; endLP: INTEGER); BEGIN SELF.textImage.text.HiliteParagraphs(highTransit, startIndex, startLP, endIndex, endLP, SELF.isParaSelection); END; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.currLPt := mouseLPt; {$IFC fTextTrace} IF fTextTrace THEN BEGIN LIntToHex(ORD(SELF.textRange.firstPara), @str1); LIntToHex(ORD(SELF.textRange.lastPara), @str2); Writeln; Writeln('*** MultiPara MouseMove: firstPara, lastPara = (', str1, ',', str2, ')'); Writeln('*** About to call FindParaAndLp'); END; {$ENDC} textRange := SELF.textRange; textImage := SELF.textImage.FindTextImage(mouseLPt, firstTxtImg); SELF.textImage := firstTxtImg; textImage.FindParaAndLp(mouseLPt, currPImage, currIndex, currLP); currPara := currPImage.paragraph; IF SELF.isParaSelection THEN BEGIN IF currIndex < SELF.anchorIndex THEN currLP := 0 ELSE currLP := currPara.size; END ELSE IF SELF.isWordSelection THEN BEGIN currPara.FindWordBounds(currLP, first, last); IF currIndex < SELF.anchorIndex THEN currLP := first ELSE IF currIndex > SELF.anchorIndex THEN currLP := last ELSE IF first <= SELF.anchorBegin THEN currLP := first ELSE currLP := last; END; IF currIndex = SELF.anchorIndex THEN mouseBeforeAnchor := currLP < SELF.anchorBegin ELSE mouseBeforeAnchor := currIndex < SELF.anchorIndex; beginIsAnchor := (textRange.firstIndex = SELF.anchorIndex) AND (textRange.firstLP = SELF.anchorBegin); {After determining if the mouse is before or after the anchor position, set up variables for higlighting below and dehilite any text that was on other side of the anchor previous to this mouse move} IF mouseBeforeAnchor THEN BEGIN oldIndex := textRange.firstIndex; oldLP := textRange.firstLP; IF beginIsAnchor THEN {current Position is on other side of anchor, so must dehighlight} BEGIN IF SELF.isParaSelection THEN IF SELF.anchorIndex = textRange.lastIndex THEN startIndex := -1 ELSE NextIndex(SELF.anchorIndex, SELF.anchorEnd, startIndex, startLP) ELSE BEGIN startIndex := SELF.anchorIndex; startLP := SELF.anchorEnd; END; IF startIndex > 0 THEN HiExtOnPads(hOnToOff, startIndex, startLP, textRange.lastIndex, textRange.lastLP); END; WITH SELF, textRange DO BEGIN firstPara := currPara; firstIndex := currIndex; lastPara := anchorPara; lastIndex := anchorIndex; firstLP := currLP; lastLP := anchorEnd; END; END ELSE BEGIN oldIndex := textRange.lastIndex; oldLp := textRange.lastLP; IF NOT beginIsAnchor THEN BEGIN {current Position is on other side of anchor, so must dehighlight} IF SELF.isParaSelection THEN PrevIndex(SELF.anchorIndex, SELF.anchorBegin, startIndex, startLP) ELSE BEGIN startIndex := SELF.anchorIndex; startLP := SELF.anchorBegin; END; HiExtOnPads(hOnToOff, textRange.firstIndex, textRange.firstLP, startIndex, startLP); END; WITH SELF, textRange DO BEGIN lastPara := currPara; lastIndex := currIndex; firstPara := anchorPara; firstIndex := anchorIndex; firstLP := anchorBegin; lastLP := currLP; END; END; IF mouseBeforeAnchor = beginIsAnchor THEN oldBeforeCurr := NOT mouseBeforeAnchor ELSE IF currIndex = oldIndex THEN oldBeforeCurr := oldLP < currLP ELSE oldBeforeCurr := oldIndex < currIndex; IF oldBeforeCurr THEN BEGIN startIndex := oldIndex; startLP := oldLP; endIndex := currIndex; endLP := currLP; END ELSE BEGIN startIndex := currIndex; startLP := currLP; endIndex := oldIndex; endLP := oldLP; END; selChanged := TRUE; IF SELF.isParaSelection THEN IF startIndex = endIndex THEN selChanged := FALSE ELSE IF mouseBeforeAnchor THEN PrevIndex(endIndex, endLP, endIndex, endLP) ELSE NextIndex(startIndex, startLP, startIndex, startLP) ELSE selChanged := (startIndex <> endIndex) OR (startLP <> endLP); IF selChanged THEN HiExtOnPads(hOffToOn, startIndex, startLP, endIndex, endLP); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TMultiParaSelection.MousePress(mouseLPt: LPoint); BEGIN {$IFC fTrace}BP(10);{$ENDC} IF clickState.fShift THEN SELF.MouseMove(mouseLPt) ELSE IF clickState.clickCount > 1 THEN BEGIN {For now do nothing if some jerk starts double/triple clicking while dragging} END ELSE SELF.textImage.MousePress(mouseLPt); {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TMultiParaSelection.MouseRelease; VAR insPt: TInsertionPoint; oneParaSel: TOneParaSelection; first,last: INTEGER; isPara: BOOLEAN; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF SELF.textRange.firstPara = SELF.textRange.lastPara THEN BEGIN isPara := SELF.isParaSelection; IF SELF.textRange.firstLP = SELF.textRange.lastLP THEN BEGIN insPt := SELF.BecomeInsertionPoint; insPt.isParaSelection := isPara; IF NOT isPara THEN insPt.textImage.text.HiliteRange(hOffToOn, insPt.textRange, FALSE); END ELSE BEGIN first := SELF.anchorBegin; last := SELF.anchorEnd; WITH SELF, textRange DO {$H-} oneParaSel := TOneParaSelection(SELF.FreedAndReplacedBy(TOneParaSelection.CREATE(NIL, SELF.Heap, view, textImage, anchorLPoint, firstPara, firstIndex, firstLP, lastLP))); {$H+} WITH oneParaSel DO BEGIN anchorBegin := first; anchorEnd := last; isParaSelection := isPara; isWordSelection := NOT isPara AND (first <> last); END; SELF.textImage.text.ChangeSelInOtherPanels(oneParaSel); END; END ELSE SELF.textImage.text.ChangeSelInOtherPanels(SELF); SUPERSELF.MouseRelease; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} FUNCTION TMultiParaSelection.SelSize: INTEGER; VAR size: INTEGER; s: TListScanner; paragraph: TEditPara; BEGIN {$IFC fTrace}BP(9);{$ENDC} IF SELF.textRange.firstPara = SELF.textRange.lastPara THEN size := SELF.textRange.lastLP - SELF.textRange.firstLP ELSE BEGIN size := SELF.textRange.firstPara.size - SELF.textRange.firstLP; {skip first paragraph by not subtracting one from firstIndex} s := SELF.textImage.text.paragraphs.ScannerFrom(SELF.textRange.firstIndex, scanForward); WHILE s.Scan(paragraph) DO IF paragraph = SELF.textRange.lastPara THEN BEGIN size := size + SELF.textRange.lastLP; s.Done; END ELSE size := size + paragraph.size; END; SelSize := size; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} PROCEDURE TMultiParaSelection.StyleFromContext; VAR typeStyle: TTypeStyle; BEGIN {$IFC fTrace}BP(8);{$ENDC} SELF.textRange.firstPara.StyleAt(SELF.textRange.firstLP, typeStyle); SELF.currTypeStyle := typeStyle; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtIni} END; {Methods of TMultiParaSelection} {$S SgTxtCld} METHODS OF TClearTextCmd; FUNCTION TClearTextCmd.CREATE(object: TObject; heap: THeap; itsCmdNumber: TCmdNumber; itsImage: TImage; itsText: TText): TClearTextCmd; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF object = NIL THEN object := NewObject(heap, THISCLASS); SELF := TClearTextCmd(TCommand.CREATE(object, heap, itsCmdNumber, itsImage, TRUE, revealAll)); WITH SELF DO BEGIN savedText := NIL; text := itsText; END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE TClearTextCmd.Free; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF SELF.savedText <> NIL THEN SELF.savedText.FreeSelf(FALSE); SUPERSELF.Free; {$IFC fTrace}EP;{$ENDC} END; {$IFC fTextTrace} PROCEDURE TClearTextCmd.Fields(PROCEDURE Field(nameAndType: S255)); BEGIN SUPERSELF.Fields(Field); Field('savedText: TText'); Field('text: TText'); Field(''); END; {$ENDC} PROCEDURE TClearTextCmd.Commit; BEGIN {$IFC fTrace}BP(10);{$ENDC} Free(SELF.savedText); SELF.savedText := NIL; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE TClearTextCmd.Perform(cmdPhase: TCmdPhase); var textSel: TTextSelection; insertionPt: TInsertionPoint; text: TText; selection: TSelection; panel: TPanel; {$IFC fTextTrace} junk: TObject; str1: STR255; str2: STR255; {$ENDC} BEGIN {$IFC fTrace}BP(10);{$ENDC} panel := SELF.image.view.panel; text := SELF.text; CASE cmdPhase OF doPhase, redoPhase: BEGIN selection := panel.selection; WHILE selection.coSelection <> NIL DO selection := selection.coSelection; {$IFC fTextTrace} IF fTextTrace THEN BEGIN LIntToHex(ORD(selection), @str1); Writeln('*** Clear Cmd Perfrom; panel last coselection = ', str1); junk := SELF.text.paragraphs.First; {So can set break point here} END; {$ENDC} textSel := TTextSelection(selection.FreedAndReplacedBy( text.SelectAll(TTextSelection(selection).textImage))); text.ChangeSelInOtherPanels(textSel); text.HiliteRange(hOffToOn, textSel.textRange, FALSE); text := textSel.DeleteButSave; SELF.savedText := text; insertionPt := textSel.BecomeInsertionPoint; {$IFC fTextTrace} IF fTextTrace THEN BEGIN LIntToHex(ORD(insertionPt), @str1); Writeln('*** Clear Cmd Perfrom; final insertionPt = ', str1); junk := SELF.text.paragraphs.First; {So can set break point here} END; {$ENDC} END; undoPhase: BEGIN selection := panel.selection; WHILE selection.coSelection <> NIL DO selection := selection.coSelection; insertionPt := TInsertionPoint(selection); insertionPt.InsertText(SELF.savedText, FALSE, FALSE, FALSE); Free(SELF.savedText); SELF.savedtext := NIL; {$$ Need to hilte before, after?} SELF.text.ChangeSelInOtherPanels(insertionPt); END; END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtIni} END; {METHODS OF TClearTextCmd} {$S SgTxtCld} METHODS OF TStyleCmd; FUNCTION TStyleCmd.CREATE(object: TObject; heap: THeap; itsCmdNumber: TCmdNumber; itsImage: TImage; itsFirstIndex: LONGINT; itsLastIndex: LONGINT; itsLPFirst: INTEGER; itsLPLast: INTEGER; itsSelection: TTextSelection): TStyleCmd; VAR sel: TTextSelection; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF object = NIL THEN object := NewObject(heap, THISCLASS); SELF := TStyleCmd(TCommand.CREATE(object, heap, itsCmdNumber, itsImage, TRUE, revealSome)); sel := TTextSelection(itsSelection.Clone(SELF.Heap)); WITH SELF DO BEGIN textSelection := sel; text := sel.textImage.text; firstFiltParaIndex := itsFirstIndex; lastFiltParaIndex := itsLastIndex; filtFirstLP := itsLPFirst; filtLastLP := itsLPLast; currFilteredPara := NIL; filteredStyles := NIL; END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE TStyleCmd.Free; VAR sPar: TListScanner; paragraph: TEditPara; paraImage: TParaImage; BEGIN {$IFC fTrace}BP(10);{$ENDC} sPar := SELF.text.paragraphs.ScannerFrom(SELF.firstFiltParaIndex - 1, scanForward); WHILE sPar.Scan(paragraph) DO BEGIN paragraph.beingFiltered := FALSE; IF sPar.position = SELF.lastFiltParaIndex THEN sPar.Done; END; SELF.textSelection.Free; Free(SELF.filteredStyles); SUPERSELF.Free; {$IFC fTrace}EP;{$ENDC} END; {$IFC fTextTrace} PROCEDURE TStyleCmd.Fields(PROCEDURE Field(nameAndType: S255)); BEGIN SUPERSELF.Fields(Field); Field('text: TText'); Field('textSelection: TTextSelection'); Field('firstFiltParaIndex: LONGINT'); Field('lastFiltParaIndex: LONGINT'); Field('filtFirstLP: INTEGER'); Field('filtLastLP: INTEGER'); Field('currFilteredPara: TEditPara'); Field('filteredStyles: TArray'); Field(''); END; {$ENDC} PROCEDURE TStyleCmd.Commit; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.textSelection.ChangeStyle(SELF.cmdNumber); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE TStyleCmd.FilterAndDo(actualObject: TObject; PROCEDURE DoToObject(filteredObject: TObject)); VAR savedStyles: TArray; paragraph: TEditPara; typeStyle: TTypeStyle; firstLP: INTEGER; lastLP: INTEGER; BEGIN {$IFC fTrace}BP(10);{$ENDC} paragraph := TParaImage(actualObject).paragraph; IF paragraph.beingFiltered THEN BEGIN IF paragraph = SELF.currFilteredPara THEN BEGIN savedStyles := paragraph.typeStyles; paragraph.typeStyles := SELF.filteredStyles; END ELSE BEGIN IF paragraph = TEditPara(SELF.text.paragraphs.At(SELF.firstFiltParaIndex)) THEN firstLP := SELF.filtFirstLP ELSE firstLP := 0; IF paragraph = TEditPara(SELF.text.paragraphs.At(SELF.lastFiltParaIndex)) THEN lastLP := SELF.filtLastLP ELSE lastLP := paragraph.size; Free(SELF.filteredStyles); savedStyles := TArray(paragraph.typeStyles.Clone(SELF.heap)); SELF.textSelection.DoChangeStyle(SELF.cmdNumber, paragraph, firstLP, lastLP, typeStyle); SELF.currFilteredPara := paragraph; SELF.filteredStyles := paragraph.typeStyles; END; DoToObject(TParaImage(actualObject)); paragraph.typeStyles := savedStyles; END ELSE DoToObject(TParaImage(actualObject)); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE TStyleCmd.Perform(cmdPhase: TCmdPhase); VAR textSelection: TTextSelection; selection: TSelection; sPar: TListScanner; paragraph: TEditPara; {Need to filter paragraph before asking about its type styles} PROCEDURE FindFilteredStyle(obj: TObject); BEGIN textSelection.StyleFromContext; END; BEGIN {$IFC fTrace}BP(10);{$ENDC} selection := SELF.image.view.panel.selection; WHILE selection.coSelection <> NIL DO selection := selection.coSelection; textSelection := TTextSelection(selection); IF cmdPhase = doPhase THEN BEGIN sPar := SELF.text.paragraphs.ScannerFrom(SELF.firstFiltParaIndex - 1, scanForward); WHILE sPar.Scan(paragraph) DO BEGIN paragraph.beingFiltered := TRUE; IF sPar.position = SELF.lastFiltParaIndex THEN sPar.Done; END; END; textSelection.MarkChanged; textSelection.textImage.text.RecomputeImages; SELF.FilterAndDo(TParaImage(TEditPara(SELF.text.paragraphs.At( SELF.firstFiltParaIndex)).images.First), FindFilteredStyle); (*textSelection.Invalidate;*) {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtIni} END; {METHODS OF TStyleCmd} {$S SgTxtCld} METHODS OF TTextCutCopy; FUNCTION TTextCutCopy.CREATE(object: TObject; heap: THeap; itsCmdNumber: TCmdNumber; itsImage: TImage; isCutCmd: BOOLEAN; itsText: TText): TTextCutCopy; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF object = NIL THEN object := NewObject(heap, THISCLASS); SELF := TTextCutCopy(TCutCopyCommand.CREATE(object, heap, itsCmdNumber, itsImage, isCutCmd)); WITH SELF DO BEGIN text := itsText; IF itsCmdNumber = uCopy THEN BEGIN unHiliteBefore[doPhase] := FALSE; hiliteAfter[doPhase] := FALSE; END; END; {$IFC fTrace}EP;{$ENDC} END; {$IFC fTextTrace} PROCEDURE TTextCutCopy.Fields(PROCEDURE Field(nameAndType: S255)); BEGIN TCutCopyCommand.Fields(Field); Field('text: TText'); Field(''); END; {$ENDC} PROCEDURE TTextCutCopy.DoCutCopy(clipSelection: TSelection; deleteOriginal: BOOLEAN; cmdPhase: TCmdPhase); VAR textSel: TTextSelection; insertionPt: TInsertionPoint; multiParaSel: TMultiParaSelection; heap: THeap; firstPara: TEditPara; firstLP: INTEGER; panel: TPanel; selection: TSelection; saveTextSel: TTextSelection; firstIndex: LONGINT; BEGIN {$IFC fTrace}BP(10);{$ENDC} heap := SELF.Heap; panel := SELF.image.view.panel; CASE cmdPhase OF doPhase, redoPhase: BEGIN selection := panel.selection; {we know that the last coSelection must be the textSelection since textSelections do not have coSelections} WHILE selection.coSelection <> NIL DO selection := selection.coSelection; textSel := TTextSelection(selection); IF (cmdPhase = redoPhase) AND deleteOriginal THEN SELF.text.HiliteRange(hOffToOn, textSel.textRange, textSel.isParaSelection); textSel.CutCopy(clipSelection, deleteOriginal); END; undoPhase: BEGIN IF deleteOriginal THEN BEGIN selection := panel.selection; WHILE selection.coSelection <> NIL DO selection := selection.coSelection; insertionPt := TInsertionPoint(selection); firstPara := insertionPt.textRange.firstPara; firstLP := insertionPt.textRange.firstLP; firstIndex := insertionPt.textRange.firstIndex; {get the cut text from the clipboard and insert it back into the text} multiParaSel := TMultiParaSelection(clipSelection); insertionPt.InsertText(multiParaSel.textImage.text, multiParaSel.isParaSelection, multiParaSel.isWordSelection, FALSE); IF multiParaSel.isParaSelection THEN BEGIN WITH insertionPt DO IF textRange.firstIndex > 1 THEN BEGIN textRange.firstIndex := textRange.firstIndex - 1; {$H-} textRange.firstPara := TEditPara(SELF.text.paragraphs.At(textRange.firstIndex)); textRange.firstLP := textRange.firstPara.size; {$H+} END; END ELSE IF multiParaSel.isWordSelection THEN {don't want to select extra blank generated by insert} WITH insertionPt DO {$H-} IF firstPara.At(firstLP + 1) = ' ' THEN firstLP := firstLP + 1 ELSE IF textRange.firstPara.At(textRange.firstLP) = ' ' THEN textRange.firstLP := textRange.firstLP - 1; {$H+} {build the original selection} textSel := TTextSelection(selection.FreedAndReplacedBy( insertionPt.textImage.NewTextSelection( firstPara, firstIndex, firstLP, insertionPt.textRange.firstPara, insertionPt.textRange.firstIndex, insertionPt.textRange.firstLP))); textSel.isParaSelection := multiParaSel.isParaSelection; SELF.text.ChangeSelInOtherPanels(textSel); END; END; END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtIni} END; {METHODS OF TTextCutCopy} {$S SgTxtCld} METHODS OF TTextPaste; FUNCTION TTextPaste.CREATE(object: TObject; heap: THeap; itsImage: TImage; itsText: TText): TTextPaste; VAR range: TTextRange; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF object = NIL THEN object := NewObject(heap, THISCLASS); SELF := TTextPaste(TPasteCommand.CREATE(object, heap, uPaste, itsImage)); {need noSelection since it gets FreedAndReplacedBy'ed} range := TTextRange.CREATE(NIL, heap, NIL, 0, 0, NIL, 0, 0); {Perform initializes} WITH SELF DO BEGIN pasteRange := range; text := itsText; savedText := NIL; origIsPara := FALSE; origIsWord := FALSE; clipIsPara := FALSE; END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE TTextPaste.Free; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF SELF.savedText <> NIL THEN SELF.savedText.FreeSelf(FALSE); Free(SELF.pasteRange); SUPERSELF.Free; {$IFC fTrace}EP;{$ENDC} END; {$IFC fTextTrace} PROCEDURE TTextPaste.Fields(PROCEDURE Field(nameAndType: S255)); BEGIN SUPERSELF.Fields(Field); Field('savedText: TText'); Field('pasteRange: TTextRange'); Field('text: TText'); Field('origIsPara: BOOLEAN'); Field('origIsWord: BOOLEAN'); Field('clipIsPara: BOOLEAN'); Field(''); END; {$ENDC} PROCEDURE TTextPaste.Commit; BEGIN {$IFC fTrace}BP(10);{$ENDC} Free(SELF.savedText); SELF.savedText := NIL; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE TTextPaste.DoPaste(clipSelection: TSelection; pic: PicHandle; cmdPhase: TCmdPhase); VAR heap: THeap; textSel: TTextSelection; saveTextSel: TTextSelection; insertionPt: TInsertionPoint; insPtBefore: TInsertionPoint; insPtAfter: TInsertionPoint; text: TText; firstPara: TEditPara; {bad choice of var names; change later (screws up WITH's)} firstLP: INTEGER; firstIndex: LONGINT; panel: TPanel; selection: TSelection; BEGIN {$IFC fTrace}BP(10);{$ENDC} heap := SELF.Heap; panel := SELF.image.view.panel; CASE cmdPhase OF doPhase, redoPhase: BEGIN IF InClass(clipSelection, TTextSelection) OR (clipBoard.hasUniversalText) THEN BEGIN selection := panel.selection; {we know that the last coSelection must be the textSelection since textSelections do not have coSelections} WHILE selection.coSelection <> NIL DO selection := selection.coSelection; textSel := TTextSelection(selection); SELF.origIsPara := textSel.isParaSelection; SELF.origIsWord := textSel.isWordSelection; IF InClass(clipSelection, TTextSelection) THEN SELF.clipIsPara := TTextSelection(clipSelection).isParaSelection; {delete the selected text, leaving an insertion point} text := textSel.DeleteButSave; SELF.savedText := text; insertionPt := textSel.BecomeInsertionPoint; WITH SELF, insertionPt DO BEGIN pasteRange.firstPara := textRange.firstPara; pasteRange.firstIndex := textRange.firstIndex; pasteRange.firstLP := textRange.firstLP; END; insertionPt.FinishPaste(clipSelection, pic); WITH SELF, insertionPt DO IF clipIsPara THEN BEGIN {$H-} pasteRange.lastIndex := Max(1, textRange.firstIndex - 1); pasteRange.lastPara := TEditPara(SELF.text.paragraphs.At(pasteRange.lastIndex)); pasteRange.lastLP := pasteRange.lastPara.size; {$H+} END ELSE BEGIN pasteRange.lastPara := textRange.firstPara; pasteRange.lastIndex := textRange.firstIndex; pasteRange.lastLP := textRange.firstLP; END; SELF.text.ChangeSelInOtherPanels(insertionPt); END ELSE BEGIN panel.selection.CantDoIt; SELF.undoable := FALSE; END; END; undoPhase: BEGIN WITH SELF.pasteRange DO {$H-} textSel := TTextImage(SELF.image).NewTextSelection(firstPara, firstIndex, firstLP, lastPara, lastIndex, lastLP); {$H+} textSel.isParaSelection := SELF.clipIsPara; {user feedback: highlight pasted text} SELF.text.HiliteRange(hOffToOn, SELF.pasteRange, textSel.isParaSelection); {get rid of pasted text; can get it from clipboard for redo} textSel.DeleteAndFree; insertionPt := textSel.BecomeInsertionPoint; firstPara := insertionPt.textRange.firstPara; firstLP := insertionPt.textRange.firstLP; firstIndex := insertionPt.textRange.firstIndex; {put back any text that was pasted over} insertionPt.InsertText(SELF.savedText, SELF.origIsPara, SELF.origIsWord, FALSE); WITH insertionPt DO IF SELF.origIsPara THEN BEGIN {$H-} textRange.firstIndex := Max(1, textRange.firstIndex - 1); textRange.firstPara := TEditPara(SELF.text.paragraphs.At(textRange.firstIndex)); textRange.firstLP := textRange.firstPara.size; {$H+} END; Free(SELF.savedText); SELF.savedText := NIL; selection := panel.selection; WHILE selection.coSelection <> NIL DO selection := selection.coSelection; {build original selection (ie before the paste)} textSel := TTextSelection(selection.FreedAndReplacedBy( insertionPt.textImage.NewTextSelection( firstPara, firstIndex, firstLP, insertionPt.textRange.firstPara, insertionPt.textRange.firstIndex, insertionPt.textRange.firstLP))); textSel.isParaSelection := SELF.origIsPara; textSel.isWordSelection := SELF.origIsWord; SELF.text.ChangeSelInOtherPanels(textSel); insertionPt.Free; END; END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtIni} END; {METHODS OF TTextPaste} {$S SgTxtHot} METHODS OF TTypingCmd; FUNCTION TTypingCmd.CREATE(object: TObject; heap: THeap; itsImage: TImage; itsText: TText): TTypingCmd; VAR range: TTextRange; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF object = NIL THEN object := NewObject(heap, THISCLASS); SELF := TTypingCmd(TCommand.CREATE(object, heap, uTyping, itsImage, TRUE, revealAll)); range := TTextRange.CREATE(NIL, heap, NIL, 0, 0, NIL, 0, 0); {Perform initializes} WITH SELF DO BEGIN newCharCount := 0; newParaCount := 0; text := itsText; savedText := NIL; typingRange := range; otherInsPts := NIL; hiliteAfter[doPhase] := FALSE; END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE TTypingCmd.Free; VAR selection: TSelection; BEGIN {$IFC fTrace}BP(10);{$ENDC} Free(SELF.savedText); selection := SELF.image.view.panel.selection; WHILE selection.coSelection <> NIL DO selection := selection.coSelection; IF InClass(selection, TInsertionPoint) THEN BEGIN TInsertionPoint(selection).typingCmd := NIL; TInsertionPoint(selection).amTyping := FALSE; END; SELF.typingRange.Free; IF SELF.otherInsPts <> NIL THEN SELF.otherInsPts.FreeObject; SUPERSELF.Free; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtCld} {$IFC fTextTrace} PROCEDURE TTypingCmd.Fields(PROCEDURE Field(nameAndType: S255)); BEGIN SUPERSELF.Fields(Field); Field(''); Field('savedText: TText'); Field('text: TText'); Field('newCharCount: INTEGER'); Field('newParaCount: INTEGER'); Field('typingRange: TTextRange'); Field('otherInsPts: TList'); Field(''); END; {$ENDC} {$S SgTxtHot} PROCEDURE TTypingCmd.Perform(cmdPhase: TCmdPhase); VAR text: TText; insertionPt: TInsertionPoint; selection: TSelection; heap: THeap; firstPara: TEditPara; firstLP: INTEGER; textSel: TTextSelection; panel: TPanel; firstIndex: LONGINT; aList: TList; typeStyle: TTypeStyle; PROCEDURE InstallInsPts(obj: TObject); VAR selection: TSelection; BEGIN selection := TTextImage(obj).view.panel.selection; WHILE selection.coSelection <> NIL DO selection := selection.coSelection; IF selection <> insertionPt THEN aList.InsLast(selection); END; BEGIN {$IFC fTrace}BP(10);{$ENDC} heap := SELF.Heap; panel := SELF.image.view.panel; CASE cmdPhase OF doPhase, redoPhase: BEGIN selection := panel.selection; WHILE selection.coSelection <> NIL DO selection := selection.coSelection; textSel := TTextSelection(selection); typeStyle := textSel.currTypeStyle; {We don't want to delete the entire paragraph if we're typing over it, so set isParaSelection to FALSE} textSel.isParaSelection := FALSE; (***** Changed following line 4/27/84 13:07 LSR BUG: redo of backspace (?) leaves garbage deferUpdate := TRUE; *****) deferUpdate := (cmdPhase = doPhase) OR (SELF.savedText <> NIL); text := textSel.DeleteButSave; insertionPt := textSel.BecomeInsertionPoint; WITH SELF.typingRange DO BEGIN firstPara := insertionPt.textRange.firstPara; firstIndex := insertionPt.textRange.firstIndex; firstLP := insertionPt.textRange.firstLP; lastPara := firstPara; lastIndex := firstIndex; lastLP := firstLP; END; IF cmdPhase = doPhase THEN BEGIN WITH insertionPoint DO BEGIN amTyping := TRUE; typingCmd := SELF; IF TFakeTStyle(currTypeStyle) <> TFakeTStyle(typeStyle) THEN BEGIN styleCmdNumber := -1; {so correct typeStyle will be used} currTypeStyle := typeStyle; END; END; {If there is more than one panel displaying this text, then store the insertion points of the other panels in a list for quick access while typing} IF SELF.text.txtImgList.size > 1 THEN BEGIN aList := TList.CREATE(NIL, heap, 0); SELF.text.txtImgList.Each(InstallInsPt); SELF.otherInsPts := aList; END; insertionPt.textRange.firstPara.StartEdit(insertionPt.textRange.firstPara.GrowSize); END ELSE BEGIN firstPara := insertionPt.textRange.firstPara; firstLP := insertionPt.textRange.firstLP; firstIndex := insertionPt.textRange.firstIndex; {put back the typed text} deferUpdate := FALSE; insertionPt.InsertText(SELF.savedText, FALSE, FALSE, FALSE); Free(SELF.savedText); WITH SELF.typingRange DO BEGIN lastPara := insertionPt.textRange.firstPara; lastIndex := insertionPt.textRange.firstIndex; lastLP := insertionPt.textRange.firstLP; END; {build typed selection} textSel := TTextSelection(insertionPt.FreedAndReplacedBy( insertionPt.textImage.NewTextSelection( firstPara, firstIndex, firstLP, insertionPt.textRange.firstPara, insertionPt.textRange.firstIndex, insertionPt.textRange.firstLP))); SELF.text.ChangeSelInOtherPanels(textSel); END; {We always need a valid savedText object, even if no characters were initially typed over, in case previous characters get backspaced over. See code in KeyBack } IF text = NIL THEN BEGIN text := TText.CREATE(NIL, heap, NIL); text.paragraphs.InsLast( TTextImage(SELF.image).NewEditPara(0, SELF.typingRange.firstPara.format)); END; SELF.savedText := text; END; undoPhase: BEGIN WITH SELF.typingRange DO {$H-} textSel := TTextImage(SELF.image).NewTextSelection(firstPara, firstIndex, firstLP, lastPara, lastIndex, lastLP); {$H+} {user feedback: highlight typed text} SELF.text.HiliteRange(hOffToOn, SELF.typingRange, textSel.isParaSelection); {delete but save typed text} text := textSel.DeleteButSave; insertionPt := textSel.BecomeInsertionPoint; firstPara := insertionPt.textRange.firstPara; firstLP := insertionPt.textRange.firstLP; firstIndex := insertionPt.textRange.firstIndex; {put back any text that was typed over} insertionPt.InsertText(SELF.savedText, FALSE, FALSE, FALSE); Free(SELF.savedText); SELF.savedText := text; selection := panel.selection; WHILE selection.coSelection <> NIL DO selection := selection.coSelection; {build original selection (before typing)} textSel := TTextSelection(selection.FreedAndReplacedBy( insertionPt.textImage.NewTextSelection( firstPara, firstIndex, firstLP, insertionPt.textRange.firstPara, insertionPt.textRange.firstIndex, insertionPt.textRange.firstLP))); SELF.text.ChangeSelInOtherPanels(textSel); insertionPt.Free; END; END; {$IFC fTrace}EP;{$ENDC} END; {$S SgTxtIni} END; {METHODS OF TTypingCmd} {$S SgTxtCld}