<<>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>> <<>> 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.PutF1["<%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.PutRope[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.PutRope[""] }; 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.PutF1["", 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.