<<>> <> <> <> <> <> <> <> <> <> <> DIRECTORY Convert USING [IntFromRope, RopeFromInt], Imager USING [black, Color, Font, MaskRectangleI, SetColor, SetFont, SetXYI, ShowChar, ShowRope, white], ImagerBackdoor USING [MakeStipple], Labels USING [Label], NumberLabels USING [], Rope USING [ROPE], VFonts USING [CharWidth, DefaultFont, Font, FontHeight, StringWidth], ViewerClasses USING [GetProc, PaintProc, SetProc, Viewer, ViewerClass, ViewerClassRec, ViewerRec], ViewerOps, MessageWindowBackdoor; LabelsImpl: CEDAR PROGRAM IMPORTS Convert, Imager, ImagerBackdoor, VFonts, ViewerOps, MessageWindowBackdoor EXPORTS Labels, NumberLabels = BEGIN OPEN ViewerClasses, Labels, Rope; bottomOffset: INTEGER = 3; -- for painting sideMargin: INTEGER = 3; LabelData: TYPE = REF LabelDataRec; LabelDataRec: TYPE = RECORD [ font: Imager.Font ¬ NIL, displayStyle: DisplayStyle ¬ blackOnWhite ]; DisplayStyle: TYPE = {blackOnWhite, whiteOnBlack, blackOnGrey}; Create: PUBLIC PROC [info: ViewerRec ¬ [], font: Imager.Font ¬ NIL, paint: BOOL ¬ TRUE] RETURNS [label: Label] = { data: LabelData ~ NEW[LabelDataRec ¬ [font: VFonts.DefaultFont[font]]]; IF info.ww=0 THEN info.ww ¬ VFonts.StringWidth[info.name, data.font]+sideMargin*2; IF info.wh=0 THEN info.wh ¬ VFonts.FontHeight[data.font]+bottomOffset; IF info.parent=NIL AND info.wx=0 AND info.wy=0 THEN { [info.wx, info.wy, info.ww, info.wh] ¬ MessageWindowBackdoor.AllocateStaticArea[info.ww]; info.column ¬ static; info.spare5 ¬ TRUE; -- mark as top row }; info.data ¬ data; label ¬ ViewerOps.CreateViewer[$Label, info, paint]; }; Destroy: PUBLIC PROC [label: Label] = {ViewerOps.DestroyViewer[label]}; Set: PUBLIC PROC [label: Label, value: Rope.ROPE, paint: BOOL ¬ TRUE] = {label.class.set[label, value, paint]}; SetDisplayStyle: PUBLIC PROC [label: Label, style: ATOM, paint: BOOL ¬ TRUE] = {label.class.set[label, style, paint, $DisplayStyle]}; white: Imager.Color ~ Imager.white; black: Imager.Color ~ Imager.black; myGrey: Imager.Color ~ ImagerBackdoor.MakeStipple[001010B]; BackgroundColor: PROC [displayStyle: DisplayStyle] RETURNS [Imager.Color] ~ { SELECT displayStyle FROM blackOnWhite => RETURN[white]; whiteOnBlack => RETURN[black]; blackOnGrey => RETURN[myGrey]; ENDCASE; RETURN[white]; }; LabelColor: PROC [displayStyle: DisplayStyle] RETURNS [Imager.Color] ~ { SELECT displayStyle FROM blackOnWhite => RETURN[black]; whiteOnBlack => RETURN[white]; blackOnGrey => RETURN[black]; ENDCASE; RETURN[black]; }; LabelPaint: PaintProc = { <> data: LabelData = NARROW[self.data]; borderFudge: INTEGER = IF self.border THEN 0 ELSE 1; background: Imager.Color; IF data = NIL THEN RETURN; background ¬ BackgroundColor[data.displayStyle]; IF clear AND background=white THEN NULL ELSE { Imager.SetColor[context, background]; Imager.MaskRectangleI[context, 1, 1, self.cw-2, self.ch-2]; }; IF self.name=NIL THEN RETURN; Imager.SetColor[context, LabelColor[data.displayStyle]]; Imager.SetXYI[context, sideMargin+borderFudge, bottomOffset+borderFudge]; Imager.SetFont[context, data.font]; Imager.ShowRope[context, self.name]; }; LabelGet: GetProc = { RETURN[self.name]; }; LabelSet: SetProc = { IF op=NIL THEN self.name ¬ NARROW[data] ELSE { myData: LabelData ¬ NARROW[self.data]; IF myData = NIL THEN RETURN; SELECT data FROM $BlackOnWhite => myData.displayStyle ¬ blackOnWhite; $WhiteOnBlack => myData.displayStyle ¬ whiteOnBlack; $BlackOnGrey => myData.displayStyle ¬ blackOnGrey; ENDCASE; }; IF finalise THEN ViewerOps.PaintViewer[self, all]; }; NumberLabel: TYPE = ViewerClasses.Viewer; NumberLabelData: TYPE = REF NumberLabelDataRec; NumberLabelDataRec: TYPE = RECORD [ font: VFonts.Font, displayStyle: DisplayStyle ¬ blackOnWhite, currentValue: INT ¬ 0, lastDisplayed: INT ¬ 0 ]; <> CreateNumber: PUBLIC PROC [info: ViewerClasses.ViewerRec ¬ [], chars: NAT ¬ 0, initialValue: INT ¬ 0, font: Imager.Font ¬ NIL, paint: BOOL ¬ TRUE] RETURNS [nl: NumberLabel ¬ NIL] = { data: NumberLabelData ¬ NEW [NumberLabelDataRec ¬ [font: VFonts.DefaultFont[font], currentValue: initialValue, lastDisplayed: initialValue + 1]]; IF info.parent=NIL THEN ERROR; IF info.ww=0 THEN info.ww ¬ chars*VFonts.CharWidth['0, data.font]+sideMargin+sideMargin; IF info.wh=0 THEN info.wh ¬ VFonts.FontHeight[data.font]+bottomOffset; info.data ¬ data; nl ¬ ViewerOps.CreateViewer[$NumberLabel, info, paint]; }; NumberLabelPaint: ViewerClasses.PaintProc = { <> <> data: NumberLabelData ¬ NARROW[self.data]; borderFudge: INTEGER = IF self.border THEN 0 ELSE 1; chars: ARRAY [0..11] OF CHAR; pos: NAT ¬ 0; card: CARD32; background: Imager.Color ~ BackgroundColor[data.displayStyle]; IF data = NIL THEN RETURN; IF clear AND background=white THEN NULL ELSE { Imager.SetColor[context, background]; Imager.MaskRectangleI[context, 1, 1, self.cw-2, self.ch-2]; whatChanged ¬ NIL; }; IF whatChanged = $Update AND data.currentValue = data.lastDisplayed THEN RETURN; data.lastDisplayed ¬ data.currentValue; Imager.SetColor[context, LabelColor[data.displayStyle]]; Imager.SetXYI[context, sideMargin+borderFudge, bottomOffset+borderFudge]; Imager.SetFont[context, data.font]; card ¬ LOOPHOLE[data.currentValue]; IF data.currentValue < 0 THEN { Imager.ShowChar[context, '-]; card ¬ - card }; <<>> WHILE card > 9 DO chars[pos] ¬ '0 + (card MOD 10); card ¬ card / 10; pos ¬ pos + 1; ENDLOOP; <<>> <> Imager.ShowChar[context, '0 + card]; <<>> <> WHILE pos > 0 DO pos ¬ pos - 1; Imager.ShowChar[context, chars[pos]]; ENDLOOP; }; NumberLabelGet: ViewerClasses.GetProc = { myData: NumberLabelData ¬ NARROW[self.data]; IF myData = NIL THEN RETURN [NIL]; IF op = NIL THEN RETURN[Convert.RopeFromInt[myData.currentValue]] ELSE RETURN [NEW[INT ¬ myData.currentValue]]; }; NumberLabelSet: ViewerClasses.SetProc = { myData: NumberLabelData ¬ NARROW[self.data]; IF myData = NIL THEN RETURN; WITH data SELECT FROM rope: ROPE => myData.currentValue ¬ Convert.IntFromRope[rope]; atom: ATOM => SELECT data FROM $BlackOnWhite => myData.displayStyle ¬ blackOnWhite; $WhiteOnBlack => myData.displayStyle ¬ whiteOnBlack; $BlackOnGrey => myData.displayStyle ¬ blackOnGrey; ENDCASE; refInt: REF INT => myData.currentValue ¬ refInt­; ENDCASE => RETURN; IF finalise THEN ViewerOps.PaintViewer[self, all]; }; NumberLabelUpdate: PUBLIC PROC [nl: NumberLabel, new: INT ¬ 0] = { myData: NumberLabelData ¬ NARROW[nl.data]; IF myData = NIL THEN RETURN; myData.currentValue ¬ new; IF new # myData.lastDisplayed THEN ViewerOps.PaintViewer[nl, all, FALSE, $Update]; }; NumberLabelQuery: PUBLIC PROC [nl: NumberLabel] RETURNS [current: INT ¬ 0] = { myData: NumberLabelData ¬ NARROW[nl.data]; IF myData = NIL THEN RETURN; RETURN [myData.currentValue]; }; <> <<>> labelClass: ViewerClasses.ViewerClass ¬ NEW[ViewerClasses.ViewerClassRec ¬ [ paint: LabelPaint, get: LabelGet, set: LabelSet ]]; numberLabelClass: ViewerClasses.ViewerClass ¬ NEW[ViewerClasses.ViewerClassRec ¬ [ paint: NumberLabelPaint, get: NumberLabelGet, set: NumberLabelSet ]]; ViewerOps.RegisterViewerClass[$Label, labelClass]; -- plug in to Viewers ViewerOps.RegisterViewerClass[$NumberLabel, numberLabelClass]; -- plug in to Viewers END.