<> <> <> <> <> DIRECTORY CursorDefs, DisplayDefs USING [DisplayOff], FrameDefs USING [MakeCodeResident, GlobalFrame], Graphics USING [black, CharData, CopyContext, DestroyPath, DisplayChar, DisplayContext, DisplayString, DrawRectangle, DrawScreenArea, EnterPoint, GetStringBox, grey, InitContext, MakeFont, Map, MoveTo, NewContext, PaintingFunction, ScreenToUser, SetClipArea, SetFont, SetLineWidth, SetPaint, SetTexture, StartAreaPath, Texture, Translate, Vec, white], ImageDefs USING [StopMesa], IODefs USING [ReadChar, Rubout, SetEcho, WriteLine], MiscDefs USING [CurrentTime], MusicDefs USING [AnyBug, BlueBug, Control, MouseX, MouseY, RedBug, Shift, YellowBug], MusicProcess, InterfaceImplA, Real USING [FixI], Score USING [InitializeSynthesizer, StopListening, StopPlaying, Test], Screen USING [CommandProcs], StreamDefs USING [DiskHandle, FileNameError, GetDefaultKey, KeyboardHandle, NewByteStream, Read], StringDefs USING [AppendChar, AppendString, EqualString, InvalidNumber], SystemDefs USING [AllocateHeapString, AllocateSegment, FreeHeapString], Utility USING [InitStorage]; ScreenImpl: CEDAR PROGRAM IMPORTS DisplayDefs, FrameDefs, Graphics, ImageDefs, IODefs, MiscDefs, MusicDefs, Music: MusicProcess, Interface: InterfaceImplA, Real, Score, StreamDefs, StringDefs, SystemDefs, Utility EXPORTS Screen = BEGIN OPEN Graphics, CursorDefs, MusicDefs, Screen; keyboard: StreamDefs.KeyboardHandle; <<******************************************************************>> <> <<******************************************************************>> Main: PROC = { Initialize[]; DrawScreen[]; ReadCommandLine[]; DisplayMessage["Mockingbird of January 16, 1982"]; DO IF badCommand THEN { WHILE IODefs.ReadChar[]#177C DO NULL; ENDLOOP; EraseMessage[]; badCommand _ FALSE; }; badCommand _ FALSE; SELECT TRUE FROM RedBug[] => HandleRed[]; BlueBug[] => HandleBlue[]; YellowBug[] => HandleYellow[]; NOT keyboard.endof[keyboard] => ReadKeyboard[]; ENDCASE => ChangeCursor[]; FOR w: CARDINAL IN [1..noWindows) DO IF windows[w].command.count>50 THEN BackUp[w]; ENDLOOP; ENDLOOP; }; badCommand: BOOL _ FALSE; Command: PROC RETURNS[BOOL] = { image: Image; EraseMessage[]; MousePoint[]; ScreenP _ ScreenToUser[screen, MouseP]; image _ FindCommand[ScreenP]; IF image.command # NullProc THEN { image.command[image.rect]; WHILE AnyBug[] DO NULL; ENDLOOP; RETURN[TRUE]}; RETURN[FALSE]; }; HandleRed: PROC = { w: CARDINAL; top: REAL; IF Command[] THEN RETURN; w _ FindWindow[ScreenP.y]; IF w = 0 THEN RETURN; Select[w]; top _ windows[w].top-header-40; IF ScreenP.x> 606 THEN RETURN; SELECT TRUE FROM Control[] => windows[w].command.redbug[]; Shift[] => windows[w].command.redbug[]; ScreenP.x Scroll[w, Real.FixI[top-ScreenP.y]]; ScreenP.x > rightMargin => NULL; --MoveWindow[ScreenP.y]; ENDCASE => windows[w].command.redbug[]; }; HandleBlue: PROC = { w: CARDINAL; top: REAL; IF Command[] THEN RETURN; w _ FindWindow[ScreenP.y]; IF w = 0 THEN RETURN; Select[w]; IF ScreenP.x> 606 THEN RETURN; top _ windows[w].top-header-40; SELECT TRUE FROM Control[] => windows[w].command.bluebug[]; Shift[] => windows[w].command.bluebug[]; ScreenP.x Scroll[w, Real.FixI[ScreenP.y-top]]; ScreenP.x > rightMargin => NULL; --NewWindow[w, ScreenP.y]; ENDCASE => windows[w].command.bluebug[]; }; HandleYellow: PROC = { w: CARDINAL; IF Command[] THEN RETURN; w _ FindWindow[ScreenP.y]; IF w = 0 THEN RETURN; Select[w]; IF ScreenP.x> 606 THEN RETURN; SELECT TRUE FROM Control[] => windows[w].command.yellowbug[]; Shift[] => windows[w].command.yellowbug[]; ScreenP.x < leftMargin => windows[w].command.thumb[]; ScreenP.x > rightMargin => NULL; --SubWindow[w, ScreenP.y]; ENDCASE => windows[w].command.yellowbug[]; }; ReadKeyboard: PROC = { ENABLE { StringDefs.InvalidNumber => { DisplayMessage["illegal number- type DEL to continue"]; badCommand _ TRUE; CONTINUE; }; IODefs.Rubout => { DisplayMessage["command terminated"]; CONTINUE; }; }; EraseMessage[]; windows[selectedWindow].command.keyboard; }; ChangeCursor: PROC = { newState: CursorState; MousePoint[]; ScreenP _ ScreenToUser[screen, MouseP]; IF ScreenP.x> 606 THEN RETURN; SELECT TRUE FROM FindCommand[ScreenP].command#NullProc => newState _ command; ScreenP.y > windows[0].bottom => newState _ commandwindow; ScreenP.x > rightMargin => newState _ window; ScreenP.x < leftMargin => newState _ scroll; ENDCASE => newState _ screen; IF newState=currentState THEN RETURN; IF currentState=screen THEN oldCursor _ cursor^; SELECT newState FROM window => cursor^ _ windowCursor; command => cursor^ _ bullseyeCursor; scroll => cursor^ _ scrollUpDownCursor; commandwindow => cursor^ _ textCursor; ENDCASE => cursor^ _ oldCursor; currentState _ newState; }; oldCursor: Cursor _ textCursor; CursorState: TYPE = {window, scroll, command, screen, commandwindow}; currentState: CursorState _ screen; Scroll: PROC[w: CARDINAL, y: INTEGER] = { IF y > 0 THEN cursor^ _ scrollUpCursor; IF y < 0 THEN cursor^ _ scrollDownCursor; windows[w].command.scroll[y]; cursor^ _ scrollUpDownCursor; }; Initialize: PROC = { DisplayDefs.DisplayOff[white]; <> [] _ IODefs.SetEcho[FALSE]; Utility.InitStorage[]; keyboard _ StreamDefs.GetDefaultKey[]; screen _ NewContext[NIL]; InitContext[screen]; SetLineWidth[screen, 1]; windows[0] _ [screen,, command,@commandProcs, 800, 740]; DefaultWindow[1, 740, 0]; SetFont[screen, MakeFont["TimesRoman"], 12]; manager _SystemDefs.AllocateSegment[SIZE[Image]*mMax]; commandProcs.display _ DisplayCommandWindow; FrameDefs.MakeCodeResident[FrameDefs.GlobalFrame[Music]]; Score.InitializeSynthesizer[]; }; ReadCommandLine: PROC = { OPEN StreamDefs, StringDefs; ENABLE StreamDefs.FileNameError => { DisplayMessage["no such file"]; CONTINUE; }; char: CHARACTER; CR: CHARACTER=015C; filename: STRING _ [40]; ending: STRING _ [12]; test, error: BOOL _ FALSE; hardcopy: BOOL _ FALSE; command, second, period: BOOL _ FALSE; inputStream: DiskHandle; inputStream _ NewByteStream["com.cm", Read]; inputStream.reset[inputStream]; DO IF inputStream.endof[inputStream] THEN EXIT; char _ inputStream.get[inputStream]; <> IF command THEN SELECT char FROM '/ => EXIT; 'n => NULL; 't => test _ TRUE; 'h => hardcopy _ TRUE; ' => command _ FALSE; ENDCASE => NULL; IF char='/ THEN command _ TRUE; IF command THEN LOOP; <> SELECT TRUE FROM char=CR OR char=' => NULL; inputStream.endof[inputStream] => NULL; char='. => IF period THEN EXIT ELSE {period _ TRUE; LOOP}; period => {AppendChar[ending, char]; LOOP}; ENDCASE => {AppendChar[filename, char]; LOOP}; <> IF filename.length#0 AND ~EqualString[ending,"image"] AND ~EqualString[ending,"bcd"] THEN { AppendString[filename,".music"]; windows[1].file.length _ 0; AppendString[windows[1].file, filename]; DisplayHeader[black, 1]; DisplayMessage["Please wait-- retrieving file"]; IODefs.WriteLine[filename]; windows[1].command.fileIn[filename, second]; EraseMessage[]; windows[1].command.display[TRUE]; <> IF test AND Score.Test[] THEN {error _ TRUE; EXIT}; IF hardcopy THEN Hardcopy[[[215, 747],[249, 761]]]; second _ TRUE}; filename.length _ 0; ending.length _ 0; period _ FALSE; ENDLOOP; inputStream.destroy[inputStream]; <> IF test AND ~error THEN Quit[[[0, 0],[0, 0]]]; IF hardcopy THEN Quit[[[0, 0],[0, 0]]]; }; MousePoint: PROC= { x, y: REAL _ 1; x _ x*MouseX^; y _ y*MouseY^; MouseP _ [x, y]; }; MouseP, ScreenP: Vec; <<******************************************************************>> <> <<******************************************************************>> DrawScreen: PROC = { i: CARDINAL; FOR i IN [0..noWindows) DO windows[i].command.display[TRUE] ENDLOOP; }; MoveWindow: PROC[y: REAL] = { i, a, w: CARDINAL _ 0; dist, last: REAL _ 1000; cursor^ _ moveWindowCursor; FOR i IN [1..noWindows) DO IF (windows[i].top-y windows[a].top - 16 THEN y _ windows[a].top - 16; IF y < windows[w].bottom + 16 THEN y _ windows[w].bottom + 16; MoveContext[w, y]; windows[a].bottom _ y; windows[w].top _ y; SetClipper[a]; SetClipper[w]; DisplayHeader[black, w]; IF last > windows[w].top THEN windows[a].command.display[TRUE]; windows[w].command.display[TRUE]; Select[w]; }; NewWindow: PROC[w: CARDINAL, y: REAL] = { <> cursor^ _ newWindowCursor; WHILE BlueBug[] AND NOT YellowBug[] DO NULL; ENDLOOP; IF YellowBug[] THEN { DeleteWindow[w]; RETURN; }; DefaultWindow[noWindows, y, windows[w].bottom]; windows[w].bottom _ y; Select[noWindows]; DisplayHeader[black, noWindows]; SetClipper[w]; SetClipper[noWindows]; noWindows _ noWindows + 1; }; SubWindow: PROC[w: CARDINAL, y: REAL] = { <> cursor^ _ subWindowCursor; WHILE NOT BlueBug[] AND YellowBug[] DO NULL; ENDLOOP; IF BlueBug[] THEN { DeleteWindow[w]; RETURN; }; Flash[]; }; FindWindow: PROC[y: REAL] RETURNS[CARDINAL] = { i: CARDINAL; FOR i IN [0..noWindows) DO IF y < windows[i].top AND y > windows[i].bottom THEN RETURN[i]; ENDLOOP; RETURN[0]; }; DeleteWindow: PROC[w: CARDINAL] = { neighbor: CARDINAL; cursor^ _ windowCursor; Invert[windows[w].context]; WHILE BlueBug[] AND YellowBug[] DO NULL; ENDLOOP; Wait[1]; Invert[windows[w].context]; IF BlueBug[] OR YellowBug[] THEN RETURN; neighbor _ FindWindow[windows[w].top + 1]; IF neighbor # 0 THEN { windows[neighbor].bottom _ windows[w].bottom; DisplayHeader[white, w]; } ELSE { neighbor _ FindWindow[windows[w].bottom - 1]; IF neighbor # 0 THEN { MoveContext[neighbor, windows[w].top]; DisplayHeader[white, neighbor]; windows[neighbor].top _ windows[w].top; DisplayHeader[black, neighbor]; }; }; IF neighbor = 0 THEN { DisplayMessage["cannot delete that window"]; RETURN; }; noWindows _ noWindows - 1; SystemDefs.FreeHeapString[windows[w].file]; windows[w] _ windows[noWindows]; SetClipper[neighbor]; Select[neighbor]; windows[neighbor].command.display[TRUE]; }; Invert: PROC[dc: DisplayContext] = { SetTexture[dc, black]; SetPaint[dc, invert]; DrawScreenArea[dc]; SetPaint[dc, replace]; }; MoveContext: PROC[w: CARDINAL, y: REAL] = { sip, sop, tip, top: Vec; sip _ [0, y]; tip _ [0, windows[w].top]; sop _ Map[screen, windows[w].context, sip]; top _ Map[screen, windows[w].context, tip]; Translate[windows[w].context,[0, sop.y- top.y]]; }; Select: PROC[w: CARDINAL] = { SetBrush[black, erase]; DrawRectangle[screen,[20, windows[selectedWindow].top- header- 10], [28, windows[selectedWindow].top- header]]; SetBrush[grey, paint]; DrawRectangle[screen,[20, windows[w].top- header- 10],[28, windows[w].top- header]]; selectedWindow _ w; }; selectedWindow: CARDINAL _ 1; listenWindow: CARDINAL _ 1; DefaultWindow: PROC[w: CARDINAL, top, bottom: REAL] = { Logical: POINTER TO FRAME[InterfaceImplA]; windows[w] _ [,, unknown,@unknownProcs, top, bottom]; windows[w].context _ CopyContext[screen]; windows[w].file _ SystemDefs.AllocateHeapString[40]; Translate[windows[w].context,[30, top - header - 40]]; --30 regular, 45 for videotaping SetClipper[w]; SetTexture[windows[w].context, black]; SetPaint[windows[w].context, erase]; DrawScreenArea[windows[w].context]; windows[w].type _ logical; Logical _ NEW Interface; windows[w].command _ START Logical; windows[w].command.initialize[windows[w].context]; }; <<******************************************************************>> <> <<******************************************************************>> DisplayCommandWindow: PROC[redraw: BOOL] = { i: CARDINAL; Erase[TRUE]; SetBrush[black, replace]; ClearManager[]; DisplayCommand["FileIn", 30, 750, FileIn]; DisplayCommand["PlayBack", 110, 750, Play]; DisplayCommand["Print", 215, 750, Hardcopy]; DisplayCommand["Quit", 300, 750, Quit]; DisplayCommand["Record", 385, 750, Listen]; DisplayCommand["FileOut", 480, 750, FileOut]; FOR i IN [1..noWindows) DO DisplayHeader[black, i] ENDLOOP; Select[1]; }; DisplayCommand: PROC[command: STRING, x, y: REAL, proc: PROC[r: Rect]] = { ll, ur: Vec; data: CharData; MoveTo[screen,[x, y]]; SetBrush[black, invert]; DisplayString[screen, command]; GetStringBox[screen, command,@data]; ll.x_ x + data.origin.x; ll.y_ y + data.origin.y; ur.x_ ll.x + data.size.x; ur.y_ ll.y + data.size.y; IF ur.x - ll.x < 30 THEN ur.x _ ll.x + 30; AddCommand[[ll, ur], proc]; }; DisplayHeader: PROC[color: Texture, w: CARDINAL] = { top: REAL _ windows[w].top; p: Vec _ [30, windows[w].top - 16]; SetBrush[color, replace]; DrawRectangle[screen,[0, top-header],[620, top]]; DeleteCommand[p]; IF color = grey THEN SetBrush[grey, invert]; IF color = black THEN SetBrush[black, invert ]; IF color = white THEN RETURN; DisplayCommand[windows[w].file, 30, top-12, EditFileName]; }; EraseMessage: PROC = { SetBrush[white, replace]; DrawRectangle[screen,[0, 763],[620, 780]]; SetBrush[black, invert]; }; DisplayMessage: PUBLIC PROC[s: STRING] = { data: CharData; IF s=NIL THEN {EraseMessage[]; RETURN}; SetBrush[black, replace]; DrawRectangle[screen,[0, 765],[620, 780]]; SetBrush[black, invert]; GetStringBox[screen, s,@data]; MoveTo[screen,[300 - data.width.x/2, 767]]; DisplayString[screen, s]; }; AddCommand: PROC[r: Rect, proc: PROC[r: Rect]] = { FOR i: CARDINAL IN [0..mIndex) DO IF manager[i].command=proc THEN RETURN; ENDLOOP; manager[mIndex] _ [r, proc]; IF proc=Play THEN playIndex _ mIndex; IF proc=Listen THEN listenIndex _ mIndex; mIndex _ mIndex + 1; }; DeleteCommand: PROC[p: Vec] = { i: CARDINAL; FOR i IN [0..mIndex) DO IF manager[i].rect.ll = p THEN { mIndex _ mIndex - 1; manager[i] _ manager[mIndex]; }; ENDLOOP; }; FindCommand: PROC[p: Vec] RETURNS[m: Image]= { i: CARDINAL; FOR i IN [0..mIndex) DO { m _ manager[i]; IF p.x > m.rect.ll.x AND p.x < m.rect.ur.x AND p.y > m.rect.ll.y AND p.y < m.rect.ur.y THEN RETURN[m]; }; ENDLOOP; m.command _ NullProc; RETURN[m]; }; Flash: PROC = { Invert[windows[selectedWindow].context]; Invert[windows[selectedWindow].context]; }; Erase: PROC[redraw: BOOL] = { SetTexture[screen, white]; SetPaint[screen, replace]; DrawScreenArea[screen]; SetTexture[screen, black]; SetPaint[screen, paint]; }; <<******************************************************************>> <> <<******************************************************************>> Confirm: PROC[w: CARDINAL, s: STRING] RETURNS[BOOL] = { confirm: BOOL; IF windows[w].command.count=0 THEN RETURN[TRUE]; DisplayMessage[s]; confirm_ IODefs.ReadChar[]=CR; EraseMessage[]; RETURN[confirm]; }; FileIn: PROC[r: Rect] = { ENABLE StreamDefs.FileNameError => { DisplayMessage["no such file"]; DrawRectangle[screen, r.ll, r.ur]; CONTINUE; }; s: CARDINAL _ selectedWindow; SetBrush[black, invert]; DrawRectangle[screen, r.ll, r.ur]; IF Confirm[s,"the current file has not been filed out-- type CR to confirm"] THEN { windows[s].command.fileIn[windows[s].file, FALSE]; EraseMessage[]; windows[s].command.display[TRUE]; windows[s].command.count _ 0; }; DrawRectangle[screen, r.ll, r.ur]; }; FileOut: PROC[r: Rect] = { ENABLE StreamDefs.FileNameError => { DisplayMessage["illegal file name"]; DrawRectangle[screen, r.ll, r.ur]; CONTINUE; }; s: CARDINAL _ selectedWindow; SetBrush[black, invert]; DrawRectangle[screen, r.ll, r.ur]; windows[s].command.fileOut[windows[s].file]; windows[s].command.count _ 0; DrawRectangle[screen, r.ll, r.ur]; }; BackUp: PROC[w: CARDINAL] = { DisplayMessage["Please wait... storing file on backup.music"]; windows[w].command.fileOut["backup.music"]; windows[w].command.count _ 1; -- so it will look dirty EraseMessage[]; }; Play: PROC[r: Rect] = { windows[selectedWindow].command.play[]; }; InvertPlay: PUBLIC PROC = { r: Rect = manager[playIndex].rect; SetBrush[black, invert]; DrawRectangle[screen, r.ll, r.ur]; }; Listen: PROC[r: Rect] = { windows[listenWindow].command.listen[]; listenWindow _ selectedWindow; }; InvertListen: PUBLIC PROC = { r: Rect = manager[listenIndex].rect; SetBrush[black, invert]; DrawRectangle[screen, r.ll, r.ur]; }; playIndex: CARDINAL _ 0; listenIndex: CARDINAL _ 0; Hardcopy: PROC[r: Rect] = { SetBrush[black, invert]; DrawRectangle[screen, r.ll, r.ur]; DisplayMessage["Please wait... printing screen on music.press"]; windows[selectedWindow].command.hardcopy["music.press"]; DrawRectangle[screen, r.ll, r.ur]; EraseMessage[]; }; EditFileName: PROC[r: Rect] = { w: CARDINAL _ FindWindow[ScreenP.y]; c, last: CHARACTER _ 040C; CR: CHARACTER _ 015C; IF w = 0 THEN RETURN; windows[w].file.length _ 0; DisplayMessage["Please enter filename."]; DisplayHeader[white, w]; DisplayHeader[black, w]; DO { c _ IODefs.ReadChar[]; IF c=177C OR c=010C THEN { IF windows[w].file.length = 0 THEN LOOP; windows[w].file.length_ windows[w].file.length- 1; DisplayHeader[black, w]; LOOP; }; IF c=' THEN { windows[w].file.length_ 0; DisplayHeader[black, w]; LOOP; }; IF c#CR AND c#'. AND c#033C THEN { StringDefs.AppendChar[windows[w].file, c]; DisplayChar[screen, c]; LOOP; }; StringDefs.AppendString[windows[w].file,".music"]; windows[w].type _ logical; EXIT; }; ENDLOOP; DisplayHeader[black, w]; EraseMessage[]; Select[w]; }; Quit: PROC[r: Rect] = { IF NOT Confirm[1,"type CR to confirm Quit"] THEN RETURN; Score.StopPlaying[]; Score.StopListening[]; ImageDefs.StopMesa; }; ClearManager: PROC = { mIndex _ 0; }; manager: POINTER TO ARRAY [0..20) OF Image; Image: TYPE = RECORD[rect: Rect, command: PROC[r: Rect]]; mIndex: CARDINAL _ 0; mMax: CARDINAL = 20; <<******************************************************************>> <> <<******************************************************************>> SetBrush: PROC[tex: Texture, pnt: PaintingFunction] = INLINE { SetTexture[screen, tex]; SetPaint[screen, pnt]; }; SetClipper: PROC[w: CARDINAL] = { ll, ur: Vec; ll _ Map[screen, windows[w].context,[0, windows[w].bottom]]; ur _ Map[screen, windows[w].context,[650, windows[w].top - header]]; StartAreaPath[windows[w].context]; EnterPoint[windows[w].context,[ll.x, ll.y]]; EnterPoint[windows[w].context,[ll.x, ur.y]]; EnterPoint[windows[w].context,[ur.x, ur.y]]; EnterPoint[windows[w].context,[ur.x, ll.y]]; EnterPoint[windows[w].context,[ll.x, ll.y]]; SetClipArea[windows[w].context]; DestroyPath[windows[w].context]; }; Wait: PROC[t: CARDINAL] = { now: LONG CARDINAL _ MiscDefs.CurrentTime[]; WHILE MiscDefs.CurrentTime[] < now + t DO NULL; ENDLOOP; }; screen: PUBLIC DisplayContext; leftMargin: CARDINAL = 5; rightMargin: CARDINAL = 585; header: CARDINAL = 15; CR: CHARACTER = 015C; windows: ARRAY [0..10) OF Window; noWindows: CARDINAL _ 2; Window: TYPE = RECORD[context: DisplayContext, file: STRING, type: WType, command: POINTER TO CommandProcs, top, bottom: REAL]; WType: TYPE = {physical, graphical, logical, command, unknown}; commandProcs: CommandProcs; unknownProcs: CommandProcs _ [Flash, Flash, Flash, Flash, Flash, Flash,, Flash, Erase,,,,, 0]; Rect: TYPE = RECORD[ll, ur: Vec]; NullProc: PROC[r: Rect] = { }; Main[]; END.