<> <> <> <<>> DIRECTORY Convert USING [RopeFromInt], IO USING [PutFR, int], DictationOps USING [DictationOps], MBQueue USING [CreateMenuEntry], Menus USING [Menu, AppendMenuEntry, CreateEntry, MenuProc, CreateMenu], MessageWindow USING [Blink, Append], Rope USING [ROPE, Concat], SoundList USING [SoundListFromIntervalSpecs, SoundChars], SourceMarkerTracking USING [RegisterViewer], TiogaOps USING [SaveSelA, SelectDocument, SetLooks, SetStyle, RestoreSelA, FirstChild, ViewerDoc], TiogaOpsDefs USING [Location], ViewerClasses USING [Viewer], ViewerEvents USING [EventRegistration, RegisterEventProc, UnRegisterEventProc, EventProc], ViewerLocks USING [CallUnderWriteLock], ViewerOps USING [CreateViewer, AddProp, FetchProp, SetMenu, PaintViewer], ViewerTools USING [TiogaContents, TiogaContentsRec, SetTiogaContents], VoiceAging USING [youngest, oldest, AgeAllViewers, ReColorViewer], VoiceInText USING [voiceButtonQueue, StoreVoiceAtSelection, CancelProc, DebugRope, DeleteSourceMarker, SaveRopeAtSourceMarker, thrushHandle], VoiceMarkers USING [AddCharMark, DeleteCharMarks, TextListFromRope, RopeFromTextList, RedrawTextMarkers], VoicePlayBack USING [PlayBackMenuProc, RemoveViewerReferences, RedrawViewer], VoiceRecord USING [AddVoiceProc, DictationMachine], VoiceRope USING [IntervalSpecs, Length, DescribeRope, VoiceRopeInterval], WindowManager USING [colorDisplayOn], VoiceViewers; <<>> VoiceViewersImpl: CEDAR MONITOR IMPORTS Convert, DictationOps, IO, MBQueue, Menus, MessageWindow, Rope, SoundList, SourceMarkerTracking, TiogaOps, ViewerEvents, ViewerLocks, ViewerOps, ViewerTools, VoiceAging, VoiceInText, VoiceMarkers, VoicePlayBack, VoiceRecord, VoiceRope, WindowManager EXPORTS VoiceViewers = BEGIN voiceViewerMenu: PUBLIC Menus.Menu; CreateVoiceViewerMenu: PROC = { voiceViewerMenu _ Menus.CreateMenu[]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "Add", VoiceRecord.AddVoiceProc]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "Play", VoicePlayBack.PlayBackMenuProc]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "STOP", VoiceInText.CancelProc]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "Save", SaveVoice]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "Store", StoreVoice]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "Redraw", RedrawViewer]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "Mark", VoiceMarkers.AddCharMark]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "DeleteMarks", VoiceMarkers.DeleteCharMarks]]; Menus.AppendMenuEntry[voiceViewerMenu, MBQueue.CreateMenuEntry[VoiceInText.voiceButtonQueue, "DictationMachine", VoiceRecord.DictationMachine]]; Menus.AppendMenuEntry[voiceViewerMenu, Menus.CreateEntry["DictationOps", DictationOps.DictationOps]]; }; voiceViewerInfoList: PUBLIC VoiceViewers.VoiceViewerInfo _ NIL; <<>> BuildVoiceViewer: PUBLIC PROC [voiceID: Rope.ROPE, textInVoice: Rope.ROPE, youngVoice: BOOLEAN] RETURNS [viewer: ViewerClasses.Viewer, viewerInfo: VoiceViewers.VoiceViewerInfo, viewerNumber: INT] = { viewerInfo _ InsertVoiceViewerInfo[]; viewer _ ViewerOps.CreateViewer[ flavor: $Text, info: [ name: Rope.Concat["Sound Viewer #", Convert.RopeFromInt[viewerInfo.viewerNumber]], column: IF WindowManager.colorDisplayOn THEN color ELSE left, iconic: FALSE << icon: create one of these>> ], paint: TRUE]; viewer.inhibitDestroy _ FALSE; <<>> viewerNumber _ viewerInfo.viewerNumber; ViewerOps.AddProp[viewer, $voiceViewerInfo, viewerInfo]; viewerInfo.viewer _ viewer; viewerInfo.color _ viewer.column = color; ViewerOps.SetMenu[viewer, voiceViewerMenu]; <<>> viewerInfo.destroyEvent _ ViewerEvents.RegisterEventProc[ proc: DestroyViewerEvent, event: destroy, filter: viewer, before: TRUE]; viewerInfo.changeColumnEvent _ ViewerEvents.RegisterEventProc[ proc: ChangeColumnEvent, event: changeColumn, filter: viewer, before: FALSE]; SetViewerContents[viewer, viewerInfo, voiceID, textInVoice, youngVoice]; MakeNotEdited[viewer] }; SetViewerContents: PUBLIC PROC [viewer: ViewerClasses.Viewer, viewerInfo: VoiceViewers.VoiceViewerInfo, voiceID: Rope.ROPE, textInVoice: Rope.ROPE, youngVoice: BOOLEAN] = { viewercontents: ViewerTools.TiogaContents _ NEW[ViewerTools.TiogaContentsRec _ []]; intervals: VoiceRope.IntervalSpecs; viewerInfo.soundList _ NIL; IF voiceID # NIL THEN { -- **** ought to check here that the rope actually exists viewerInfo.ropeInterval _ [voiceID, 0, VoiceRope.Length[VoiceInText.thrushHandle, NEW [VoiceRope.VoiceRopeInterval _ [voiceID, 0, 0]]]]; intervals _ VoiceRope.DescribeRope[VoiceInText.thrushHandle, NEW [VoiceRope.VoiceRopeInterval _ viewerInfo.ropeInterval]]; viewerInfo.soundList _ SoundList.SoundListFromIntervalSpecs[intervals, viewerInfo.ropeInterval.length]; [soundRope: viewercontents.contents, remnant: viewerInfo.remnant] _ SoundList.SoundChars[viewerInfo]; viewerInfo.textMarkList _ VoiceMarkers.TextListFromRope[textInVoice]; viewerInfo.ageList _ CONS [[0, IF youngVoice THEN VoiceAging.youngest-1 ELSE VoiceAging.oldest], NIL] } ELSE { viewercontents.contents _ " "; viewerInfo.ropeInterval _ [NIL, 0, 0]; }; ViewerTools.SetTiogaContents[viewer, viewercontents]; TiogaOps.SaveSelA[]; TiogaOps.SelectDocument[viewer]; TiogaOps.SetStyle["voiceProfile", root]; TiogaOps.SetLooks["v"]; TiogaOps.RestoreSelA[]; VoiceMarkers.RedrawTextMarkers[viewer, TiogaOps.FirstChild[TiogaOps.ViewerDoc[viewer]]]; IF voiceID # NIL AND viewerInfo.ageList.first.age = VoiceAging.youngest-1 THEN VoiceAging.AgeAllViewers[viewer] ELSE VoiceAging.ReColorViewer[viewer, viewerInfo]; <<>> <<**** the Plass-bug: shouldn't be necessary and he says he'll have a look at it>> IF viewerInfo.textMarkList # NIL THEN ViewerOps.PaintViewer[viewer: viewer, hint: client, clearClient: TRUE, whatChanged: NIL]; viewerInfo.editInProgress _ (voiceID = NIL) -- can do this because the viewer is created with editInProgress = TRUE, so nobody else can have grabbed the lock }; MakeNotEdited: PROC [viewer: ViewerClasses.Viewer] = { <> DoIt: PROC = { viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; viewerInfo.edited _ viewer.newVersion _ viewer.newFile _ FALSE; ViewerOps.PaintViewer[viewer, caption, FALSE]; }; ViewerLocks.CallUnderWriteLock[DoIt, viewer] }; SetVoiceViewerEditStatus: PUBLIC PROC [viewer: ViewerClasses.Viewer] = { <> DoIt: PROC = { viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; IF viewerInfo.edited # viewer.newVersion THEN { viewer.newVersion _ viewerInfo.edited; IF ~viewerInfo.edited THEN viewer.newFile _ FALSE; ViewerOps.PaintViewer[viewer, caption, FALSE]; } }; ViewerLocks.CallUnderWriteLock[DoIt, viewer] }; <<>> SetParentViewer: PUBLIC PROC [viewerInfo: VoiceViewers.VoiceViewerInfo, parentViewer: ViewerClasses.Viewer, positionInParent: TiogaOpsDefs.Location] = { viewerInfo.parentViewer _ parentViewer; viewerInfo.positionInParent _ positionInParent; SourceMarkerTracking.RegisterViewer[parentViewer] }; RemoveParentViewer: PUBLIC PROC [viewerNumber: INT] = { FOR info: VoiceViewers.VoiceViewerInfo _ voiceViewerInfoList, info.nextInfoRec WHILE info # NIL DO IF info.viewerNumber = viewerNumber THEN {info.parentViewer _ NIL; RETURN} ENDLOOP }; InsertVoiceViewerInfo: PROC RETURNS [newViewerInfo: VoiceViewers.VoiceViewerInfo] = { restOfList: VoiceViewers.VoiceViewerInfo _ voiceViewerInfoList; newViewerInfo _ NEW[VoiceViewers.VoiceViewerInfoRec]; IF voiceViewerInfoList = NIL THEN { newViewerInfo.viewerNumber _ 1; voiceViewerInfoList _ newViewerInfo; RETURN }; IF voiceViewerInfoList.viewerNumber > 1 THEN { newViewerInfo.viewerNumber _ 1; newViewerInfo.nextInfoRec _ voiceViewerInfoList; voiceViewerInfoList _ newViewerInfo; RETURN }; DO IF restOfList.nextInfoRec = NIL OR restOfList.nextInfoRec.viewerNumber > restOfList.viewerNumber + 1 THEN { newViewerInfo.viewerNumber _ restOfList.viewerNumber + 1; newViewerInfo.nextInfoRec _ restOfList.nextInfoRec; restOfList.nextInfoRec _ newViewerInfo; RETURN }; restOfList _ restOfList.nextInfoRec ENDLOOP }; StoreVoice: Menus.MenuProc = { <<**** locking against edits in this and the next one?>> viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[NARROW[parent], $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; oldParentViewer: ViewerClasses.Viewer _ viewerInfo.parentViewer; oldPosition: TiogaOpsDefs.Location _ viewerInfo.positionInParent; IF VoiceInText.StoreVoiceAtSelection[viewerInfo] THEN { MakeNotEdited[NARROW[parent]]; IF oldParentViewer # NIL THEN VoiceInText.DeleteSourceMarker[oldParentViewer, oldPosition, viewerInfo.viewerNumber] } }; SaveVoice: Menus.MenuProc = { viewer: ViewerClasses.Viewer _ NARROW[parent]; viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; IF ~viewerInfo.edited THEN { MessageWindow.Append["voice viewer is not edited", TRUE]; RETURN }; IF viewerInfo.parentViewer = NIL THEN { MessageWindow.Append["voice viewer has no parent text viewer", TRUE]; MessageWindow.Blink[]; RETURN }; IF ~VoiceInText.SaveRopeAtSourceMarker[viewerInfo.parentViewer, viewerInfo.positionInParent, viewerInfo.viewerNumber, viewerInfo.ropeInterval.ropeID, VoiceMarkers.RopeFromTextList[viewerInfo.textMarkList]] THEN { MessageWindow.Append["unable to find source marker for voice window: voice not saved", TRUE]; MessageWindow.Blink[]; RETURN }; MakeNotEdited[viewer] }; RemoveVoiceViewerInfo: PROC [viewerInfo: VoiceViewers.VoiceViewerInfo] = { IF voiceViewerInfoList = NIL THEN ERROR; IF voiceViewerInfoList = viewerInfo THEN voiceViewerInfoList _ viewerInfo.nextInfoRec ELSE { ptrToCurrInfo: VoiceViewers.VoiceViewerInfo _ voiceViewerInfoList; currInfo: VoiceViewers.VoiceViewerInfo _ voiceViewerInfoList.nextInfoRec; DO IF currInfo = NIL THEN ERROR; IF currInfo = viewerInfo THEN { ptrToCurrInfo.nextInfoRec _ viewerInfo.nextInfoRec; RETURN }; ptrToCurrInfo _ currInfo; currInfo _ currInfo.nextInfoRec ENDLOOP } }; DestroyViewerEvent: ViewerEvents.EventProc = { RETURN [~DestroyVoiceInfo[viewer]] }; DestroyVoiceInfo: PROC [viewer: ViewerClasses.Viewer] RETURNS [didIt: BOOLEAN _ TRUE] = { viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; IF ~VoicePlayBack.RemoveViewerReferences[viewer] THEN { MessageWindow.Append["Wait until voice cue disappears before destroying viewer", TRUE]; MessageWindow.Blink[]; RETURN [FALSE] }; <> IF viewerInfo.parentViewer = NIL THEN VoiceInText.DebugRope[IO.PutFR["Voice viewer %d had no parent\n", IO.int[viewerInfo.viewerNumber]]] ELSE VoiceInText.DeleteSourceMarker[viewerInfo.parentViewer, viewerInfo.positionInParent, viewerInfo.viewerNumber]; RemoveVoiceViewerInfo[viewerInfo]; ViewerEvents.UnRegisterEventProc[viewerInfo.destroyEvent, destroy]; ViewerEvents.UnRegisterEventProc[viewerInfo.changeColumnEvent, changeColumn]; }; RedrawViewer: Menus.MenuProc = { viewer: ViewerClasses.Viewer _ NARROW[parent]; viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; IF GetVoiceLock[viewerInfo] THEN { trueContents: Rope.ROPE _ SoundList.SoundChars[viewerInfo].soundRope; [] _ VoicePlayBack.RedrawViewer[viewer, trueContents, 0, 0, 0, viewerInfo.remnant, FALSE, unAltered]; SetVoiceViewerEditStatus[viewer]; viewerInfo.editInProgress _ FALSE } }; ChangeColumnEvent: ViewerEvents.EventProc = { viewerInfo: VoiceViewers.VoiceViewerInfo _ NARROW[ViewerOps.FetchProp[viewer, $voiceViewerInfo], VoiceViewers.VoiceViewerInfo]; IF (viewer.column = color) # viewerInfo.color THEN { viewerInfo.color _ viewer.column = color; IF GetVoiceLock[viewerInfo] THEN { trueContents: Rope.ROPE _ SoundList.SoundChars[viewerInfo].soundRope; [] _ VoicePlayBack.RedrawViewer[viewer, trueContents, 0, 0, 0, viewerInfo.remnant, FALSE, unAltered]; SetVoiceViewerEditStatus[viewer]; viewerInfo.editInProgress _ FALSE } ELSE { MessageWindow.Append["Cannot repaint viewer during edit: click REDRAW to change window between color and monchrome if the wrong state persists", TRUE]; MessageWindow.Blink[] } } }; GetVoiceLock: PUBLIC ENTRY PROC [info: VoiceViewers.VoiceViewerInfo] RETURNS [gotIt: BOOLEAN] = { gotIt _ ~ info.editInProgress; IF info.editInProgress THEN MessageWindow.Append["Try again when the viewer's contents are stable", TRUE] ELSE info.editInProgress _ TRUE; }; CreateVoiceViewerMenu[]; END.