<> <> <> <> <> <> DIRECTORY Buttons: TYPE USING[ ButtonProc ], DB, DBEnvironment, NoteEditor, Menus, NutButtons USING [NutButton], NutViewer USING [MakeButton, Error, Initialize, MakeBigTextBox, MakeRuler], Rope, VFonts, ViewerClasses: TYPE USING[ Viewer ], ViewerOps: TYPE USING[ AddProp, FetchProp, PaintHint, PaintViewer, CreateViewer, DestroyViewer, EstablishViewerPosition, SetNewVersion ], ViewerTools; NoteEditorImpl: PROGRAM IMPORTS DB, ViewerOps, Rope, VFonts, ViewerTools, NutViewer, Menus EXPORTS NoteEditor = BEGIN OPEN DB, Rope, ViewerClasses; xFudge: INT = 4; BoolPtr: TYPE = REF BOOL; DisplayNote: PUBLIC PROC[ entity: Entity, sibling: Viewer, segment: DB.Segment _ NIL, openHeight: NAT _ 0, openWidth: NAT _ 0, noEdits: BOOL _ FALSE ] RETURNS[ noteViewer: Viewer] = { <> <> NoteRel: Relation = DeclareRelation["note", IF entity = NIL THEN segment ELSE SegmentOf[entity], OldOnly]; NoteOfAttr: Attribute = DB.DeclareAttribute[ r: NoteRel, name: "of", type: AnyDomainType, version: OldOnly ]; NoteIsAttr: Attribute = DB.DeclareAttribute[ r: NoteRel, name: "is", type: RopeType, version: OldOnly]; noteRelship: Relship_ IF NoteRel=NIL OR entity = NIL THEN NIL ELSE NextRelship[RelationSubset[NoteRel, LIST[AttributeValue[NoteOfAttr, entity]]]]; text: ROPE_ IF noteRelship = NIL THEN NIL ELSE GetFS[ noteRelship, NoteIsAttr ]; tiogaText: ViewerTools.TiogaContents_ RopeToTioga[text]; noteButton: NutButtons.NutButton; textViewer: Viewer; IF noEdits AND Rope.Equal[text, ""] THEN RETURN[NIL]; noteButton _ NutViewer.MakeButton[ q: NIL, proc: NoteProc, sib: sibling, name: "Notes", newLine: TRUE, visible: TRUE]; IF openHeight = 0 THEN openHeight _ VFonts.FontHeight[]*(Rope.Length[text]/70+2); IF openWidth = 0 THEN openWidth _ 40*VFonts.CharWidth['A]; noteViewer _ ViewerOps.CreateViewer[flavor: $Container, info: [parent: sibling.parent, wx: noteButton.wx + noteButton.ww + xFudge, wy: noteButton.wy, ww: openWidth, wh: openHeight, border: TRUE, scrollable: FALSE] ]; textViewer _ NutViewer.Initialize[noteViewer]; textViewer _ NutViewer.MakeBigTextBox[sib: textViewer, contents: ""]; ViewerTools.SetTiogaContents[ viewer: textViewer, contents: tiogaText, paint: TRUE ]; ViewerTools.InhibitUserEdits[textViewer]; -- shouldn't edit text directly ViewerOps.AddProp[ noteButton, $edits, NEW[ BOOL _ (NOT noEdits)] ]; ViewerOps.AddProp[ noteButton, $note, noteRelship ] ; ViewerOps.AddProp[ noteButton, $Next, noteViewer]; ViewerOps.AddProp[ noteViewer, $Value, text ] ; ViewerOps.AddProp[ noteViewer, $TextViewer, textViewer]; ViewerOps.AddProp[ sibling.parent, $Notes, noteButton] }; NoteProc: Buttons.ButtonProc = TRUSTED BEGIN noteButton: NutButtons.NutButton = NARROW[parent]; noteViewer: Viewer = NARROW[ ViewerOps.FetchProp[ noteButton, $Next]]; edits: BoolPtr = NARROW[ ViewerOps.FetchProp[ noteButton, $edits ]]; SELECT mouseButton FROM Menus.MouseButton[red] => IF edits^ = TRUE THEN MakeNoteEditor[noteViewer] ELSE NutViewer.Error[noteButton.parent, "Cannot edit note"]; Menus.MouseButton[blue] => --grow box?? {}; ENDCASE; ViewerOps.PaintViewer[ noteButton.parent, client ]; END; MakeNoteEditor: PROC[noteViewer: Viewer] = BEGIN textViewer: Viewer = NARROW[ ViewerOps.FetchProp[ noteViewer, $TextViewer]]; text: ROPE = ViewerTools.GetContents[ textViewer ]; tiogaText: ViewerTools.TiogaContents_ RopeToTioga[text]; width: INT _ noteViewer.ww; height: INT _ noteViewer.wh; lastV: Viewer; ViewerOps.DestroyViewer[textViewer]; ViewerOps.EstablishViewerPosition[viewer: noteViewer, x: noteViewer.wx, y: noteViewer.wy, w: noteViewer.ww, h: 2*noteViewer.wh]; lastV _ NutViewer.Initialize[noteViewer]; lastV _ NutViewer.MakeButton[q: NIL, sib: lastV, proc: ValueGrow, name: "Grow"]; lastV _ NutViewer.MakeButton[q: NIL, sib: lastV, proc: ValueDone, name: "Done"]; lastV _ NutViewer.MakeButton[q: NIL, sib: lastV, proc: ValueReset, name: "Reset"]; lastV _ NutViewer.MakeRuler[lastV]; lastV _ NutViewer.MakeBigTextBox[sib: lastV, contents: "" ]; ViewerTools.SetTiogaContents[ viewer: lastV, contents: tiogaText, paint: TRUE ]; ViewerOps.AddProp[ noteViewer, $TextViewer, lastV]; ViewerTools.SetSelection[ lastV, NIL ]; END; SaveNote: PUBLIC PROC[newEntity: Entity, viewer: Viewer, update: BOOLEAN _ FALSE] = BEGIN noteViewer: Viewer = NARROW[ ViewerOps.FetchProp[viewer, $Next]]; text: ROPE = NARROW[ ViewerOps.FetchProp[noteViewer, $Value]]; NoteRel: Relation = DeclareRelation["note", SegmentOf[newEntity], NewOrOld]; NoteOfAttr: Attribute = DeclareAttribute[NoteRel, "of", AnyDomainType]; NoteIsAttr: Attribute = DeclareAttribute[NoteRel, "is", RopeType]; IF update THEN BEGIN noteRelship: Relship = V2E[ ViewerOps.FetchProp[ viewer, $note ] ]; IF noteRelship # NIL THEN { SetF[ noteRelship, NoteIsAttr, S2V[text] ]; RETURN }; END; ViewerOps.AddProp[ viewer, $note, CreateRelship[ r: NoteRel, init: LIST[ AttributeValue[attribute: NoteOfAttr, lo: newEntity ], AttributeValue[attribute: NoteIsAttr, lo: S2V[text]]]]]; END; TiogaToRope: PROC[tioga: ViewerTools.TiogaContents] RETURNS [rope: ROPE] = { <> IF tioga.formatting.Length[]=0 THEN -- No formatting RETURN[tioga.contents] ELSE -- Concatenate text and formatting with a null as separator RETURN[Rope.Cat[tioga.contents, "\000", tioga.formatting]]; }; RopeToTioga: PROC[rope: ROPE] RETURNS [tioga: ViewerTools.TiogaContents] = { <> pos: INT_ rope.Find["\000"]; IF pos=-1 THEN -- No formatting: fake a Tioga node tioga_ NEW[ViewerTools.TiogaContentsRec_ [rope, NIL]] ELSE -- Break into parts before and after null separator tioga_ NEW[ViewerTools.TiogaContentsRec_ [rope.Substr[0, pos], rope.Substr[pos+1]]]; }; ValueGrow: Buttons.ButtonProc = TRUSTED BEGIN noteViewer: ViewerClasses.Viewer _ (NARROW[parent, Viewer]).parent; shiftHeight: INT _ 2*noteViewer.wh; ViewerOps.EstablishViewerPosition[viewer: noteViewer, x: noteViewer.wx, y: noteViewer.wy, h: 2*noteViewer.wh, w: noteViewer.ww]; ViewerOps.PaintViewer[noteViewer, all]; END; ValueDone: Buttons.ButtonProc = TRUSTED BEGIN noteViewer: ViewerClasses.Viewer _ (NARROW[parent, Viewer]).parent; textViewer: ViewerClasses.Viewer _ NARROW[ ViewerOps.FetchProp[noteViewer, $TextViewer] ]; newValue: Rope.ROPE = ViewerTools.GetContents[textViewer]; topOfViewer: INT = textViewer.sibling.sibling.wy; newHeight: INT = VFonts.FontHeight[]*(Rope.Length[newValue]/70+2); newWidth: INT = 40*VFonts.CharWidth['A]; <<-- destroy buttons and move text up>> ViewerOps.EstablishViewerPosition[viewer: noteViewer, x: noteViewer.wx, y: noteViewer.wy, h: newHeight, w: newWidth]; ViewerOps.EstablishViewerPosition[viewer: textViewer, x: textViewer.wx, y: topOfViewer, h: newHeight, w: newWidth]; ViewerOps.DestroyViewer[textViewer.sibling.sibling.sibling.sibling]; --("grow") ViewerOps.DestroyViewer[textViewer.sibling.sibling.sibling]; --("done") ViewerOps.DestroyViewer[textViewer.sibling.sibling]; --("reset") ViewerOps.DestroyViewer[textViewer.sibling]; --(line) <<-- if new value then reset properties and flag editor as changed>> IF newValue # ViewerOps.FetchProp[noteViewer, $Value] THEN BEGIN noteButton: NutButtons.NutButton = noteViewer.sibling; ViewerOps.AddProp[noteButton, $Changes, noteViewer]; ViewerOps.AddProp[noteViewer, $Value, newValue]; ViewerOps.SetNewVersion[noteViewer.parent]; IF Menus.FindEntry[noteViewer.parent.menu, "Reset"] # NIL THEN --editor viewer Menus.SetGuarded[ Menus.FindEntry[noteViewer.parent.menu, "Reset"], TRUE ]; END; ViewerOps.PaintViewer[noteViewer.parent, client]; END; ValueReset: Buttons.ButtonProc = TRUSTED BEGIN noteViewer: ViewerClasses.Viewer _ (NARROW[parent, Viewer]).parent; textViewer: ViewerClasses.Viewer _ NARROW[ ViewerOps.FetchProp[noteViewer, $TextViewer]]; oldValue: Rope.ROPE _ NARROW[ViewerOps.FetchProp[noteViewer, $Value]]; tiogaText: ViewerTools.TiogaContents_ RopeToTioga[oldValue]; ViewerTools.SetTiogaContents[ viewer: textViewer, contents: tiogaText, paint: TRUE ]; END; END.