DIRECTORY BiScrollers, Cursors, Geom2D, Graphics, Icons, InputFocus, Real, RealFns, TIPUser, ViewerClasses, ViewerOps; BiScrollersButtonless: CEDAR MONITOR IMPORTS BiScrollers, Cursors, Geom2D, Graphics, InputFocus, Real, RealFns, TIPUser, ViewerOps = BEGIN OPEN BiScrollers; Number: TYPE = Geom2D.Number; ViewerClass: TYPE = ViewerClasses.ViewerClass; Axis: TYPE = Geom2D.Axis; Vec: TYPE = Geom2D.Vec; Area: TYPE = Geom2D.Area; AreaRef: TYPE = REF Area; Buttonless: TYPE = REF ButtonlessRep; ButtonlessRep: TYPE = RECORD [ class: ButtonlessClass, clientData: REF ANY, viewer: Viewer _ NIL, children: Child _ NIL, t: Transform _ Geom2D.id, --Client to Viewer Transform u: Transform _ Geom2D.id, --Viewer coords*u = Client coords cw, ch: INTEGER _ 0, --last time we looked in the viewer-- clientWantsActive: BOOL _ FALSE, state: State _ Normal ]; ButtonlessClass: TYPE = REF ButtonlessClassRep; ButtonlessClassRep: TYPE = RECORD [ viewerClass: ViewerClass, cursor: Cursors.CursorType ]; Child: TYPE = REF ChildObject; ChildObject: TYPE = RECORD [next: Child, where: Vec, it: Viewer]; Mouse: TYPE = REF MouseRec; MouseRec: TYPE = RECORD [ start: StartProc _ NIL, finish: FinishProc _ NIL, cursor: CursorProc _ NIL, track: TrackProc _ NIL, newTransform: NewTransformProc, data: REF ANY _ NIL]; StartProc: TYPE = PROC [viewMouse, viewCenter: Vec, bs: BiScroller, bl: Buttonless, data: REF ANY]; FinishProc: TYPE = PROC [bs: BiScroller, bl: Buttonless, data: REF ANY]; CursorProc: TYPE = PROC [viewMouse, viewCenter: Vec, data: REF ANY] RETURNS [Cursors.CursorType]; TrackProc: TYPE = PROC [viewMouse, viewCenter: Vec, bs: BiScroller, bl: Buttonless, data: REF ANY]; NewTransformProc: TYPE = PROC [viewMouse, viewCenter: Vec, bs: BiScroller, bl: Buttonless, data: REF ANY]; Areas: TYPE = REF AreasRec; AreasRec: TYPE = RECORD [next: Areas, area: Area]; Paths: TYPE = REF PathsRep; PathsRep: TYPE = RECORD [next: Paths, path: Graphics.Path, op: {fill, stroke}]; State: TYPE = {Normal, Thumbing, ScrollToCentering, ScrollAlongClicksing, Expanding, Contracting}; ActiveState: TYPE = State[Thumbing .. Contracting]; awake: Viewer _ NIL; mice: ARRAY ActiveState OF Mouse _ ALL[NIL]; pointUpRight, pointUpLeft, pointDownRight, pointDownLeft: Cursors.CursorType; buttonlessStyle: 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 ]]; first, next: Area; NewBiScrollerClass: PROC [cc: ClassCommon] RETURNS [bsc: BiScrollerClass] = BEGIN viewerClass: ViewerClass; t: TIPUser.TIPTable _ TIPUser.InstantiateNewTIPTable["BiScroller.TIP"]; IF cc.vanilla = NIL THEN cc.vanilla _ GenID; IF cc.tipTable # NIL THEN BEGIN t.mouseTicks _ MIN[t.mouseTicks, cc.tipTable.mouseTicks]; t.opaque _ FALSE; t.link _ cc.tipTable; END; viewerClass _ NEW [ViewerClasses.ViewerClassRec _ [ flavor: cc.flavor, notify: NotifyBiScroller, paint: PaintBiScroller, modify: cc.modify, destroy: cc.destroy, copy: cc.copy, set: cc.set, get: cc.get, save: cc.save, menu: cc.menu, tipTable: t, icon: cc.icon, cursor: cc.cursor]]; ViewerOps.RegisterViewerClass[flavor: viewerClass.flavor, class: viewerClass]; bsc _ NEW [BiScrollerClassRep _ [ style: buttonlessStyle, common: cc, rep: NEW [ButtonlessClassRep _ [viewerClass: viewerClass, cursor: cc.cursor]] ]]; END; CreateBiScroller: PROC [class: BiScrollerClass, info: ViewerClasses.ViewerRec _ [], paint: BOOLEAN _ TRUE] RETURNS [new: BiScroller] = BEGIN bsc: ButtonlessClass _ NARROW[class.rep]; paintFirst: BOOL = paint AND info.iconic; bl: Buttonless _ NEW [ButtonlessRep _ [class: bsc, clientData: info.data]]; info.data _ new _ NEW [BiScrollerRep _ [ style: class.style, class: class, rep: bl]]; bl.viewer _ ViewerOps.CreateViewer[flavor: bsc.viewerClass.flavor, info: info, paint: paintFirst]; ChangeTransform[new, class.common.vanilla[new], FALSE]; bl.cw _ bl.viewer.cw; bl.ch _ bl.viewer.ch; SetBS[bl.viewer, new]; IF class.common.init # NIL THEN class.common.init[bl.viewer]; IF NOT paintFirst THEN ViewerOps.ComputeColumn[column: ViewerOps.ViewerColumn[bl.viewer], paint: paint]; END; Destroy: PROC [bs: BiScroller] RETURNS [BiScroller] = BEGIN bl: Buttonless _ NARROW[bs.rep]; ViewerOps.DestroyViewer[bl.viewer]; bl.viewer _ NIL; RETURN [NIL]; END; AddChild: PROC [to: BiScroller, what: Viewer, x, y: REAL _ 0, useTheseCoords: BOOLEAN _ FALSE, paint: BOOLEAN _ TRUE] = BEGIN bl: Buttonless _ NARROW[to.rep]; my: Vec; c: Child _ NEW [ChildObject _ [next: bl.children, it: what, where: IF useTheseCoords THEN [x, y] ELSE [what.wx, what.wy] ]]; bl.children _ c; my _ bl.t.MapVec[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 bl: Buttonless _ 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]}; bl.children _ Filter[bl.children]; END; QuaViewer: PROC [bs: BiScroller, inner: BOOL _ FALSE] RETURNS [Viewer] = {bl: Buttonless _ NARROW[bs.rep]; RETURN [bl.viewer]}; ClientDataOf: PROC [bs: BiScroller] RETURNS [REF ANY] = {bl: Buttonless _ NARROW[bs.rep]; RETURN [bl.clientData]}; ViewportOf: PROC [bs: BiScroller] RETURNS [VecList] = BEGIN bl: Buttonless _ NARROW[bs.rep]; RETURN [Geom2D.MapVecs[bl.u, LIST[[0, 0], [bl.viewer.cw, 0], [bl.viewer.cw, bl.viewer.ch], [0, bl.viewer.ch]]]]; END; FinishClient: PROC [bs: BiScroller, bl: Buttonless] = { IF bs.class.common.notify # NIL THEN bs.class.common.notify[bl.viewer, bs.class.common.finish]; }; NotifyBiScroller: PROC [self: Viewer, input: LORA] --ViewerClasses.NotifyProc-- = BEGIN bs: BiScroller _ NARROW[self.data, BiScroller]; bl: Buttonless _ NARROW[bs.rep]; i, o, l: LIST OF REF ANY _ NIL; viewMouse: Vec; ToClient: PROC = { IF bl.state # Normal THEN GiveUp[bs, bl]; IF bs.class.common.notify # NIL THEN bs.class.common.notify[bl.viewer, input]}; 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 Awake[bl] THEN { v: Viewer; inClient: BOOL; [v, inClient] _ ViewerOps.MouseInViewer[z]; IF v # bl.viewer OR NOT inClient THEN { didWant: BOOL _ bl.clientWantsActive; bl.clientWantsActive _ FALSE; IF bl.state IN ActiveState THEN Finish[bs, bl, mice[bl.state]]; Sleep[bl]; IF didWant THEN FinishClient[bs, bl]; RETURN}; }; l.first _ NEW [Vec _ bl.u.MapVec[viewMouse _ [z.mouseX, z.mouseY]]]; }; ENDCASE; ENDLOOP; input _ o; IF input = NIL THEN ToClient[] ELSE SELECT input.first FROM $BSexpand => Work[bs, bl, viewMouse, Expanding, input.rest]; $BScontract => Work[bs, bl, viewMouse, Contracting, input.rest]; $BSthumb => Work[bs, bl, viewMouse, Thumbing, input.rest]; $BSscrollToCenter => Work[bs, bl, viewMouse, ScrollToCentering, input.rest]; $BSscrollAlongClicks => Work[bs, bl, viewMouse, ScrollAlongClicksing, input.rest]; $BSgiveUp => GiveUp[bs, bl]; $BSeatIt => NULL; ENDCASE => ToClient[]; END; Work: PROC [bs: BiScroller, bl: Buttonless, viewMouse: Vec, why: ActiveState, input: LORA] = BEGIN viewCenter: Vec; who: Mouse _ mice[why]; oldState: State _ bl.state; clientWanted: BOOL _ bl.clientWantsActive; bl.clientWantsActive _ FALSE; bl.state _ why; viewCenter _ [bl.viewer.cw/2, bl.viewer.ch/2]; IF clientWanted THEN FinishClient[bs, bl]; WakeUp[bl]; IF why # oldState THEN BEGIN IF oldState IN ActiveState THEN Finish[bs, bl, mice[oldState]]; IF who.start # NIL THEN who.start[viewMouse, viewCenter, bs, bl, who.data]; END; IF who.cursor # NIL THEN Cursors.SetCursor[bl.viewer.class.cursor _ who.cursor[viewMouse, viewCenter, who.data]]; IF who.track # NIL THEN who.track[viewMouse, viewCenter, bs, bl, who.data]; IF input.rest.first = $Doit THEN BEGIN Sleep[bl]; oldT _ bl.t; bcUsed _ viewCenter; who.newTransform[viewMouse, viewCenter, bs, bl, who.data]; END ELSE IF input.rest.first # $Idle THEN ERROR; END; oldT: Transform; bcUsed: Vec; GiveUp: PROCEDURE [bs: BiScroller, bl: Buttonless] = BEGIN WasIdle: ENTRY PROC RETURNS [BOOLEAN] = {oldState _ bl.state; IF bl.state = Normal THEN RETURN [TRUE]; DoSleep[bl]; RETURN [FALSE]}; oldState: State; IF WasIdle[] THEN RETURN; IF oldState = Normal THEN ERROR; Finish[bs, bl, mice[oldState]]; END; Finish: PROC [bs: BiScroller, bl: Buttonless, mouse: Mouse] = BEGIN IF mouse.finish # NIL THEN mouse.finish[bs, bl, mouse.data]; END; Awake: ENTRY PROC [bl: Buttonless] RETURNS [b: BOOL] = {b _ awake = bl.viewer}; WakeUp: ENTRY PROC [bl: Buttonless] = {ENABLE UNWIND => {}; SetActive[bl]}; Sleep: ENTRY PROC [bl: Buttonless] = {ENABLE UNWIND => {}; DoSleep[bl]}; DoSleep: INTERNAL PROC [bl: Buttonless] = { bl.state _ Normal; Cursors.SetCursor[bl.viewer.class.cursor _ bl.class.cursor]; SetActive[bl]; }; SetActive: INTERNAL PROC [bl: Buttonless] = { wasAwake: Viewer _ awake; IF bl.clientWantsActive OR (bl.state # Normal) THEN { IF awake = NIL THEN { awake _ bl.viewer; InputFocus.CaptureButtons[proc: bl.viewer.class.notify, tip: bl.viewer.tipTable, viewer: bl.viewer]; }; } ELSE { IF awake = bl.viewer THEN { awake _ NIL; InputFocus.ReleaseButtons[]; }; }; IF NOT (wasAwake = bl.viewer OR wasAwake = NIL) THEN ERROR; }; SetButtonsCapturedness: PROC [bs: BiScroller, captured: BOOL] = { bl: Buttonless _ NARROW[bs.rep]; Doit: ENTRY PROC = { bl.clientWantsActive _ captured; SetActive[bl]}; Doit[]}; outline: Area; ThumbStart: StartProc = BEGIN cxmin, cxmax, cymin, cymax: Number; cx, cy, dx, dy: Number; windowT: Transform; [cxmin, cxmax] _ ViewLimitsOfImage[bs, X]; [cymin, cymax] _ ViewLimitsOfImage[bs, Y]; [windowT.a, windowT.e] _ Squeeze[cxmin, cxmax, 0, bl.viewer.cw]; [windowT.d, windowT.f] _ Squeeze[cymin, cymax, 0, bl.viewer.ch]; windowT.b _ windowT.c _ 0; cx _ (cxmin+cxmax)/2; cy _ (cymin+cymax)/2; dx _ bl.viewer.cw/2; dy _ bl.viewer.ch/2; outline _ windowT.MapArea[[cx-dx, cy-dy, cx+dx, cy+dy]]; first _ viewMouse.Minus[viewCenter].Displace[outline]; ViewerOps.PaintViewer[ viewer: bl.viewer, hint: client, clearClient: FALSE, whatChanged: NewArea[first] ]; next _ first; END; ThumbTrack: TrackProc = BEGIN new: Area _ viewMouse.Minus[viewCenter].Displace[outline]; ViewerOps.PaintViewer[viewer: bl.viewer, hint: client, clearClient: FALSE, whatChanged: AreaDiff[new, next]]; next _ new; END; ThumbFinish: FinishProc = { ViewerOps.PaintViewer[viewer: bl.viewer, hint: client, clearClient: FALSE, whatChanged: NewArea[next]]; }; ThumbTransform: NewTransformProc = BEGIN Align[ bs, [fraction[viewMouse.x/bl.viewer.cw, viewMouse.y/bl.viewer.ch]], [fraction[0.5, 0.5]] ]; END; arWidth: REAL _ 0.1; arHalfWidth: REAL _ arWidth/2; arHeadLen: REAL _ 0.4; rootTwo: REAL _ RealFns.SqRt[2.0]; rootHalf: REAL _ RealFns.SqRt[0.5]; MakeArrow: PROC [from, to: Vec, also: Paths] RETURNS [alles: Paths] = { first: BOOL _ TRUE; p: Graphics.Path _ Graphics.NewPath[10]; diff: Vec; t: Transform; Do: PROC [x, y: REAL] = { v: Vec _ t.MapVec[[x, y]]; IF first THEN Graphics.MoveTo[p, v.x, v.y] ELSE Graphics.LineTo[p, v.x, v.y]; first _ FALSE; }; [from, to, ] _ AdjustScroll[from, to]; diff _ from.Minus[to]; t _ Geom2D.id .RotateDegrees[RealFns.ArcTanDeg[diff.y, diff.x] - 90] .ScaleT[diff.Length[]] .TranslateV[to]; Do[arHalfWidth, 1.0]; Do[arHalfWidth, arWidth*rootTwo+arHalfWidth]; Do[(arHeadLen - arWidth)*rootHalf, (arHeadLen + arWidth)*rootHalf]; Do[arHeadLen*rootHalf, arHeadLen*rootHalf]; Do[0, 0]; Do[-arHeadLen*rootHalf, arHeadLen*rootHalf]; Do[(arWidth-arHeadLen)*rootHalf, (arWidth+arHeadLen)*rootHalf]; Do[-arHalfWidth, arWidth*rootTwo+arHalfWidth]; Do[-arHalfWidth, 1.0]; alles _ NEW [PathsRep _ [next: also, path: p, op: fill]]; }; AdjustScroll: PROC [from, to: Vec] RETURNS [nFrom, nTo: Vec, changed: BOOL] = { delta: Vec _ to.Minus[from]; adx: Number _ ABS[delta.x]; ady: Number _ ABS[delta.y]; IF changed _ (adx < 2 OR adx < ady/10) THEN delta.x _ 0 ELSE IF changed _ (ady < 2 OR ady < adx/10) THEN delta.y _ 0; nTo _ to; nFrom _ nTo.Minus[delta]; }; scrollDown: Vec; oldArrow: Paths; ScrollFrom: PROC [viewMouse, viewCenter: Vec, data: REF ANY] RETURNS [from: Vec] = {from _ SELECT data FROM $toCenter => viewMouse, $alongClicks => scrollDown, ENDCASE => ERROR}; ScrollTo: PROC [viewMouse, viewCenter: Vec, data: REF ANY] RETURNS [to: Vec] = {to _ SELECT data FROM $toCenter => viewCenter, $alongClicks => viewMouse, ENDCASE => ERROR}; ScrollStart: StartProc = { scrollDown _ viewMouse; oldArrow _ NIL; }; ScrollTrack: TrackProc = { ViewerOps.PaintViewer[ viewer: bl.viewer, hint: client, clearClient: FALSE, whatChanged: oldArrow _ MakeArrow[ ScrollFrom[viewMouse, viewCenter, data], ScrollTo[viewMouse, viewCenter, data], oldArrow] ]; oldArrow.next _ NIL; }; ScrollFinish: FinishProc = { IF oldArrow # NIL THEN ViewerOps.PaintViewer[viewer: bl.viewer, hint: client, clearClient: FALSE, whatChanged: oldArrow]; }; ScrollCursor: CursorProc = BEGIN d: Vec _ Geom2D.Minus[ ScrollTo[viewMouse, viewCenter, data], ScrollFrom[viewMouse, viewCenter, data]]; adx: Number _ ABS[d.x]; ady: Number _ ABS[d.y]; RETURN [IF d = [0, 0] THEN Cursors.CursorType[bullseye] ELSE IF adx < 2 OR adx < ady/10 THEN (IF d.y < 0 THEN pointDown ELSE pointUp) ELSE IF ady < 2 OR ady < adx/10 THEN (IF d.x < 0 THEN pointLeft ELSE pointRight) ELSE IF d.x > 0 THEN (IF d.y > 0 THEN pointUpRight ELSE pointDownRight) ELSE (IF d.y > 0 THEN pointUpLeft ELSE pointDownLeft)]; END; ScrollTransform: NewTransformProc = BEGIN from, to: Vec; [from, to, ] _ AdjustScroll[ ScrollFrom[viewMouse, viewCenter, data], ScrollTo[viewMouse, viewCenter, data]]; Shift[bs, to.x-from.x, to.y-from.y]; END; slope: Number; scaleCenter: Vec; ScaleRandomStart: StartProc = BEGIN viewer: Viewer _ bs.style.QuaViewer[bs, TRUE]; slope _ IF viewer.cw = 0 THEN 1 ELSE REAL[viewer.ch]/viewer.cw; scaleCenter _ viewMouse; next _ first _ [viewMouse.x, viewMouse.y, viewMouse.x, viewMouse.y]; END; ScaleRandomTrack: TrackProc = BEGIN d: Vec _ viewMouse.Minus[scaleCenter]; adx: Number _ ABS[d.x]; ady: Number _ IF bs.class.common.mayStretch THEN ABS[d.y] ELSE adx*slope; new: Area _ [scaleCenter.x-adx, scaleCenter.y-ady, scaleCenter.x+adx, scaleCenter.y+ady]; ViewerOps.PaintViewer[viewer: bl.viewer, hint: client, clearClient: FALSE, whatChanged: AreaDiff[new, next]]; next _ new; END; ScaleRandomFinish: FinishProc = { ViewerOps.PaintViewer[viewer: bl.viewer, hint: client, clearClient: FALSE, whatChanged: NewArea[next]]; }; ScaleRandomTransform: NewTransformProc = BEGIN viewer: Viewer _ bs.style.QuaViewer[bs, TRUE]; fromA, toA: Area; SELECT data FROM $Expand => {fromA _ next; toA _ [0, 0, viewer.cw, viewer.ch]}; $Contract => {toA _ next; fromA _ [0, 0, viewer.cw, viewer.ch]}; ENDCASE => ERROR; BoxScale[bs, fromA, toA]; END; TextCursor: CursorProc = {RETURN [textPointer]}; PaintBiScroller: PROC [self: Viewer, context: Graphics.Context, whatChanged: REF ANY, clear: BOOL] --ViewerClasses.PaintProc-- = BEGIN bs: BiScroller _ NARROW[self.data]; bl: Buttonless _ NARROW[bs.rep]; IF clear AND (self.cw # bl.cw OR self.ch # bl.ch) THEN { client: Vec --the point that stays fixed, in client coords--; client _ bl.u.MapVec[[ bs.class.common.preserve[X]*bl.cw, bs.class.common.preserve[Y]*bl.ch]]; Align[ bs: bs, client: [coord[client.x, client.y]], viewer: [fraction[bs.class.common.preserve[X], bs.class.common.preserve[Y]]], paint: FALSE]; bl.cw _ self.cw; bl.ch _ self.ch; }; IF whatChanged # NIL THEN WITH whatChanged SELECT FROM as: Areas => { Graphics.SetStipple[context, 122645B]; [] _ Graphics.SetPaintMode[context, invert]; FOR a: Areas _ as, a.next WHILE a # NIL DO Graphics.DrawBox[context, a.area]; ENDLOOP; RETURN; }; ps: Paths => { Graphics.SetStipple[context, 122645B]; [] _ Graphics.SetPaintMode[context, invert]; FOR p: Paths _ ps, p.next WHILE p # NIL DO SELECT p.op FROM fill => Graphics.DrawArea[context, p.path]; stroke => Graphics.DrawStroke[context, p.path]; ENDCASE => ERROR; ENDLOOP; RETURN; }; ENDCASE; Graphics.Translate[context, bl.t.e, bl.t.f]; Graphics.Concat[context, bl.t.a, bl.t.b, bl.t.c, bl.t.d]; bs.class.common.paint[self, context, whatChanged, clear]; END; RI: PROC [REAL] RETURNS [INTEGER] = Real.RoundI; GetTransforms: PROC [bs: BiScroller] RETURNS [t, u: Transform] = {bl: Buttonless _ NARROW[bs.rep]; t _ bl.t; u _ bl.u}; ChangeTransform: PROC [bs: BiScroller, new: Transform, paint: BOOLEAN _ TRUE] = BEGIN bl: Buttonless _ NARROW[bs.rep]; Doit: ENTRY PROC [t, u: Transform] = {bl.u _ u; bl.t _ t}; inv: Transform; IF bs.class.common.offsetsMustBeIntegers THEN {new.e _ RI[new.e]; new.f _ RI[new.f]}; IF new.a*new.d - new.b*new.c = 0 THEN RETURN; inv _ new.Inverse[]; FOR c: Child _ bl.children, c.next UNTIL c = NIL DO nu: Vec; nu _ new.MapVec[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: bl.viewer, hint: client]; END; Squeeze: PROC [fromMin, fromMax, toMin, toMax: Number] RETURNS [scale, offset: Number] = BEGIN dFrom: Number _ fromMax - fromMin; IF dFrom = 0 THEN RETURN [1, (toMin+toMax)/2]; scale _ (toMax - toMin)/dFrom; offset _ toMin - scale*fromMin; END; NewArea: PROC [a: Area, next: Areas _ NIL] RETURNS [Areas] = {RETURN [NEW [AreasRec _ [next: next, area: a]]]}; AreaDiff: PROC [a, b: Area] RETURNS [d: Areas] = BEGIN y: Number; IF b.ymin < a.ymin THEN {c: Area _ a; a _ b; b _ c}; IF (IF a.ymax <= b.ymin THEN TRUE ELSE IF a.xmin >= b.xmax THEN TRUE ELSE IF a.xmax <= b.xmin THEN TRUE ELSE FALSE) THEN RETURN [NewArea[a, NewArea[b]]]; IF a.ymax > b.ymax THEN d _ NewArea[[a.xmin, y _ b.ymax, a.xmax, a.ymax]] ELSE d _ NewArea[[b.xmin, y _ a.ymax, b.xmax, b.ymax]]; RETURN [NewArea[[b.xmin, b.ymin, a.xmin, y], NewArea[[b.xmax, b.ymin, a.xmax, y], NewArea[[a.xmin, a.ymin, a.xmax, b.ymin], d]]]]; END; Setup: PROCEDURE = BEGIN pointUpRight _ Cursors.NewCursor[hotX: -15, hotY: 0, bits: [ 000037B, 000177B, 000777B, 001477B, 002077B, 000176B, 000346B, 000704B, 001614B, 003410B, 007020B, 016000B, 034000B, 070000B, 160000B, 140000B]]; pointUpLeft _ Cursors.NewCursor[hotX: 0, hotY: 0, bits: [ 174000B, 177000B, 177600B, 176300B, 176040B, 077000B, 063400B, 021600B, 030700B, 010340B, 004160B, 000070B, 000034B, 000016B, 000007B, 000003B]]; pointDownRight _ Cursors.NewCursor[hotX: -15, hotY: -15, bits: [ 140000B, 160000B, 070000B, 034000B, 016000B, 007020B, 003410B, 001614B, 000704B, 000346B, 000176B, 002077B, 001477B, 000777B, 000177B, 000037B]]; pointDownLeft _ Cursors.NewCursor[hotX: 0, hotY: -15, bits: [ 000003B, 000007B, 000016B, 000034B, 000070B, 004160B, 010340B, 030700B, 021600B, 063400B, 077000B, 176040B, 176300B, 177600B, 177000B, 174000B]]; mice[Thumbing] _ NEW [MouseRec _ [ start: ThumbStart, track: ThumbTrack, finish: ThumbFinish, cursor: TextCursor, newTransform: ThumbTransform]]; mice[ScrollToCentering] _ NEW [MouseRec _ [ start: ScrollStart, track: ScrollTrack, finish: ScrollFinish, cursor: ScrollCursor, newTransform: ScrollTransform, data: $toCenter]]; mice[ScrollAlongClicksing] _ NEW [MouseRec _ [ start: ScrollStart, track: ScrollTrack, finish: ScrollFinish, cursor: ScrollCursor, newTransform: ScrollTransform, data: $alongClicks]]; mice[Expanding] _ NEW [MouseRec _ [ start: ScaleRandomStart, track: ScaleRandomTrack, finish: ScaleRandomFinish, cursor: TextCursor, newTransform: ScaleRandomTransform, data: $Expand]]; mice[Contracting] _ NEW [MouseRec _ [ start: ScaleRandomStart, track: ScaleRandomTrack, finish: ScaleRandomFinish, cursor: TextCursor, newTransform: ScaleRandomTransform, data: $Contract]]; RegisterStyle["Buttonless", buttonlessStyle]; END; Setup[]; END. ŠFILE: BiScrollersButtonless.Mesa Last Edited by: Spreitzer, April 15, 1985 9:52:23 am PST Implements BiScrollerStyle "Buttonless". Κο˜J™ J™8J™Jšœ(™(J˜codešΟk œm˜vK˜—šΠbxœœ˜$KšœV˜]—K˜Kšœœœ ˜K˜Kšœœ˜Kšœ œ˜.Kšœœ˜Kšœœ˜Kšœœ˜Kšœ œœ˜K˜Kšœ œœ˜%šœœœ˜Kšœ˜Kšœ œœ˜Kšœœ˜Kšœœ˜KšœΟc˜6KšœŸ!˜;KšœœŸ%˜;Kšœœœ˜ K˜K˜K˜—Kšœœœ˜/šœœœ˜#K˜K˜Kšœ˜K˜—Kšœœœ ˜Kšœ œœ'˜AK˜Kšœœœ ˜šœ œœ˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœœ˜K˜Kšœœœœ˜K˜—Kš Οn œœœDœœ˜cKš   œœœ(œœ˜HKš   œœœ$œœœ˜aKš   œœœDœœ˜cKš  œœœDœœ˜jK˜Kšœœœ ˜Kšœ œœ˜2K˜Kšœœœ ˜Kšœ œœ8˜OK˜šœœW˜bK˜—Kšœ œ"˜3K˜Kšœœ˜Kš œœ œ œœ˜,K˜K˜MK˜šœ#œ˜>Kšœ'˜'Kšœ#˜#Kšœ˜Kšœ˜Kšœ!˜!Kšœ˜Kšœ˜Kšœ/˜/Kšœ˜Kšœ˜Kšœ˜K˜—K˜K˜K˜š œœœ˜KKš˜K˜K˜GKšœœœ˜,šœœ˜Kš˜Kšœœ'˜9Kšœ œ˜K˜Kšœ˜—šœœ"˜3K˜K˜K˜K˜K˜K˜K˜ K˜ K˜K˜K˜ K˜K˜—KšœN˜Nšœœ˜!Kšœ˜K˜ KšœœE˜MK˜—Kšœ˜K˜—š  œœEœœœ˜†Kš˜Kšœœ ˜)Kšœ œ œ ˜)Kšœœ7˜Kšœœ˜(Kšœ˜Kšœ ˜ Kšœ ˜ —Kšœb˜bKšœ0œ˜7K˜K˜K˜Kšœœœ˜=Kšœœ œR˜hKšœ˜K˜—š œœœ˜5Kš˜Kšœœ ˜ Kšœ#˜#Kšœ œ˜Kšœœ˜ Kšœ˜K˜—š œœ&œœœ œœ˜wKš˜Kšœœ ˜ K˜šœ œ#˜1K˜ šœœœ˜$Kšœ˜——Kšœ˜Kšœ˜šœ&œ œ˜K˜@Kšœœ˜—K˜Kšœ˜K˜—Kšœœ˜0K˜š  œœ8œœ œŸœ˜€Kš˜Kšœœ ˜#Kšœœ ˜ šœœœœ˜8Kšœ Ÿ0œ˜=˜Kšœœ˜"Kšœœ ˜$—šœ˜Kšœ˜Kšœ$˜$Kšœ+œœ˜MKšœœ˜—K˜K˜K˜—š œœœœ œ˜6˜K˜&K˜,šœœœ˜*K˜"Kšœ˜—Kšœ˜K˜—šœ˜K˜&K˜,šœœœ˜*šœ˜Kšœ+˜+Kšœ/˜/Kšœœ˜—Kšœ˜—Kšœ˜K˜—Kšœ˜—K˜,K˜9K˜9Kšœ˜—K˜Kš œœœœœ˜0K˜š  œœœ˜@Kšœœ˜6—K˜š œœ)œœ˜OKš˜Kšœœ ˜ Kš œœœ*˜:K˜Kšœ'œ œœ ˜UKšœœœ˜-K˜šœ œœ˜3K˜K˜šœ˜Kšœ)œœ˜RKšœœœ˜C—Kšœ˜—K˜Kšœœ8˜EKšœ˜K˜—š œœ)˜6Kšœ˜!Kš˜K˜"Kšœ œœ˜.K˜K˜Kšœ˜K˜—š œœœœ ˜