<<>> <> <> <> <> <> <<>> <> DIRECTORY BiScrollers, Cursors, Geom2D, Imager, ImagerBackdoor, ImagerTransformation, InputFocus, Menus, Real, TIPUser, ViewerClasses, ViewerOps; BiScrollersButtonned: CEDAR MONITOR IMPORTS BiScrollers, Cursors, Geom2D, Imager, ImagerBackdoor, ImagerTransformation, InputFocus, Menus, Real, TIPUser, ViewerOps SHARES ViewerOps = BEGIN OPEN BiScrollers; Number: TYPE = Geom2D.Number; ViewerClass: TYPE = ViewerClasses.ViewerClass; Axis: TYPE = Geom2D.Axis; Vec: TYPE = Geom2D.Vec; Buttonned: TYPE = REF ButtonnedRep; ButtonnedRep: TYPE = RECORD [ class: ButtonnedClass, clientData: REF ANY, container, client: Viewer ¬ NIL, children: Child ¬ NIL, t, u: Transform ¬ Geom2D.id, tp, up: Transform ¬ Geom2D.id, h, v: Viewer ¬ NIL, --horizontal and vertical BiScrollBars-- cw, ch: INTEGER ¬ 0, --of container, last time we looked-- clientWantsActive: BOOL ¬ FALSE ]; ButtonnedClass: TYPE = REF ButtonnedClassRep; ButtonnedClassRep: TYPE = RECORD [ clientClass: ViewerClass, menu: Menus.Menu]; Child: TYPE = REF ChildObject; ChildObject: TYPE = RECORD [next: Child, where: Vec, it: Viewer]; Range: TYPE = REF RangeObject; RangeObject: TYPE = RECORD [min, max: Number]; BiScrollBar: TYPE = REF BiScrollBarObject; BiScrollBarObject: TYPE = RECORD [ viewer: Viewer ¬ NIL, parent: BiScroller, axis: Axis, state: State ¬ Idle, cursors: ARRAY State OF Cursors.CursorType]; State: TYPE = {Idle, Increase, Decrease, Random}; awake: Viewer ¬ NIL; --who has CapturedButtons indent: INTEGER ¬ 11; --width of BiScrollBars reset: Cursors.CursorType ¬ bullseye; grayl: Imager.Color ¬ ImagerBackdoor.MakeStipple[8421H]; graym: Imager.Color ¬ ImagerBackdoor.MakeStipple[5A5AH]; grayh: Imager.Color ¬ ImagerBackdoor.MakeStipple[1248H]; buttonnedStyle: BiScrollerStyle ¬ NEW [BiScrollerStyleRep ¬ [ NewBiScrollerClass: NewBiScrollerClass, CreateBiScroller: CreateBiScroller, Destroy: Destroy, GetTransforms: GetTransforms, ChangeTransform: ChangeTransform, AddChild: AddChild, DeleteChild: DeleteChild, SetButtonsCapturedness: SetButtonsCapturedness, ViewportOf: ViewportOf, QuaViewer: QuaViewer, ClientDataOf: ClientDataOf ]]; containerFlavor: ATOM ¬ $ButtonnedContainer; NewBiScrollerClass: PROC [cc: ClassCommon] RETURNS [bsc: BiScrollerClass] = BEGIN vc: ViewerClass; IF cc.vanilla = NIL THEN cc.vanilla ¬ GenID; IF cc.bsUserAction = NIL THEN cc.bsUserAction ¬ DoBSUserAction; IF cc.caption#NIL THEN ERROR--not implemented yet--; vc ¬ NEW [ViewerClasses.ViewerClassRec ¬ [ flavor: cc.flavor, notify: NotifyBiScroller, paint: PaintClient, modify: cc.modify, destroy: cc.destroy, copy: cc.copy, set: cc.set, get: cc.get, save: cc.save, adjust: cc.adjust, tipTable: cc.tipTable, icon: cc.icon, cursor: cc.cursor]]; ViewerOps.RegisterViewerClass[flavor: vc.flavor, class: vc]; bsc ¬ NEW [BiScrollerClassRep ¬ [ style: buttonnedStyle, common: cc, rep: NEW [ButtonnedClassRep ¬ [ clientClass: vc, menu: cc.menu ]] ]]; END; CreateBiScroller: PROC [class: BiScrollerClass, info: ViewerClasses.ViewerRec ¬ [], paint: BOOLEAN ¬ TRUE] RETURNS [new: BiScroller] = BEGIN bdc: ButtonnedClass ¬ NARROW[class.rep]; paintFirst: BOOL = paint AND info.iconic; bd: Buttonned ¬ NEW[ButtonnedRep ¬ [class: bdc, clientData: info.data, t: Geom2D.id]]; clientInfo: ViewerClasses.ViewerRec; info.data ¬ new ¬ NEW [BiScrollerRep ¬ [ style: class.style, class: class, rep: bd]]; bd.container ¬ ViewerOps.CreateViewer[flavor: containerFlavor, info: info, paint: paintFirst]; bd.h ¬ ViewerOps.CreateViewer[flavor: $BiScrollBarX, info: [ name: "X scrolling", parent: bd.container, wx: indent, wy: 0, ww: bd.container.cw-indent, wh: indent, data: NEW[BiScrollBarObject ¬ [parent: new, axis: X, cursors: [ Increase: scrollLeft, Decrease: scrollRight, Random: pointUp, Idle: scrollLeftRight]]], scrollable: FALSE, border: FALSE], paint: FALSE]; bd.v ¬ ViewerOps.CreateViewer[flavor: $BiScrollBarY, info: [ name: "Y scrolling", parent: bd.container, wx: 0, wy: indent, ww: indent, wh: bd.container.ch-indent, data: NEW[BiScrollBarObject ¬ [parent: new, axis: Y, cursors: [ Increase: scrollUp, Decrease: scrollDown, Random: pointRight, Idle: scrollUpDown]]], scrollable: FALSE, border: FALSE], paint: FALSE]; clientInfo ¬ info; clientInfo.parent ¬ bd.container; clientInfo.border ¬ FALSE; clientInfo.menu ¬ NIL; bd.client ¬ ViewerOps.CreateViewer[flavor: bdc.clientClass.flavor, info: clientInfo, paint: FALSE]; [] ¬ ComputeClientBounds[new, bd, FALSE]; ChangeTransform[new, class.common.vanilla[new], ignore, FALSE]; SetBS[bd.container, new]; IF class.common.init # NIL THEN class.common.init[bd.client]; IF paintFirst THEN NULL ELSE IF bd.container.parent=NIL THEN ViewerOps.ComputeColumn[column: ViewerOps.ViewerColumn[bd.container], paint: paint] ELSE IF paint THEN ViewerOps.PaintViewer[bd.container, all]; END; Destroy: PROC [bs: BiScroller] RETURNS [BiScroller] = BEGIN bd: Buttonned ¬ NARROW[bs.rep]; ViewerOps.DestroyViewer[bd.container]; bd.container ¬ NIL; RETURN [NIL]; END; AddChild: PROC [to: BiScroller, what: Viewer, x, y: REAL ¬ 0, useTheseCoords: BOOLEAN ¬ FALSE, paint: BOOLEAN ¬ TRUE] = BEGIN bd: Buttonned ¬ NARROW[to.rep]; my: Vec; c: Child ¬ NEW [ChildObject ¬ [ next: bd.children, it: what, where: IF useTheseCoords THEN [x, y] ELSE [what.wx, what.wy] ]]; bd.children ¬ c; my ¬ bd.t.Transform[c.where]; ViewerOps.MoveViewer[viewer: what, x: RI[my.x], y: RI[my.y], w: what.ww, h: what.wh, paint: paint]; END; DeleteChild: PROC [of: BiScroller, who: Viewer] = BEGIN bd: Buttonned ¬ NARROW[of.rep]; Filter: PROC [c: Child] RETURNS [Child] = {IF c = NIL THEN RETURN [NIL]; IF c.it = who THEN RETURN [c.next]; c.next ¬ Filter[c.next]; RETURN [c]}; bd.children ¬ Filter[bd.children]; END; QuaViewer: PROC [bs: BiScroller, inner: BOOL ¬ FALSE] RETURNS [v: Viewer] = {bd: Buttonned ¬ NARROW[bs.rep]; v ¬ IF inner THEN bd.client ELSE bd.container}; ClientDataOf: PROC [bs: BiScroller] RETURNS [ra: REF ANY] = {bd: Buttonned ¬ NARROW[bs.rep]; ra ¬ bd.clientData}; ViewportOf: PROC [bs: BiScroller] RETURNS [VecList] = BEGIN bd: Buttonned ¬ NARROW[bs.rep]; RETURN [Geom2D.MapVecs[bd.u, LIST[ [0, 0], [bd.client.cw, 0], [bd.client.cw, bd.client.ch], [0, bd.client.ch]]]]; END; ComputeClientBounds: PROC [bs: BiScroller, bd: Buttonned, adjust: BOOL] RETURNS [changed: BOOL] = { <> IF changed ¬ (bd.cw # bd.container.cw OR bd.ch # bd.container.ch) THEN { client: Vec --the point that stays fixed, in client coords--; IF adjust THEN { client ¬ bd.u.Transform[[ bs.class.common.preserve[X]*bd.client.cw, bs.class.common.preserve[Y]*bd.client.ch]]; }; bd.cw ¬ bd.container.cw; bd.ch ¬ bd.container.ch; SetViewerPosition[bd.h, indent, 0, bd.cw-indent, indent]; SetViewerPosition[bd.v, 0, indent, indent, bd.ch-indent]; SetViewerPosition[bd.client, indent, indent, bd.cw-indent, bd.ch-indent]; IF adjust THEN { Align[ bs: bs, client: [coord[client.x, client.y]], viewer: [fraction[ bs.class.common.preserve[X], bs.class.common.preserve[Y]]], paint: FALSE]; }; }; }; Awoken: ENTRY PROC [v: Viewer] RETURNS [BOOL] ~ {RETURN [awake=v]}; Awaken: PROC [v: Viewer] RETURNS [tookit, havit: BOOL ¬ FALSE] ~ { Inner: ENTRY PROC ~ {IF (tookit ¬ awake = NIL) THEN awake ¬ v; havit ¬ awake = v}; Inner[]; IF tookit THEN InputFocus.CaptureButtons[proc: v.class.notify, tip: v.tipTable, viewer: v]; RETURN}; Sleepen: PROC [v: Viewer] RETURNS [lostit, asleep: BOOL ¬ FALSE] ~ { Inner: ENTRY PROC ~ {IF (lostit ¬ awake = v) THEN awake ¬ NIL; asleep ¬ awake = NIL}; Inner[]; IF lostit THEN InputFocus.ReleaseButtons[]; RETURN}; NotifyBiScroller: PROC [self: Viewer, input: LIST OF REF ANY, device, user, display: REF ANY] --ViewerClasses.NotifyProc-- = { bs: BiScroller ¬ NARROW[self.data]; bd: Buttonned ¬ NARROW[bs.rep]; i, o, l: LIST OF REF ANY ¬ NIL; IF self # bd.client THEN ERROR; IF bs.class.common.notify = NIL THEN RETURN; FOR i ¬ input, i.rest WHILE i # NIL DO l ¬ IF l = NIL THEN o ¬ CONS[i.first, NIL] ELSE l.rest ¬ CONS[i.first, NIL]; WITH l.first SELECT FROM z: TIPUser.TIPScreenCoords => { IF Awoken[self] THEN { v: Viewer; inClient: BOOL; [v, inClient] ¬ ViewerOps.MouseInViewer[z]; IF v # bd.client OR NOT inClient THEN { bd.clientWantsActive ¬ FALSE; SetActive[bd]; bs.class.common.notify[bd.client, bs.class.common.finish]; RETURN}; }; l.first ¬ NEW [Vec ¬ bd.u.Transform[[z.mouseX, z.mouseY]]]; }; ENDCASE; ENDLOOP; bs.class.common.notify[self, o]; }; SetActive: PROC [bd: Buttonned] = { ok: BOOL; IF bd.clientWantsActive THEN ok ¬ Awaken[bd.client].havit ELSE ok ¬ Sleepen[bd.client].asleep; IF NOT ok THEN ERROR; }; PaintClient: PROC [self: Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL] RETURNS [quit: BOOL ¬ FALSE] --ViewerClasses.PaintProc-- = { bs: BiScroller ¬ NARROW[self.data]; bd: Buttonned ¬ NARROW[bs.rep]; context.ConcatT[bd.t]; quit ¬ bs.class.common.paint[self, context, whatChanged, clear]; }; SetButtonsCapturedness: PROC [bs: BiScroller, captured: BOOL] = { bd: Buttonned ¬ NARROW[bs.rep]; bd.clientWantsActive ¬ captured; SetActive[bd]}; InitBiScrollBar: PROC [self: Viewer] --ViewerClasses.InitProc-- = BEGIN bsb: BiScrollBar ¬ NARROW[self.data]; bsb.viewer ¬ self; END; PaintBiScrollBar: PROC [self: Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL] RETURNS [quit: BOOL ¬ FALSE] --ViewerClasses.PaintProc-- = BEGIN bsb: BiScrollBar ¬ NARROW[self.data]; Do: PROCEDURE [c: Imager.Color, xmin, ymin, xmax, ymax: Number] = {Imager.SetColor[context, c]; Imager.MaskBox[context, [xmin, ymin, xmax, ymax]]}; IF whatChanged # NIL THEN WITH whatChanged SELECT FROM r: Range => { SELECT bsb.axis FROM X => {Do[grayh, 0, 0, r.min*self.cw, self.ch]; Do[graym, r.min*self.cw, 0, r.max*self.cw, self.ch]; Do[grayl, r.max*self.cw, 0, self.cw, self.ch]}; Y => {Do[grayh, 0, 0, self.cw, r.min*self.ch]; Do[graym, 0, r.min*self.ch, self.cw, r.max*self.ch]; Do[grayl, 0, r.max*self.ch, self.cw, self.ch]}; ENDCASE => ERROR; }; ENDCASE ELSE IF NOT clear THEN Do[Imager.white, 0, 0, self.cw, self.ch]; END; NotifyBiScrollBarProc: TYPE = PROC [bsb: BiScrollBar, bs: BiScroller, bd: Buttonned, mouse: TIPUser.TIPScreenCoords, input: LIST OF REF ANY] RETURNS [LIST OF REF ANY]; WakeUpBiScrollBar: PROC [bsb: BiScrollBar, bs: Buttonned, to: State, indicate: BOOLEAN] ~ { IF NOT Awaken[bsb.viewer].havit THEN ERROR; bsb.state ¬ to; Cursors.SetCursor[bsb.viewer.class.cursor ¬ bsb.cursors[to]]; IF indicate THEN Indicate[bsb, bs]; }; Indicate: PROC [bsb: BiScrollBar, bd: Buttonned] = { bs: BiScroller ¬ bsb.parent; r: Range = NEW[RangeObject]; beginW, endW, beginZ, endZ, deltaW: Number; SELECT bsb.axis FROM X => {[beginW, endW] ¬ ViewLimitsOfImage[bs, X]; beginZ¬0; endZ¬bd.client.cw}; Y => {[beginW, endW] ¬ ViewLimitsOfImage[bs, Y]; beginZ¬0; endZ¬bd.client.ch}; ENDCASE => ERROR; deltaW ¬ endW - beginW; IF ABS[deltaW] # 0 THEN r­ ¬ [ MAX[0.0, MIN[1.0, (beginZ - beginW)/deltaW]], MAX[0.0, MIN[1.0, (endZ - beginW)/deltaW]]] ELSE r­ ¬ [ IF beginW > beginZ THEN 0.0 ELSE 1.0, IF beginW < endZ THEN 1.0 ELSE 0.0]; ViewerOps.PaintViewer[viewer: bsb.viewer, hint: client, clearClient: FALSE, whatChanged: r]; }; Sleep: PROC [bsb: BiScrollBar] = BEGIN IF NOT Sleepen[bsb.viewer].lostit THEN ERROR; bsb.state ¬ Idle; Cursors.SetCursor[bsb.viewer.class.cursor ¬ bsb.cursors[Idle]]; END; Relax: PROC [bsb: BiScrollBar] = { bsb.state ¬ Idle; Cursors.SetCursor[bsb.viewer.class.cursor ¬ bsb.cursors[Idle]]; }; IncreaseBiScrollBar: NotifyBiScrollBarProc = BEGIN IF bsb.state # Increase THEN WakeUpBiScrollBar[bsb, bd, Increase, FALSE]; IF input.first = $Idle THEN NULL ELSE IF input.first = $Doit THEN BEGIN Relax[bsb]; Scroll[bs, SELECT bsb.axis FROM X => [0 - mouse.mouseX, 0], Y => [0, bsb.viewer.ch - mouse.mouseY], ENDCASE => ERROR]; END ELSE ERROR; RETURN [input.rest]; END; DecreaseBiScrollBar: NotifyBiScrollBarProc = BEGIN IF bsb.state # Decrease THEN WakeUpBiScrollBar[bsb, bd, Decrease, FALSE]; IF input.first = $Idle THEN NULL ELSE IF input.first = $Doit THEN BEGIN Relax[bsb]; Scroll[bs, SELECT bsb.axis FROM X => [mouse.mouseX, 0], Y => [0, mouse.mouseY - bsb.viewer.ch], ENDCASE => ERROR]; END ELSE ERROR; RETURN [input.rest]; END; ThumbBiScrollBar: NotifyBiScrollBarProc = BEGIN IF bsb.state # Random THEN WakeUpBiScrollBar[bsb, bd, Random, FALSE]; IF input.first = $Idle THEN NULL ELSE IF input.first = $Doit THEN BEGIN cmin, cmax: Number; Foo: PROCEDURE [low, high, mouse: Number] RETURNS [Number] = {RETURN [(mouse-low) / (high-low)]}; SELECT bsb.axis FROM X => {[cmin, cmax] ¬ ViewLimitsOfImage[bs, X]; Relax[bsb]; Jump[bs, Foo[0, bd.client.cw, mouse.mouseX], X]}; Y => {[cmin, cmax] ¬ ViewLimitsOfImage[bs, Y]; Relax[bsb]; Jump[bs, Foo[0, bd.client.ch, mouse.mouseY], Y]}; ENDCASE => ERROR; END ELSE ERROR; RETURN [input.rest]; END; Jump: PROC [bs: BiScroller, x: REAL, axis: Axis] ~ { SELECT axis FROM X => bs.class.common.bsUserAction[bs, LIST[$AlignFracs, NEW [Vec ¬ [x, x]], NEW [Vec ¬ [0.5, 0.5]], $TRUE, $FALSE]]; Y => bs.class.common.bsUserAction[bs, LIST[$AlignFracs, NEW [Vec ¬ [x, x]], NEW [Vec ¬ [0.5, 0.5]], $FALSE, $TRUE]]; ENDCASE => ERROR}; Scroll: PROC [bs: BiScroller, by: Vec] ~ { bs.class.common.bsUserAction[bs, LIST[$Shift, NEW [Vec ¬ by]]]}; NotifyBiScrollBar: PROC [self: Viewer, input: LIST OF REF ANY, device, user, display: REF ANY ¬ NIL] --ViewerClasses.NotifyProc-- = BEGIN ENABLE UNWIND => InputFocus.ReleaseButtons[]; bsb: BiScrollBar ¬ NARROW[self.data]; bs: BiScroller ¬ bsb.parent; bsr: Buttonned ¬ NARROW[bs.rep]; mouse: TIPUser.TIPScreenCoords; WHILE input # NIL DO WITH input.first SELECT FROM x: ATOM => SELECT x FROM $HereToEdge => input ¬ IncreaseBiScrollBar[bsb, bs, bsr, mouse, input.rest]; $EdgeToHere => input ¬ DecreaseBiScrollBar[bsb, bs, bsr, mouse, input.rest]; $Thumb => input ¬ ThumbBiScrollBar[bsb, bs, bsr, mouse, input.rest]; ENDCASE => ERROR; z: TIPUser.TIPScreenCoords => BEGIN v: Viewer; c: BOOLEAN; mouse ¬ z; IF Awoken[self] THEN BEGIN [v, c] ¬ ViewerOps.MouseInViewer[mouse]; IF v # self OR NOT c THEN {Sleep[bsb]; ViewerOps.PaintViewer[self, client, TRUE, NIL]; RETURN}; END ELSE WakeUpBiScrollBar[bsb, bsr, Idle, TRUE]; input ¬ input.rest; END; ENDCASE => ERROR; ENDLOOP; END; RI: PROC [REAL] RETURNS [INT] = Real.Round; GetTransforms: PROC [bs: BiScroller, age: TransformsAge ¬ current] RETURNS [clientToViewer, viewerToClient: Transform] = { bsr: Buttonned ¬ NARROW[bs.rep]; SELECT age FROM current => RETURN [clientToViewer: bsr.t, viewerToClient: bsr.u]; previous => RETURN [clientToViewer: bsr.tp, viewerToClient: bsr.up]; ENDCASE => ERROR; }; ChangeTransform: PROC [bs: BiScroller, new: Transform, ageOp: AgeOp, paint: BOOL ¬ TRUE] = BEGIN bd: Buttonned ~ NARROW[bs.rep]; Doit: ENTRY PROC [t, u: Transform] = { ENABLE UNWIND => NULL; SELECT ageOp FROM remember => {bd.up ¬ bd.u; bd.tp ¬ bd.t}; ignore => NULL; ENDCASE => ERROR; bd.u ¬ u; bd.t ¬ t; }; activeBar: BiScrollBar ¬ NIL; FindBar: ENTRY PROC ~ { ENABLE UNWIND => NULL; IF awake#NIL THEN WITH awake.data SELECT FROM x: BiScrollBar => activeBar ¬ x; ENDCASE => NULL; RETURN}; inv: Transform; IF bs.class.common.offsetsMustBeIntegers THEN new ¬ new.TranslateTo[[RI[new.c], RI[new.f]]]; IF new.a*new.e - new.b*new.d = 0 THEN RETURN; inv ¬ new.Invert[]; FOR c: Child ¬ bd.children, c.next UNTIL c = NIL DO nu: Vec; nu ¬ new.Transform[c.where]; IF paint THEN ViewerOps.EstablishViewerPosition[c.it, RI[nu.x], RI[nu.y], c.it.ww, c.it.wh] ELSE SetViewerPosition[c.it, RI[nu.x], RI[nu.y], c.it.ww, c.it.wh]; ENDLOOP; Doit[new, inv]; IF paint THEN ViewerOps.PaintViewer[viewer: bd.client, hint: client]; FindBar[]; IF activeBar#NIL AND activeBar.parent = bs THEN Indicate[activeBar, bd]; END; InitContainer: PROC [self: Viewer] --ViewerClasses.InitProc-- = { bs: BiScroller ¬ NARROW[self.data]; bd: Buttonned ¬ NARROW[bs.rep]; IF bd.class.menu # NIL AND self.parent = NIL THEN self.menu ¬ Menus.CopyMenu[bd.class.menu]; IF self.icon = unInit THEN self.icon ¬ bs.class.common.icon; }; AdjustContainer: PROC [self: Viewer] RETURNS [adjusted: BOOL ¬ FALSE] --ViewerClasses.AdjustProc-- = { bs: BiScroller ¬ NARROW[self.data]; bd: Buttonned ¬ NARROW[bs.rep]; adjusted ¬ bd.container # NIL AND ComputeClientBounds[bs, bd, TRUE]; }; SaveContainer: PROC [self: Viewer, force: BOOL ¬ FALSE] --ViewerClasses.SaveProc-- = { bs: BiScroller ¬ NARROW[self.data]; bd: Buttonned ¬ NARROW[bs.rep]; IF bs.class.common.save # NIL THEN bs.class.common.save[self, force]; }; Setup: PROCEDURE = BEGIN ViewerOps.RegisterViewerClass[flavor: containerFlavor, class: NEW [ViewerClasses.ViewerClassRec ¬ [ flavor: containerFlavor, init: InitContainer, adjust: AdjustContainer, save: SaveContainer ]]]; ViewerOps.RegisterViewerClass[flavor: $BiScrollBarX, class: NEW [ViewerClasses.ViewerClassRec ¬ [ flavor: $BiScrollBarX, init: InitBiScrollBar, notify: NotifyBiScrollBar, paint: PaintBiScrollBar, tipTable: TIPUser.InstantiateNewTIPTable["Knob.tip"], cursor: scrollLeftRight]]]; ViewerOps.RegisterViewerClass[flavor: $BiScrollBarY, class: NEW [ViewerClasses.ViewerClassRec ¬ [ flavor: $BiScrollBarY, init: InitBiScrollBar, notify: NotifyBiScrollBar, paint: PaintBiScrollBar, tipTable: TIPUser.InstantiateNewTIPTable["Knob.tip"], cursor: scrollUpDown]]]; RegisterStyle["Buttonned", buttonnedStyle]; [] ¬ SetDefaultStyle["Buttonned"]; END; Setup[]; END.