DIRECTORY Buttons, Graphics USING [black, Color, Context, DrawBox, DrawRope, GetBounds, PaintMode, SetColor, SetCP, SetPaintMode, SetStipple, white], GraphicsOps USING [DrawTexturedBox, Texture], InputFocus USING [CaptureButtons, ReleaseButtons], Menus USING [MouseButton], MenusPrivate USING [Document, greyGuard], MessageWindow USING [messageWindow], Process USING [Detach, InitializeMonitor, Milliseconds, MsecToTicks, priorityNormal, SetPriority, SetTimeout], Rope USING [ROPE], SafeStorage USING [NewZone], TIPUser USING [InstantiateNewTIPTable, TIPScreenCoords], VFonts USING [defaultFont, Font, FontHeight, GraphicsFont, StringWidth], ViewerClasses, ViewerOps USING [CreateViewer, MouseInViewer, MoveViewer, PaintViewer, RegisterViewerClass], ViewerSpecs; ButtonsImpl: CEDAR MONITOR LOCKS data USING data: ButtonData IMPORTS Graphics, GraphicsOps, InputFocus, MenusPrivate, MessageWindow, Process, SafeStorage, TIPUser, VFonts, ViewerOps EXPORTS Buttons SHARES MessageWindow, ViewerOps = BEGIN OPEN ViewerClasses, Buttons; ButtonData: TYPE = REF ButtonDataRec; ButtonDataRec: TYPE = MONITORED RECORD [ proc: ButtonProc, font: VFonts.Font, clientData: REF ANY, documentation: REF ANY, greyCount: INTEGER, displayStyle: DisplayStyle, inverted: BOOL, fork: BOOL, guarded: BOOL, state: GuardState ]; bZ: ZONE _ SafeStorage.NewZone[quantized]; armingTime: Process.Milliseconds _ 100; -- cover removal time. armedTime: Process.Milliseconds _ 5000; -- unguarded interval. GuardState: TYPE = { guarded, arming, armed }; DisplayStyle: TYPE = {blackOnWhite, whiteOnBlack, blackOnGrey} ; bottomOffset: INTEGER = 3; -- for painting leftOffset: INTEGER = 3; defaultButtonY: INTEGER = ViewerSpecs.screenH-ViewerSpecs.messageWindowHeight; defaultButtonH: INTEGER = ViewerSpecs.messageWindowHeight; Create: PUBLIC PROC [info: ViewerRec _ [], proc: ButtonProc, clientData: REF ANY _ NIL, fork: BOOL _ FALSE, font: VFonts.Font _ VFonts.defaultFont, documentation: REF ANY _ NIL, guarded: BOOL _ FALSE, paint: BOOL _ TRUE] RETURNS [button: Button] = BEGIN data: ButtonData _ bZ.NEW[ButtonDataRec _ [, proc, font, clientData, documentation, 0, blackOnWhite, FALSE, fork, guarded, IF guarded THEN guarded ELSE armed]]; TRUSTED {Process.InitializeMonitor[@data.LOCK]}; IF info.ww=0 THEN info.ww _ VFonts.StringWidth[info.name, font]+leftOffset+leftOffset; IF info.wh=0 THEN info.wh _ VFonts.FontHeight[font]+bottomOffset; IF info.parent=NIL AND info.wx=0 AND info.wy=0 THEN BEGIN OPEN MessageWindow.messageWindow; ViewerOps.MoveViewer[MessageWindow.messageWindow, wx, wy, ww-info.ww, wh, FALSE]; info.wx _ wx + ww; info.wy _ defaultButtonY; info.wh _ defaultButtonH; info.column _ static; END; info.data _ data; IF documentation#NIL THEN WITH documentation SELECT FROM doc: REF TEXT => NULL; doc: REF ButtonProc => NULL; doc: Rope.ROPE => NULL; ENDCASE => ERROR; -- not valid documentation RETURN[ViewerOps.CreateViewer[$Button, info, paint]]; END; guardedTexture: GraphicsOps.Texture = [ 125252B,052525B,125252B,052525B,125252B,052525B,125252B,052525B, 052525B,125252B,052525B,125252B,052525B,125252B,052525B,125252B ]; ButtonsPaint: PRIVATE PaintProc = BEGIN OPEN Graphics; data: ButtonData _ NARROW[self.data]; myGrey: CARDINAL = 001010B; IF data = NIL THEN RETURN; IF ISTYPE[whatChanged, PaintRectangle] THEN whatChanged _ NIL; IF whatChanged=NIL THEN BEGIN -- paint in label (derived from name) borderFudge: INTEGER = IF self.border THEN 0 ELSE 1; IF ~clear OR data.greyCount # 0 OR data.displayStyle=blackOnGrey THEN { SetStipple[context, myGrey]; DrawBox[context, [1, 1, self.cw-1, self.ch-1]]} ELSE IF ~clear OR data.displayStyle=whiteOnBlack THEN { SetColor[context, black]; DrawBox[context, [1, 1, self.cw-1, self.ch-1]]}; SetColor[context, SELECT data.displayStyle FROM whiteOnBlack => white, ENDCASE => black]; SetCP[context, leftOffset+borderFudge, bottomOffset+borderFudge]; DrawRope[self: context, rope: self.name, font: VFonts.GraphicsFont[data.font]]; IF data.guarded AND data.state#armed THEN BEGIN IF MenusPrivate.greyGuard THEN BEGIN SetCP[context, leftOffset+borderFudge+1, bottomOffset+borderFudge]; -- fake bold DrawRope[self: context, rope: self.name, font: VFonts.GraphicsFont[data.font]]; SetColor[context, SELECT data.displayStyle FROM whiteOnBlack => black, ENDCASE => white]; [] _ SetPaintMode[context, transparent]; GraphicsOps.DrawTexturedBox[context, [0, 0, self.cw, self.ch], guardedTexture]; END ELSE BEGIN by: INTEGER ~ bottomOffset+borderFudge+2; DrawBox[context, [0, by, self.cw, by+1]]; END; END; END; IF whatChanged=$Invert OR data.inverted THEN BEGIN -- invert to indicate highlighting [] _ SetPaintMode[context, invert]; DrawBox[context, GetBounds[context]]; IF whatChanged=$Invert THEN data.inverted _ ~data.inverted; END; END; ButtonsNotify: NotifyProc = BEGIN data: ButtonData _ NARROW[self.data]; EntryButtonsNotify[self, input, data]; END; EntryButtonsNotify: ENTRY PROC [self: Viewer, input: LIST OF REF ANY, data: ButtonData] = BEGIN ENABLE UNWIND => InputFocus.ReleaseButtons[]; button: Menus.MouseButton _ red; shift, control: BOOL _ FALSE; mouse: TIPUser.TIPScreenCoords; IF data = NIL THEN RETURN; FOR list: LIST OF REF ANY _ input, list.rest UNTIL list = NIL DO WITH list.first SELECT FROM x: ATOM => SELECT x FROM $Blue => button _ blue; $Control => control _ TRUE; $Documentation => IF data.documentation#NIL THEN MenusPrivate.Document[data.documentation, self, data.clientData, button, shift, control]; $Hit => IF data.inverted THEN SELECT data.state FROM guarded => { data.state_arming; ViewerOps.PaintViewer[self, client, FALSE, $Invert]; InputFocus.ReleaseButtons[]; TRUSTED {Process.Detach[FORK ArmButtonProc[data, self]]}; IF data.documentation#NIL THEN -- post documentation MenusPrivate.Document[data.documentation, self, data.clientData, button, shift, control]; }; arming=> NULL; -- no action armed=> { InputFocus.ReleaseButtons[]; ViewerOps.PaintViewer[self, client, FALSE, $Invert]; IF data.guarded THEN BEGIN data.state_guarded; ViewerOps.PaintViewer[self, client]; END; IF data.fork THEN TRUSTED {Process.Detach[FORK ButtonPusher[self, data, data.proc, data.clientData, button, shift, control, TRUE]]} ELSE ButtonPusher[self, data, data.proc, data.clientData, button, shift, control, FALSE]; }; ENDCASE; $Mark => IF ~data.inverted THEN BEGIN InputFocus.CaptureButtons[ButtonsNotify, buttonsClass.tipTable, self]; ViewerOps.PaintViewer[self, client, FALSE, $Invert]; END ELSE BEGIN v: Viewer; c: BOOL; [v, c] _ ViewerOps.MouseInViewer[mouse]; IF v=self AND c THEN RETURN; ViewerOps.PaintViewer[self, client, FALSE, $Invert]; InputFocus.ReleaseButtons[]; END; $Red => button _ red; $Shift => shift _ TRUE; $Yellow => button _ yellow; ENDCASE => NULL; z: TIPUser.TIPScreenCoords => mouse _ z; ENDCASE => ERROR; ENDLOOP; END; ArmButtonProc: ENTRY PROC [data: ButtonData, button: Buttons.Button] = { IF data = NIL THEN RETURN; ButtonWait[data, armingTime]; IF data.state = arming THEN { data.state_armed; ViewerOps.PaintViewer[button, client]; ButtonWait[data, armedTime]; }; IF data.state#guarded THEN BEGIN data.state_guarded; ViewerOps.PaintViewer[button, client]; END; }; ButtonWait: INTERNAL PROCEDURE[data: ButtonData, ticks: Process.Milliseconds] = TRUSTED { buttonWaitCondition: CONDITION; Process.SetTimeout[LONG[@buttonWaitCondition], Process.MsecToTicks[ticks]]; WAIT buttonWaitCondition; }; ButtonPusher: PROC [button: Button, myData: ButtonData, proc: ButtonProc, data: REF ANY, mouseButton: Menus.MouseButton, shift, control, normalPriority: BOOL] = BEGIN IF myData = NIL THEN RETURN; myData.greyCount _ myData.greyCount + 1; IF myData.displayStyle#blackOnGrey THEN ViewerOps.PaintViewer[button, client]; IF normalPriority THEN TRUSTED {Process.SetPriority[Process.priorityNormal]}; proc[button, data, mouseButton, shift, control ! ABORTED => CONTINUE]; myData.greyCount _ MAX[myData.greyCount - 1, 0]; IF myData.displayStyle#blackOnGrey THEN ViewerOps.PaintViewer[button, client]; END; ButtonGet: PRIVATE GetProc = BEGIN RETURN[self.name]; END; ButtonsSet: PRIVATE SetProc = BEGIN IF op=NIL THEN self.name _ NARROW[data] ELSE BEGIN myData: ButtonData _ NARROW[self.data]; IF myData = NIL THEN RETURN; SELECT data FROM $BlackOnWhite => { myData.greyCount _ MAX[myData.greyCount - 1, 0]; IF myData.greyCount <= 0 THEN myData.displayStyle _ blackOnWhite}; $WhiteOnBlack => { myData.greyCount _ MAX[myData.greyCount - 1, 0]; IF myData.greyCount <= 0 THEN myData.displayStyle _ whiteOnBlack}; $BlackOnGrey, $BlackOnGray => { myData.greyCount _ myData.greyCount + 1; myData.displayStyle _ blackOnWhite}; ENDCASE => ERROR; END; IF finalise THEN ViewerOps.PaintViewer[self, all]; END; buttonsClass: ViewerClasses.ViewerClass _ NEW[ViewerClasses.ViewerClassRec _ [ paint: ButtonsPaint, get: ButtonGet, set: ButtonsSet, notify: ButtonsNotify, tipTable: TIPUser.InstantiateNewTIPTable["/Indigo/CedarViewers/Viewers/Button.tip"], cursor: bullseye ]]; ViewerOps.RegisterViewerClass[$Button, buttonsClass]; -- plug in to Viewers END. ΞButtonsImpl.mesa; Edited by McGregor on October 21, 1982 9:46 am Last Edited by: Maxwell, June 7, 1983 2:25 pm borderFudge is so buttons line up whether they have borders or not assert: state=arming Κ – "Mesa" style˜JšΟc@™@J™-J˜šΟk ˜ J˜šœ žœ+˜9J˜H—Jšœ žœ˜-Jšœ žœ"˜2Jšœžœ˜Jšœ žœ˜)Jšœžœ˜$šœžœG˜TJ˜—Jšœžœžœ˜Jšœ žœ ˜Jšœžœ+˜8Jšœžœ<˜HJ˜šœ žœ7˜FJ˜—J˜ J˜—Jšœ ž œžœžœ˜Jšœ(˜>J˜Jšœ žœ˜.J˜Jšœžœ.˜@J˜Jšœžœ˜*Jšœ žœ˜J˜Jšœžœ7˜NJšœžœ#˜:J˜š Οnœžœžœ6žœžœžœ˜WJš œžœžœ9žœžœžœ˜YJš œ žœžœ žœžœžœž˜Kšœžœ=˜VJš œžœžœ žœ žœ ˜I—Jšžœ"žœ˜0Jšžœ žœE˜VJšžœ žœ0˜Aš žœ žœžœ žœ ž˜3Jšžœžœ˜'˜IJšžœ˜—J˜J˜J˜J˜Jšžœ˜—J˜š žœžœžœžœžœž˜8Jšœžœžœžœ˜Jšœžœžœ˜Jšœ žœžœ˜Jšžœžœ˜0—Jšžœ/˜5Jšžœ˜J˜—˜'J˜@J˜?J˜J˜—šœžœ žœžœ ˜6Jšœžœ ˜%Jšœžœ ˜Jšžœžœžœžœ˜Jšžœžœžœžœ˜>š žœ žœžœžœ%˜CJšB™BJš œ žœžœ žœžœ˜4šžœžœžœžœ˜GJšœ˜Jšœ/˜/—šžœžœžœ žœ˜7Jšœ˜Jšœ0˜0—šœžœž˜/J˜Jšžœ ˜—J˜AJ˜Ošžœžœžœž˜/šžœžœž˜$JšœD ˜PJ˜Ošœžœž˜/J˜Jšžœ ˜—J˜(J˜OJšž˜—šžœž˜ Jšœžœ˜)J˜)Jšžœ˜—Jšžœ˜—Jšžœ˜J˜—š žœžœžœžœ"˜UJ˜#J˜%Jšžœžœ ˜;Jšžœ˜—Jšžœ˜J˜—šœž˜!Jšœžœ ˜%J˜&Jšžœ˜J˜—šŸœžœžœžœžœžœžœ˜YJšž˜Jšžœžœ ˜-J˜ Jšœžœžœ˜J˜Jšžœžœžœžœ˜šžœžœžœžœžœžœžœž˜@šžœ žœž˜šœžœžœž˜J˜Jšœžœ˜šœžœžœž˜0J˜@J˜—šœžœžœžœ ž˜4˜ J˜Jšœ$žœ ˜4J˜Jšžœžœ˜9šžœžœžœ˜4J˜@J˜—J˜—Jšœ žœ ˜˜ J˜Jšœ$žœ ˜4šžœžœž˜J˜J˜$Jšžœ˜—šžœ žœžœžœ˜AJšœ:žœ˜A—šžœ5˜9Jšœžœ˜"—Jšžœ˜——šœ žœžœž˜%J˜FJšœ$žœ ˜4Jšž˜šžœž˜ J˜ Jšœžœ˜J˜(Jšžœžœžœžœ˜Jšœ$žœ ˜4J˜Jšžœ˜——J˜Jšœžœ˜J˜Jšžœžœ˜—J˜(Jšžœžœ˜—Jšžœ˜—Jšžœ˜J˜—šŸ œžœžœ/˜HJš™Jšžœžœžœžœ˜J˜šžœžœ˜J˜J˜&J˜J˜—šžœžœž˜ J˜J˜&Jšžœ˜J˜—šŸ œžœž œ2žœ˜YJšœž œ˜Jšœžœ4˜KJšžœ˜J˜——šŸ œžœ>žœžœ˜XJšœ@žœž˜MJšžœ žœžœžœ˜Jšœ(˜(Jšžœ!žœ'˜NJšžœžœžœ/˜MJšœ1žœžœ˜FJšœžœ˜0Jšžœ!žœ'˜NJšžœ˜J˜—šœ žœ ž˜"Jšžœ ˜Jšžœ˜J˜—šœ žœ ž˜#Jšžœžœžœ žœ˜'šžœž˜ Jšœžœ ˜'Jšžœ žœžœžœ˜šžœž˜˜Jšœžœ˜0Jšžœžœ%˜B—˜Jšœžœ˜0Jšžœžœ%˜B—˜J˜(Jšœ$˜$—Jšžœžœ˜—Jšžœ˜—Jšžœ žœ"˜2Jšžœ˜J˜—šœ*žœ!˜NJ˜J˜J˜J˜J˜TJ˜J˜J˜—Jšœ6˜KJ˜Jšžœ˜J˜J˜—…—#B..