Visible text: the part of the text editor that maintains a consistent display of an editable text. It also provides highlighting, scrolling, window-splitting, and the insertion caret.
MODULE********************************************************************** Creation **********************************************************************; IMPORT Font, MText, Point, Rd, Rect, Thread, VBT, VT, VTBase, VTCaret, VTDef, VTInterval, VTMarker, VTPounce, VTReal, VTView, VTVirtual, VTextRegion; TYPE LineNo = VTDef.LineNo; VirtualStart = VTDef.VirtualStart; VText
PROCEDURE********************************************************************** Regions **********************************************************************New ( mtext : MText.T; vbt : VBT.T; READONLY rect : Rect.T; READONLY vOptions: VOptions ): T RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = VAR vtext: T; BEGIN IF (mtext = NIL) OR (vbt = NIL) OR (vOptions.vFontxxx = NIL) THEN RAISE VTDef.Error (ErrorCode.IsNil); END; vtext := NEW (T); vtext.mtext := mtext; (* old-style *) vtext.vbt := vbt; (* old-style *) vtext.font := vOptions.vFontxxx.font; (* old-style *) vtext.vOptions := vOptions; (* semi old-style *) vtext.vt := VT.New (mtext); vtext.west := rect.west; (* old-style *) vtext.north := rect.north; (* old-style *) vtext.width := rect.east - rect.west; (* old-style *) vtext.height := rect.south - rect.north; (* old-style *) vtext.regionMax := 0; (* old-style *) vtext.closed := FALSE; VTextRegion.SetupRegion ( vtext, 0, rect.north, rect.south - rect.north, 0); vtext.lineSpacing := vtext.region [0].view.vScreenFont.box.south - vtext.region [0].view.vScreenFont.box.north + vtext.leading; (* old-style *) vtext.lineOffset := -vtext.region [0].view.vScreenFont.box.north; (* old-style *) vtext.caretState := vtext.vt.caret.state; (* old-style *) vtext.dividersDirty := FALSE; RETURN vtext; END New; PROCEDUREExplodeVText (READONLY vtext : T; VAR (* OUT*) mtext : MText.T; VAR (* OUT*) vbt : VBT.T; VAR (* OUT*) rect : Rect.T; VAR (* OUT*) vOptions: VOptions ) RAISES {} = BEGIN mtext := vtext.mtext; vbt := vtext.vbt; rect := Rect.FromEdges(vtext.west, vtext.west + vtext.width, vtext.north, vtext.north + vtext.height); vOptions := vtext.vOptions; END ExplodeVText; PROCEDUREMakeVFont ( font : Font.T; READONLY printable: SET OF CHAR; whiteTabs: BOOLEAN ): VFont RAISES {VTDef.Error} = BEGIN RETURN VTView.MakeVFont(font, printable, whiteTabs); END MakeVFont; PROCEDUREExplodeVFont (READONLY vFont : VFont; VAR (* OUT*) font : Font.T; VAR (* OUT*) printable: SET OF CHAR; VAR (* OUT*) whiteTabs: BOOLEAN ) RAISES {} = BEGIN font := vFont.font; printable := vFont.printable; whiteTabs := vFont.whiteTabs; END ExplodeVFont; PROCEDUREMakeVOptions (vFont: VFont; leftMargin, rightMargin, turnMargin, topMargin, leading: Points; whiteBlack, whiteStroke: ColorScheme; leftOffset : Points; wrap : BOOLEAN; eob : BOOLEAN; intervalStylePrecedence: IntervalStylePrecedence := NIL): VOptions RAISES {} = BEGIN RETURN VTView.MakeVOptions(vFont, leftMargin, rightMargin, turnMargin, topMargin, leading, whiteBlack, whiteStroke, leftOffset, wrap, eob, intervalStylePrecedence); END MakeVOptions; PROCEDUREExplodeVOptions (READONLY vOptions: VOptions; VAR (* OUT*) vFont : VFont; VAR (* OUT*) leftMargin, rightMargin, turnMargin, topMargin, leading: Points; VAR (* OUT*) whiteBlack, whiteStroke: ColorScheme; VAR (* OUT*) leftOffset: Points; VAR (* OUT*) wrap: BOOLEAN; VAR (* OUT*) eob: BOOLEAN; VAR (* OUT*) intervalStylePrecedence: IntervalStylePrecedence) RAISES {} = BEGIN vFont := vOptions.vFontxxx; leftMargin := vOptions.leftMarginPts; rightMargin := vOptions.rightMarginPts; turnMargin := vOptions.turnMarginPts; topMargin := vOptions.topMarginPts; leading := vOptions.leadingPts; whiteBlack := vOptions.whiteBlack; whiteStroke := vOptions.whiteStroke; leftOffset := vOptions.leftOffsetPts; wrap := vOptions.wrap; eob := vOptions.eob; intervalStylePrecedence := vOptions.intervalStylePrecedence; END ExplodeVOptions; PROCEDUREChangeVOptions (vtext: T; READONLY vOptions: VOptions) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = VAR start: Index; BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO vtext.vOptions := vOptions; vtext.font := vtext.vOptions.vFontxxx.font; (* old-style *) WITH vo = vtext.vOptions DO VTView.SetPixelOptions (vo, vtext.vbt); vtext.leftMargin := vo.leftMargin; vtext.rightMargin := vo.rightMargin; vtext.turnMargin := vo.turnMargin; vtext.topMargin := vo.topMargin; vtext.leading := vo.leading END; vtext.left := vtext.west + vtext.leftMargin + vtext.turnMargin; vtext.lineSpacing := vtext.region [0].view.vScreenFont.box.south - vtext.region [0].view.vScreenFont.box.north + vtext.leading; (* old-style *) vtext.lineOffset := -vtext.region [0].view.vScreenFont.box.north; (* old-style *) FOR r := 0 TO vtext.regionMax DO start := vtext.region [r].view.virtual.start.at; VTView.Close (vtext.region [r].view); VTextRegion.SetupRegion ( vtext, r, vtext.region [r].north, vtext.region [r].height, start); END; vtext.dividersDirty := TRUE; END; END ChangeVOptions; PROCEDUREClose (vtext: T) RAISES {VTDef.Error} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; VT.Close (vtext.vt); vtext.closed := TRUE; END; END Close;
PROCEDURE********************************************************************** Moving **********************************************************************SplitRegion (vtext : T; r : Region; v : Pixels; scroll: BOOLEAN := TRUE) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error(ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error(ErrorCode.Closed); END; VTextRegion.SplitRegion(vtext, r, v, scroll); END; END SplitRegion; PROCEDUREMergeRegion (vtext: T; i, j: Region; scroll: BOOLEAN := TRUE) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error(ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error(ErrorCode.Closed); END; VTextRegion.MergeRegion(vtext, i, j, scroll); END; END MergeRegion;
PROCEDURE********************************************************************** Drawing **********************************************************************Move ( vtext : T; READONLY newRect, savedRect: Rect.T; READONLY dividers : ARRAY OF Pixels; scroll : BOOLEAN := TRUE) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error(ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error(ErrorCode.Closed); END; VTextRegion.Move(vtext, newRect, savedRect, dividers, scroll); END; END Move; PROCEDURERescreen (vtext: T; READONLY cd: VBT.RescreenRec) RAISES {} = VAR view := vtext.vt.views; BEGIN WHILE view # NIL DO VTView.Rescreen (view, cd); view := view.next; END; WITH vo = vtext.vOptions DO VTView.SetPixelOptions (vo, vtext.vbt); vtext.leftMargin := vo.leftMargin; vtext.rightMargin := vo.rightMargin; vtext.turnMargin := vo.turnMargin; vtext.topMargin := vo.topMargin; vtext.leading := vo.leading; vtext.left := vtext.west + vtext.leftMargin + vtext.turnMargin; vtext.lineSpacing := vtext.region [0].view.vScreenFont.box.south - vtext.region [0].view.vScreenFont.box.north + vtext.leading; (* old-style *) vtext.lineOffset := -vtext.region [0].view.vScreenFont.box.north; (* old-style *) END END Rescreen;
PROCEDUREUpdate (vtext: T) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; ConcurrentUpdate (vtext); Quiesce (vtext); END Update; PROCEDUREConcurrentUpdate (vtext: T) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; VTextRegion.UpdateDividers (vtext); VTReal.Update (vtext.vt); END; END ConcurrentUpdate; PROCEDUREQuiesce (vtext: T) RAISES {VTDef.Error} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; END; END Quiesce; PROCEDUREBad (vtext: T; READONLY where: Rect.T) RAISES {VTDef.Error} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; VTextRegion.Bad (vtext, where); END END Bad;
**********************************************************************
Editing **********************************************************************
PROCEDURE********************************************************************** The Caret **********************************************************************Replace (vtext: T; begin, end: Index; newText: TEXT) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error(ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error(ErrorCode.Closed); END; IF begin > vtext.vt.length THEN begin := vtext.vt.length; END; IF end > vtext.vt.length THEN end := vtext.vt.length; END; IF begin > end THEN RAISE VTDef.Error(ErrorCode.IllegalIndex); END; VT.Replace(vtext.vt, begin, end, newText); END; END Replace; PROCEDUREReplaceChars ( vtext : T; begin, end: Index; READONLY str : ARRAY OF CHAR) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF begin > vtext.vt.length THEN begin := vtext.vt.length; END; IF end > vtext.vt.length THEN end := vtext.vt.length; END; IF begin > end THEN RAISE VTDef.Error (ErrorCode.IllegalIndex); END; VT.ReplaceChars (vtext.vt, begin, end, str); END; END ReplaceChars; PROCEDUREReplaceFile (vtext : T; begin, end: Index; file : Rd.T; start : Index := 0; numChars : Index := LAST(Index)) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error(ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error(ErrorCode.Closed); END; IF begin > vtext.vt.length THEN begin := vtext.vt.length; END; IF end > vtext.vt.length THEN end := vtext.vt.length; END; IF begin > end THEN RAISE VTDef.Error(ErrorCode.IllegalIndex); END; VT.ReplaceFile(vtext.vt, begin, end, file, start, numChars); END; END ReplaceFile; PROCEDUREInvalidate (vtext: T; begin, oldEnd, newEnd: Index) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error(ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error(ErrorCode.Closed); END; IF begin > vtext.vt.length THEN begin := vtext.vt.length; END; IF oldEnd > vtext.vt.length THEN oldEnd := vtext.vt.length; END; IF (begin > oldEnd) OR (begin > newEnd) THEN RAISE VTDef.Error(ErrorCode.IllegalIndex); END; VT.Invalidate(vtext.vt, begin, oldEnd, newEnd - begin); END; END Invalidate;
PROCEDURE********************************************************************** Intervals **********************************************************************SwitchCaret (vtext: T; state: OnOffState) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error(ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error(ErrorCode.Closed); END; VTCaret.Switch(vtext.vt, state); vtext.caretState := state; (* old-style *) END; END SwitchCaret; PROCEDUREMoveCaret (vtext: T; place: Index) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error(ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error(ErrorCode.Closed); END; IF place > vtext.vt.length THEN place := vtext.vt.length; END; VTCaret.Move(vtext.vt, place); END; END MoveCaret; PROCEDURECaretIndex (vtext: T): Index RAISES {VTDef.Error} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error(ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error(ErrorCode.Closed); END; RETURN vtext.vt.caret.index; END; END CaretIndex;
PROCEDURE********************************************************************** Markers **********************************************************************CreateInterval ( vtext : T; indexL, indexR: Index; READONLY options : IntervalOptions): Interval RAISES {VTDef.Error} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error(ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error(ErrorCode.Closed); END; IF indexL > vtext.vt.length THEN indexL := vtext.vt.length; END; IF indexR > vtext.vt.length THEN indexR := vtext.vt.length; END; IF indexL > indexR THEN RAISE VTDef.Error(ErrorCode.IllegalIndex); END; RETURN VTInterval.New(vtext.vt, indexL, indexR, options); END; END CreateInterval; PROCEDUREExplodeInterval (READONLY interval : Interval; VAR (* OUT *) indexL, indexR: Index; VAR (* OUT *) options : IntervalOptions; VAR (* OUT *) state : OnOffState ) RAISES {} = BEGIN VTInterval.ExplodeInterval (interval, indexL, indexR, options, state) END ExplodeInterval; PROCEDUREMakeIntervalOptions (style : IntervalStyle; whiteBlack, whiteStroke: ColorScheme; leading : Tint ): IntervalOptions RAISES {} = BEGIN RETURN VTInterval.MakeOptions(style, whiteBlack, whiteStroke, leading); END MakeIntervalOptions; PROCEDUREExplodeIntervalOptions (READONLY intervalOptions: IntervalOptions; VAR (* OUT*) style: IntervalStyle; VAR (* OUT*) whiteBlack, whiteStroke: ColorScheme; VAR (* OUT*) leading: Tint) RAISES {} = BEGIN style := intervalOptions.style; whiteBlack := intervalOptions.whiteBlack; whiteStroke := intervalOptions.whiteStroke; leading := intervalOptions.leading; END ExplodeIntervalOptions; PROCEDURESwitchInterval (interval: Interval; state: OnOffState) RAISES {VTDef.Error} = BEGIN VTInterval.Switch (interval, state) END SwitchInterval; PROCEDUREMoveInterval (interval: Interval; indexL, indexR: Index) RAISES {VTDef.Error} = BEGIN VTInterval.Move (interval, indexL, indexR) END MoveInterval; PROCEDUREChangeIntervalOptions ( interval: Interval; READONLY options : IntervalOptions) RAISES {VTDef.Error} = BEGIN VTInterval.ChangeOptions (interval, options) END ChangeIntervalOptions; PROCEDUREDeleteInterval (interval: Interval) RAISES {VTDef.Error} = BEGIN VTInterval.Delete (interval) END DeleteInterval;
PROCEDURECreateMarker (vtext: T; at: Index; options: MarkerOptions): Marker RAISES {VTDef.Error} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF at > vtext.vt.length THEN at := vtext.vt.length; END; RETURN VTMarker.New (vtext.vt, at, options); END; END CreateMarker; PROCEDUREExplodeMarker (READONLY marker : Marker; VAR (* OUT *) at : Index; VAR (* OUT *) options: MarkerOptions; VAR (* OUT*) state : OnOffState ) RAISES {} = BEGIN at := marker.index; options := marker.options; state := marker.state; END ExplodeMarker; PROCEDUREMakeMarkerOptions (whichEnd : WhichEnd; top, bottom: BOOLEAN; stroke : Tint ): MarkerOptions RAISES {} = BEGIN RETURN VTMarker.MakeOptions (whichEnd, top, bottom, stroke); END MakeMarkerOptions; PROCEDUREExplodeMarkerOptions (READONLY markerOptions: MarkerOptions; VAR (* OUT *) whichEnd : WhichEnd; VAR (* OUT *) top, bottom: BOOLEAN; VAR (* OUT *) stroke : Tint ) RAISES {} = BEGIN whichEnd := markerOptions.whichEnd; top := markerOptions.top; bottom := markerOptions.bottom; stroke := markerOptions.stroke; END ExplodeMarkerOptions; PROCEDURESwitchMarker (marker: Marker; state: OnOffState) RAISES {VTDef.Error} = VAR vt: VTDef.T; BEGIN IF marker = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; vt := marker.vt; IF vt = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vt.mutex DO IF vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF marker.vt = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; VTMarker.Switch (marker, state); END; END SwitchMarker;
Sets marker's state := state.
PROCEDUREMoveMarker (marker: Marker; index: Index) RAISES {VTDef.Error} = VAR vt: VTDef.T; BEGIN IF marker = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; vt := marker.vt; IF vt = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vt.mutex DO IF vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF marker.vt = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; IF index > marker.vt.length THEN index := marker.vt.length; END; VTMarker.Move (marker, index); END; END MoveMarker;
Moves the marker.
PROCEDUREChangeMarkerOptions (marker: Marker; options: MarkerOptions) RAISES {VTDef.Error} = VAR vt: VTDef.T; BEGIN IF marker = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; vt := marker.vt; IF vt = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vt.mutex DO IF vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF marker.vt = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; VTMarker.ChangeOptions (marker, options); END; END ChangeMarkerOptions;
Re-sets marker's options.
PROCEDUREDeleteMarker (marker: Marker) RAISES {VTDef.Error} = VAR vt: VTDef.T; BEGIN IF marker = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; vt := marker.vt; IF vt = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vt.mutex DO IF vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF marker.vt = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; VTMarker.Close (marker); END; END DeleteMarker;
Sets marker's state = Off and then deletes marker from the set of markers associated with the VText.
********************************************************************** Scrolling **********************************************************************
PROCEDURE********************************************************************** Locations **********************************************************************Scroll (vtext: T; r: Region; displacement: INTEGER) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF r > vtext.regionMax THEN RAISE VTDef.Error (ErrorCode.IllegalRegion); END; WITH z_144 = vtext.region [r] DO WITH z_145 = z_144.view^ DO IF displacement = 0 THEN RETURN; END; IF displacement > 0 THEN VTVirtual.SetStart ( z_144.view, MIN (VTBase.Down ( z_144.view, z_145.virtual.start.at, displacement), z_145.vt.length)); ELSE VTVirtual.SetStart ( z_144.view, z_145.virtual.start.at, -displacement); END; END; END; END; END Scroll; PROCEDURESetStart (vtext : T; r : Region; place : Index; upLines: CARDINAL := 0; force : BOOLEAN := FALSE) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error(ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error(ErrorCode.Closed); END; IF r > vtext.regionMax THEN RAISE VTDef.Error(ErrorCode.IllegalRegion); END; IF place > vtext.vt.length THEN place := vtext.vt.length; END; VTVirtual.SetStart(vtext.region[r].view, place, upLines, force); END; END SetStart; PROCEDURELinesBetween (vtext : T; begin, end: Index; max : CARDINAL; avail : Pixels := UseCurrentWidth; ): INTEGER RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = (* Compute the number of lines that would be displayed between indexL and end, with "avail" horizontal pixels available. 0 if on same line, 1 if adjacent, etc. Will quit computing and return "max" if there are more lines than that between begin and end. *) VAR index, by: INTEGER; lineCount: INTEGER; turned : BOOLEAN; l0, l1 : INTEGER; start : VirtualStart; width : Pixels; BEGIN IF vtext = NIL THEN RAISE VTDef.Error(ErrorCode.IsNil); END; LOCK vtext^.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error(ErrorCode.Closed); END; IF avail = UseCurrentWidth THEN avail := vtext^.region[0].view.lineWidth; END; IF begin > vtext.vt.length THEN begin := vtext.vt.length; END; IF end > vtext.vt.length THEN end := vtext.vt.length; END; IF begin > end THEN RAISE VTDef.Error(ErrorCode.IllegalIndex); END; (* See if we can give a simple answer *) IF avail = vtext^.region[0].view.lineWidth THEN FOR r := 0 TO vtext^.regionMax DO IF NOT vtext^.region[r].view.virtual.bodyDirty THEN l0 := VTBase.UnsafeLocateLine(vtext^.region[r].view, begin); IF l0 >= 0 THEN l1 := VTBase.UnsafeLocateLine(vtext^.region[r].view, end); IF l1 >= 0 THEN RETURN MIN(MAX(l1 - l0, -1), max); END; END; END; END; END; (* do it the hard way *) VTBase.Up(vtext.region[0].view, avail, begin, 0, start); index := start.at; lineCount := -1; WHILE (index <= end) AND (lineCount < max) DO index := VTBase.ComputeLine( vtext^.region[0].view, avail, index, by, turned, width); lineCount := lineCount + 1; END; RETURN lineCount; END; END LinesBetween; PROCEDUREComputeLine ( vtext : T; from : Index; VAR (* OUT *) max : Index; VAR (* OUT *) turned: BOOLEAN; VAR (* OUT *) width : Pixels ): Index RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = VAR i, m: INTEGER; BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF from > vtext.vt.length THEN from := vtext.vt.length; END; i := VTBase.ComputeLine ( vtext.region [0].view, vtext.region [0].view.lineWidth, from, m, turned, width); max := m; RETURN MIN (i, vtext.vt.length); END; END ComputeLine; PROCEDUREUpLines (vtext: T; place: Index; n: CARDINAL; r: Region := 0): Index RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = VAR start: VirtualStart; BEGIN IF vtext = NIL THEN RAISE VTDef.Error(ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error(ErrorCode.Closed); END; IF place > vtext.vt.length THEN place := vtext.vt.length; END; VTBase.Up(vtext.region[r].view, vtext.region[r].view.lineWidth, place, n, start); RETURN start.at; END; END UpLines;
PROCEDUREStartIndex (vtext: T; r: Region): Index RAISES {VTDef.Error} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF r > vtext.regionMax THEN RAISE VTDef.Error (ErrorCode.IllegalRegion); END; WITH z_148 = vtext.region [r] DO RETURN z_148.view.virtual.start.at; END; END; END StartIndex; PROCEDURELineIndex (vtext: T; r: Region; n: CARDINAL): Index RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF r > vtext.regionMax THEN RAISE VTDef.Error (ErrorCode.IllegalRegion); END; WITH z_149 = vtext.region [r] DO WITH z_150 = z_149.view^ DO IF z_150.virtual.dirty THEN VTVirtual.UpdateView (z_149.view); END; RETURN MIN (z_150.virtual.line [ MIN (n, z_150.virtual.lines)].virtualLine.from, z_150.vt.length); END; END; END; END LineIndex; PROCEDURECharsInRegion (vtext: T; r: Region): CARDINAL RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF r > vtext.regionMax THEN RAISE VTDef.Error (ErrorCode.IllegalRegion); END; WITH z_151 = vtext.region [r] DO WITH z_152 = z_151.view^ DO IF z_152.virtual.dirty THEN VTVirtual.UpdateView (z_151.view); END; RETURN MIN (z_152.virtual.line [ z_152.virtual.lines].virtualLine.from, z_152.vt.length) - z_152.virtual.line [0].virtualLine.from; END; END; END; END CharsInRegion; PROCEDURELocate ( vtext: T; r : Region; place: Index; VAR (* OUT *) h, v : INTEGER ) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = VAR p: Point.T; BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF r > vtext.regionMax THEN RAISE VTDef.Error (ErrorCode.IllegalRegion); END; IF place > vtext.vt.length THEN place := vtext.vt.length; END; WITH z_153 = vtext.region [r] DO IF z_153.view.virtual.dirty THEN VTVirtual.UpdateView (z_153.view); END; VTBase.UnsafeLocatePoint (z_153.view, place, p); IF p.v >= 0 THEN h := p.h; v := p.v + -z_153.view.vScreenFont.box.north; ELSE v := p.v; END; END; END; END Locate; PROCEDUREInRegion (vtext: T; r: Region; place: Index): BOOLEAN RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = VAR p: Index; BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF r > vtext.regionMax THEN RAISE VTDef.Error (ErrorCode.IllegalRegion); END; IF place > vtext.vt.length THEN place := vtext.vt.length; END; p := place; WITH z_154 = vtext.region [r] DO WITH z_155 = z_154.view^ DO IF p < z_155.virtual.start.at THEN RETURN FALSE; END; IF z_155.virtual.dirty THEN VTVirtual.UpdateView (z_154.view); END; RETURN p < z_155.virtual.line [z_155.virtual.lines].virtualLine.from; END; END; END; END InRegion; PROCEDUREWhichLine (vtext: T; r: Region; v: Pixels): CARDINAL RAISES {VTDef.Error} = BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF r > vtext.regionMax THEN RAISE VTDef.Error (ErrorCode.IllegalRegion); END; WITH z_156 = vtext.region [r] DO RETURN MAX ( MIN ((v - z_156.view.vOptions.topMargin) DIV z_156.view.lineSpacing, z_156.view.nLines - 1), 0); END; END; END WhichLine; PROCEDUREPounce ( vtext : T; r : Region; p : Point.T; mode : SelectionMode; VAR (* OUT *) indexL, indexM, indexR: Index; VAR (* OUT *) cage : Rect.T ): WhichEnd RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = VAR c : CHAR; iL, iM, iR: INTEGER; whichEnd : WhichEnd; lineNo : LineNo; BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF r > vtext.regionMax THEN RAISE VTDef.Error (ErrorCode.IllegalRegion); END; VTPounce.Locate (vtext.region [r].view, p, iL, iR, lineNo, c); VTPounce.Extend (vtext.region [r].view, iL, iR, lineNo, c, mode); whichEnd := VTPounce.Encage (vtext.region [r].view, p, iL, iM, iR, cage); <* ASSERT iR <= vtext.vt.length *> (* past the end of the mtext *) indexL := iL; indexM := iM; indexR := iR; RETURN whichEnd; END; END Pounce; PROCEDUREPounceLocate ( vtext : T; r : Region; p : Point.T; VAR (* OUT *) indexL, indexR: Index; VAR (* OUT *) lineNumber : CARDINAL; VAR (* OUT *) c : CHAR ) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = VAR iL, iR: INTEGER; lineNo: LineNo; BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF r > vtext.regionMax THEN RAISE VTDef.Error (ErrorCode.IllegalRegion); END; VTPounce.Locate (vtext.region [r].view, p, iL, iR, lineNo, c); indexL := iL; indexR := iR; lineNumber := lineNo; END; END PounceLocate; PROCEDUREPounceExtend ( vtext : T; r : Region; VAR (* INOUT *) indexL, indexR: Index; lineNumber : CARDINAL; c : CHAR; mode : SelectionMode) RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = VAR iL, iR: INTEGER; BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF r > vtext.regionMax THEN RAISE VTDef.Error (ErrorCode.IllegalRegion); END; IF indexL > vtext.vt.length THEN indexL := vtext.vt.length; END; IF indexR > vtext.vt.length THEN indexR := vtext.vt.length; END; IF indexL > indexR THEN RAISE VTDef.Error (ErrorCode.IllegalIndex); END; iL := indexL; iR := indexR; VTPounce.Extend (vtext.region [r].view, iL, iR, lineNumber, c, mode); <* ASSERT iR <= vtext.vt.length *> (* past the end of the mtext *) indexL := iL; indexR := iR; END; END PounceExtend; PROCEDUREPounceEncage ( vtext : T; r : Region; p : Point.T; indexL: Index; VAR (* OUT *) indexM: Index; indexR: Index; VAR (* OUT *) cage : Rect.T ): WhichEnd RAISES {VTDef.Error, Rd.EndOfFile, Rd.Failure, Thread.Alerted} = VAR iM : INTEGER; whichEnd: WhichEnd; BEGIN IF vtext = NIL THEN RAISE VTDef.Error (ErrorCode.IsNil); END; LOCK vtext.vt.mutex DO IF vtext.vt.closed THEN RAISE VTDef.Error (ErrorCode.Closed); END; IF r > vtext.regionMax THEN RAISE VTDef.Error (ErrorCode.IllegalRegion); END; IF indexL > vtext.vt.length THEN indexL := vtext.vt.length; END; IF indexR > vtext.vt.length THEN indexR := vtext.vt.length; END; IF indexL > indexR THEN RAISE VTDef.Error (ErrorCode.IllegalIndex); END; whichEnd := VTPounce.Encage ( vtext.region [r].view, p, indexL, iM, indexR, cage); indexM := iM; RETURN whichEnd; END; END PounceEncage; BEGIN END VText.