<<>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>> <<>> DIRECTORY Ascii, CharDisplays, SimpleDisplays, IO, ViewerOps, ViewerClasses, ViewerForkers, MessageWindow, Beeps; SimpleDisplaysImpl: CEDAR MONITOR LOCKS NARROW[cd.otherInstanceData, SimpleDisplayState] USING cd: CharDisplay IMPORTS CharDisplays, SimpleDisplays, IO, ViewerOps, ViewerForkers, MessageWindow, Beeps EXPORTS SimpleDisplays ~ BEGIN OPEN CharDisplays, SimpleDisplays; SimpleCharDisplayClass: CharDisplayClass = NEW [CharDisplayClassRep _ [ name: "Simple", Init: SDInit, ChangeDetails: SDChangeDetails, DeleteChar: SDDeleteChar, TakeChar: SDTakeChar, CursorMove: SDCursorMove, Line: SDLine, ClearTo: SDClearTo, ClearAll: SDClearAll, SetEmph: SDSetEmph, Emphasize: SDEmphasize, SetFont: SDSetFont, Beep: SDBeep, Flush: SDFlush, Destroyed: SDDestroyed ]]; SDInit: PROC [cd: CharDisplay, initData: REF ANY] = { sd: SimpleDisplayState _ NEW [ SimpleDisplayStateRep _ [driver: NARROW[initData]] ]; cd.otherInstanceData _ sd; InitCharArray[ sd, cd.det.lines, cd.det.columns ]; [cd.viewer, cd.fromDisplay] _ SimpleDisplaysViewer[sd, cd]; }; SDDeleteChar: ENTRY PROC [cd: CharDisplay] = { ENABLE UNWIND => NULL; sd: SimpleDisplayState = NARROW[cd.otherInstanceData]; line: REF LineRep = sd.theLines[cd.line]; chars: REF TEXT = line.chars; IF sd.debugChars THEN { sd.out.PutRope[""]; }; FOR i: INT IN [cd.col .. cd.det.columns-1) DO chars[i] _ chars[i+1]; ENDLOOP; chars[cd.det.columns-1] _ Ascii.SP; IF line.hasSomeEmphasis THEN { emphs: REF LineEmphsRep _ line.emphs; FOR i: INT IN [cd.col .. cd.det.columns-1) DO emphs[i] _ emphs[i+1]; ENDLOOP; emphs[cd.det.columns-1] _ ALL[FALSE]; }; NoteChange[ cd, sd, line, delete1, cd.col ]; }; SDTakeChar: ENTRY PROC [cd: CharDisplay, char: CHAR, insert: BOOL _ FALSE] = { ENABLE UNWIND => NULL; sd: SimpleDisplayState = NARROW[cd.otherInstanceData]; line: REF LineRep = sd.theLines[cd.line]; chars: REF TEXT _ line.chars; IF sd.debugChars THEN { IF insert THEN {sd.out.PutChar['_]; }; SELECT char FROM IN [Ascii.SP .. Ascii.DEL) => {sd.out.PutChar[char]; }; ENDCASE => {sd.out.PutF["<%h>", IO.char[char]]; }; }; IF insert THEN { FOR i: INT DECREASING IN [cd.col+1 .. cd.det.columns) DO chars[i] _ chars[i-1]; ENDLOOP; IF line.hasSomeEmphasis THEN { emphs: REF LineEmphsRep _ line.emphs; FOR i: INT DECREASING IN [cd.col+1 .. cd.det.columns) DO emphs[i] _ emphs[i-1]; ENDLOOP; }; }; chars[cd.col] _ char; line.emphs[cd.col] _ sd.emphs; line.hasSomeEmphasis _ sd.hasSomeEmphasis OR line.hasSomeEmphasis; NoteChange[ cd, sd, line, (IF insert THEN insert1 ELSE over1), cd.col ]; CursorMoveAux[cd, 0, 1, TRUE, TRUE, TRUE, FALSE]; }; SDCursorMove: ENTRY PROC [cd:CharDisplay, line,col:INT, relative:BOOL_FALSE, doLine,doCol: BOOL _ TRUE] = { ENABLE UNWIND => NULL; CursorMoveAux[cd,line,col,relative,doLine,doCol,TRUE] } ; CursorMoveAux: INTERNAL PROC [cd:CharDisplay, line,col:INT, relative,doLine,doCol,report: BOOL] = { sd: SimpleDisplayState = NARROW[cd.otherInstanceData]; L:INTEGER = cd.det.lines; C:INTEGER = cd.det.columns; IF sd.debugCM AND report THEN { IF relative THEN sd.out.PutRope["", IO.int[col]] ELSE sd.out.PutRope[".>"]; }; IF relative THEN {line _ line + cd.line; col _ col + cd.col}; IF NOT doLine THEN line _ cd.line; IF NOT doCol THEN col _ cd.col; IF cd.det.autoMargins THEN { dl: INT = col / C; line _ line + dl; col _ col - dl * C; WHILE col < 0 DO col _ col + C; line _ line - 1 ENDLOOP; } ELSE col _ MAX[MIN[col, C-1], 0]; IF line < 0 THEN line _ 0; IF cd.det.scrolls THEN IF line >= L THEN { Scroll[cd, 0, L, MIN[ (line-L)+1, L ] ]; line _ L - 1 } ELSE line_line ELSE line _ line MOD L; cd.line _ line; cd.col _ col; }; Scroll: INTERNAL PROC [cd: CharDisplay, start, size, scrollReq:INTEGER] ~ { <<-- start is the index in the lines array of the topmost line to be moved by the scroll>> <<-- size is the index 1 more than the last line in the region being scrolled>> <<-- ABS[scrollReq] may be [0 .. size - start]>> <<-- if scrollReq<0 then insert blank lines at start, remove lines from EOS (scroll down)>> <<-- if scrollReq>0 then delete lines at start, insert blank lines at EOS (scroll up)>> <<>> sd: SimpleDisplayState = NARROW[cd.otherInstanceData]; shift: INTEGER = IF scrollReq < 0 THEN (size-start)+scrollReq ELSE scrollReq; <<-- this loop really is just scrolling up, for scrolling down shift is hacked to get>> <<-- the equivalent of the scroll down by scrolling up.>> upFillBase: INTEGER = size - shift; IF sd.debugScroll THEN sd.out.PutF["Scroll[start:%g,size:%g,req:%g]\n",IO.int[start],IO.int[size],IO.int[scrollReq] ]; IF shift IN (0..size-start) THEN { open: INTEGER _ start + shift; -- this line will eventually be in position start headLine: REF LineRep = sd.theLines[open]; WHILE open # start DO source:INTEGER = IF (open> { fillBase:INTEGER = IF scrollReq < 0 THEN start ELSE upFillBase; logLine:BOOLEAN = start = 0 AND scrollReq = 1 AND sd.logging; FOR i: INTEGER IN [fillBase .. fillBase+ABS[scrollReq]) DO line: REF LineRep = sd.theLines[i]; chars: REF TEXT = line.chars; emphs: REF LineEmphsRep = line.emphs; line.modified _ new; line.hasSomeEmphasis _ FALSE; IF logLine THEN LogTranscriptLine[sd, chars]; FOR j: INTEGER IN [0 .. chars.maxLength) DO chars[j] _ Ascii.SP; emphs[j] _ ALL[ FALSE ]; ENDLOOP; ENDLOOP; }; <<-- Flush changes to display>> IF sd.flushMode = FlushOnScroll THEN { ViewerForkers.ForkPaint[ viewer: sd.aViewer, hint: ViewerClasses.PaintHint.client, clearClient: FALSE, whatChanged: $LINES, tryShortCuts: FALSE ]; WAIT sd.paintDone; }; }; SDLine: ENTRY PROC [cd: CharDisplay, insert: BOOL] = { ENABLE UNWIND => NULL; sd: SimpleDisplayState = NARROW[cd.otherInstanceData]; IF sd.debugOps THEN { sd: SimpleDisplayState = NARROW[cd.otherInstanceData]; msg: ROPE _ IF insert THEN "" ELSE ""; sd.out.PutRope[msg]; }; Scroll[ cd, cd.line, cd.det.lines, IF insert THEN -1 ELSE 1 ]; }; SDClearTo: ENTRY PROC [cd: CharDisplay, where: Where] = { ENABLE UNWIND => NULL; sd: SimpleDisplayState = NARROW[cd.otherInstanceData]; line: REF LineRep = sd.theLines[cd.line]; chars: REF TEXT _ line.chars; IF sd.debugOps THEN { sd: SimpleDisplayState = NARROW[cd.otherInstanceData]; msg: ROPE _ SELECT where FROM EndOfLine => "", EndOfScreen => "", ENDCASE => ERROR; sd.out.PutF[msg]; }; FOR j: INT IN [cd.col .. cd.det.columns) DO chars[j] _ Ascii.SP; ENDLOOP; IF line.hasSomeEmphasis THEN { emphs: REF LineEmphsRep _ line.emphs; FOR j: INT IN [cd.col .. cd.det.columns) DO emphs[j] _ ALL[ FALSE ]; ENDLOOP; }; IF cd.col = 0 THEN { line.modified _ new; line.hasSomeEmphasis _ FALSE; } ELSE NoteChange[ cd, sd, line, tail, cd.col ]; IF where = EndOfScreen AND cd.line+1 < cd.det.lines THEN Scroll[ cd, cd.line+1, cd.det.lines, cd.det.lines - (cd.line+1) ] }; SDClearAll: ENTRY PROC [cd: CharDisplay] = { ENABLE UNWIND => NULL; sd: SimpleDisplayState = NARROW[cd.otherInstanceData]; IF sd.debugOps THEN { sd.out.PutF[""] }; Scroll[ cd, 0, cd.det.lines, cd.det.lines ]; }; EmphNames: ARRAY Emph OF ROPE _ [ underline: "underline", bold: "bold", italic: "italic", inverse: "inverse"]; SDSetEmph: ENTRY PROC [cd: CharDisplay, emph: Emph, on: BOOL] = { ENABLE UNWIND => NULL; sd: SimpleDisplayState = NARROW[cd.otherInstanceData]; IF sd.debugEmph THEN sd.out.PutF["<%g %g>", IO.rope[EmphNames[emph]], IO.bool[on]]; sd.emphs[emph] _ on; sd.hasSomeEmphasis _ sd.emphs[underline] OR sd.emphs[bold] OR sd.emphs[italic] OR sd.emphs[inverse] ; }; SDEmphasize: ENTRY PROC [cd: CharDisplay, emph: Emph, on: BOOL] = { ENABLE UNWIND => NULL; sd: SimpleDisplayState = NARROW[cd.otherInstanceData]; IF sd.debugEmph THEN sd.out.PutF["<%g %g@>", IO.rope[EmphNames[emph]], IO.bool[on]]; sd.theLines[cd.line].emphs[cd.col][emph] _ on; NoteChange[ cd, sd, sd.theLines[cd.line], over1, cd.col ]; }; SDSetFont: ENTRY PROC [cd: CharDisplay, font: ROPE] = { ENABLE UNWIND => NULL; sd: SimpleDisplayState = NARROW[cd.otherInstanceData]; IF sd.debugOps THEN sd.out.PutF["", IO.rope[font]]; }; SDBeep: ENTRY PROC [cd: CharDisplay] = { ENABLE UNWIND => NULL; IF Beeps.can THEN Beeps.Beep[ frequency:1000, duration:65 ] -- Hz, milliseconds ELSE { MessageWindow.Append["Beep", TRUE]; MessageWindow.Blink[]; MessageWindow.Clear[]; }; }; SDFlush: PROC [cd: CharDisplay] ~ { sd: SimpleDisplayState = NARROW[cd.otherInstanceData]; ViewerOps.PaintViewer[sd.aViewer, ViewerOps.PaintHint.client, FALSE, $LINES]; sd.changeCount _ 0; }; SDDestroyed: ENTRY PROC [cd: CharDisplay] RETURNS [b: BOOL] = { ENABLE UNWIND => NULL; sd: SimpleDisplayState = NARROW[cd.otherInstanceData]; b _ sd.aViewer.destroyed; }; <> InitSimpleDisplayClass: PROC ~ { RegClass[SimpleCharDisplayClass]; }; InitCharArray: PROC [sd: SimpleDisplayState, r,c: INT] ~ { sd.theLines _ NEW[LinesRep[r]]; FOR i: INT IN [0..r) DO lineEmphs: REF LineEmphsRep _ NEW[LineEmphsRep[c]]; lineChars: REF TEXT _ NEW[TEXT[c]]; FOR j: INT IN [0..c) DO <> lineChars[j] _ Ascii.SP; ENDLOOP; sd.theLines[i] _ NEW [LineRep _ [ emphs: lineEmphs, chars: lineChars, screenLine: i ]]; ENDLOOP; }; ResizeTerminal: PUBLIC PROC [ cd: CharDisplay, sd: SimpleDisplayState, r,c: INT ] ~ { oldLines: REF LinesRep _ sd.theLines; oldr: INT _ cd.det.lines; oldc: INT _ cd.det.columns; oldCopyBase : INT _ IF oldr > r THEN oldr - r ELSE 0; InitCharArray[ sd, r, c ]; FOR i: INT IN [0..MIN[r,oldr]) DO oldes: REF LineEmphsRep _ oldLines[oldCopyBase + i].emphs; newes: REF LineEmphsRep _ sd.theLines[i].emphs; oldcs: REF TEXT _ oldLines[oldCopyBase + i].chars; newcs: REF TEXT _ sd.theLines[i].chars; sd.theLines[i].hasSomeEmphasis _ oldLines[oldCopyBase + i].hasSomeEmphasis; FOR j: INT IN [0..MIN[c,oldc]) DO newes[j] _ oldes[j]; newcs[j] _ oldcs[j]; ENDLOOP; ENDLOOP; cd.det.lines _ r; cd.det.columns _ c; cd.line _ MIN[ cd.line, r-1 ]; cd.col _ MIN[ cd.col, c-1 ]; }; <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>> <<};>> <<>> NoteChange: INTERNAL PROC [cd: CharDisplay, sd: SimpleDisplayState, line:REF LineRep, mod:ModificationType, col:INT] ~ { IF line.modified = unchanged THEN { line.modified _ mod; line.tailStartColumn _ col } ELSE IF line.modified = new THEN NULL ELSE { line.modified _ tail; line.tailStartColumn _ MIN[ line.tailStartColumn, col ]; }; IF sd.flushMode = FlushOnChangeCount THEN IF sd.changeCount >= sd.changeCountLimit THEN { sd.changeCount _ 0; ViewerForkers.ForkPaint[ viewer: sd.aViewer, hint: ViewerClasses.PaintHint.client, clearClient: FALSE, whatChanged: $LINES, tryShortCuts: FALSE ]; WAIT sd.paintDone; <> } ELSE { sd.changeCount _ sd.changeCount + 1; } }; InitSimpleDisplayClass[]; END.