FILE: BiScrollersButtonless.Mesa
Last Edited by: Spreitzer, March 29, 1985 6:29:23 pm PST
Implements BiScrollerStyle "Buttonless".
DIRECTORY BiScrollers, Cursors, Geom2D, Graphics, Icons, InputFocus, Real, RealFns, TIPUser, ViewerClasses, ViewerOps;
BiScrollersButtonless: CEDAR MONITOR
IMPORTS BiScrollers, Cursors, Geom2D, Graphics, InputFocus, Real, 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: BOOLFALSE,
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];
StartProc: TYPE = PROC [viewMouse, viewCenter: Vec, bs: BiScroller, bl: Buttonless];
FinishProc: TYPE = PROC [bs: BiScroller, bl: Buttonless];
CursorProc: TYPE = PROC [viewMouse, viewCenter: Vec] RETURNS [Cursors.CursorType];
TrackProc: TYPE = PROC [viewMouse, viewCenter: Vec, bs: BiScroller, bl: Buttonless];
NewTransformProc: TYPE = PROC [old: Transform, viewMouse, viewCenter: Vec, bs: BiScroller, bl: Buttonless] RETURNS [new: Transform];
Areas: TYPE = REF AreasRec;
AreasRec: TYPE = RECORD [next: Areas, area: Area];
State: TYPE = {Normal, Thumbing, Scrolling, ScaleRandoming};
ActiveState: TYPE = State[Thumbing .. ScaleRandoming];
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
]];
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: BOOLEANTRUE] 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;
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: BOOLEANFALSE, paint: BOOLEANTRUE] =
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: BOOLFALSE] 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 ANYNIL;
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
$BSscaleRandom => Work[bs, bl, viewMouse, ScaleRandoming, input.rest];
$BSthumb => Work[bs, bl, viewMouse, Thumbing, input.rest];
$BSscroll => Work[bs, bl, viewMouse, Scrolling, input.rest];
$BSgiveUp => GiveUp[bs, bl];
$BSeatIt => NULL;
ENDCASE => ToClient[];
END;
first, next: Area;
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];
END;
IF who.cursor # NIL THEN Cursors.SetCursor[bl.viewer.class.cursor ← who.cursor[viewMouse, viewCenter]];
IF who.track # NIL THEN who.track[viewMouse, viewCenter, bs, bl];
IF input.rest.first = $Doit THEN
BEGIN
Sleep[bl];
oldT ← bl.t; bcUsed ← viewCenter;
ChangeTransform[bs, nuT ← who.newTransform[bl.t, viewMouse, viewCenter, bs, bl]];
END
ELSE IF input.rest.first # $Idle THEN ERROR;
END;
oldT, nuT: 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];
END;
Awake: ENTRY PROC [bs: Buttonless] RETURNS [b: BOOL] = {b ← awake = bs.viewer};
WakeUp: ENTRY PROC [bs: Buttonless] = {ENABLE UNWIND => {}; SetActive[bs]};
Sleep: ENTRY PROC [bs: Buttonless] = {ENABLE UNWIND => {}; DoSleep[bs]};
DoSleep: INTERNAL PROC [bs: Buttonless] = {
bs.state ← Normal;
Cursors.SetCursor[bs.viewer.class.cursor ← bs.class.cursor];
SetActive[bs];
};
SetActive: INTERNAL PROC [bs: Buttonless] = {
wasAwake: Viewer ← awake;
IF bs.clientWantsActive OR (bs.state # Normal) THEN {
IF awake = NIL THEN {
awake ← bs.viewer;
InputFocus.CaptureButtons[proc: bs.viewer.class.notify, tip: bs.viewer.tipTable, viewer: bs.viewer];
};
}
ELSE {
IF awake = bs.viewer THEN {
awake ← NIL;
InputFocus.ReleaseButtons[];
};
};
IF NOT (wasAwake = bs.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[]};
windowT: Transform;
ThumbStart: StartProc =
BEGIN
cxmin, cxmax, cymin, cymax: Number;
cx, cy, dx, dy: Number;
[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;
first ← windowT.MapArea[[cx-dx, cy-dy, cx+dx, cy+dy]];
ViewerOps.PaintViewer[
viewer: bl.viewer,
hint: client,
clearClient: FALSE,
whatChanged: NewArea[first]
];
next ← first;
END;
ThumbTrack: TrackProc =
BEGIN
new: Area ← viewMouse.Minus[viewCenter].Displace[first];
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: AreaDiff[next, first]];
};
ThumbTransform: NewTransformProc =
BEGIN
u: Transform ← windowT.Inverse[];
RETURN [old.TranslateV[Geom2D.Minus[[bl.viewer.cw/2, bl.viewer.ch/2],
u.MapVec[viewMouse]]]];
END;
Indicate: PROC [a, b: Vec, w, h: REAL] RETURNS [Area] =
BEGIN
adx: Number ← ABS[a.x - b.x];
ady: Number ← ABS[a.y - b.y];
IF a.Minus[b] = [0, 0] THEN RETURN [[a.x, a.y, a.x, a.y]];
IF adx < 2 THEN RETURN [SortArea[[0, a.y, w, b.y]]];
IF adx < ady/10 THEN RETURN [SortArea[[0, a.y, w, b.y]]];
IF ady < 2 THEN RETURN [SortArea[[a.x, 0, b.x, h]]];
IF ady < adx/10 THEN RETURN [SortArea[[a.x, 0, b.x, h]]];
RETURN [SortArea[[a.x, a.y, b.x, b.y]]];
END;
SortArea: PROC [in: Area] RETURNS [out: Area] = INLINE
{RETURN [[MIN[in.xmin, in.xmax], MIN[in.ymin, in.ymax],
MAX[in.xmin, in.xmax], MAX[in.ymin, in.ymax]]]};
ScrollStart: StartProc = {
first ← Indicate[viewMouse, viewCenter, bl.viewer.cw, bl.viewer.ch];
ViewerOps.PaintViewer[
viewer: bl.viewer,
hint: client,
clearClient: FALSE,
whatChanged: NewArea[first]
];
next ← first;
};
ScrollTrack: TrackProc = {
new: Area ← Indicate[viewMouse, viewCenter, bl.viewer.cw, bl.viewer.ch];
ViewerOps.PaintViewer[viewer: bl.viewer, hint: client, clearClient: FALSE, whatChanged: AreaDiff[new, next]];
next ← new;
};
ScrollFinish: FinishProc = {
ViewerOps.PaintViewer[viewer: bl.viewer, hint: client, clearClient: FALSE, whatChanged: NewArea[next]];
};
ScrollCursor: CursorProc =
BEGIN
d: Vec ← viewCenter.Minus[viewMouse];
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
delta: Vec ← viewCenter.Minus[viewMouse];
adx: Number ← ABS[delta.x];
ady: Number ← ABS[delta.y];
IF adx < 2 OR adx < ady/10 THEN delta.x ← 0 ELSE
IF ady < 2 OR ady < adx/10 THEN delta.y ← 0;
RETURN [old.TranslateV[delta]];
END;
ScaleRandomStart: StartProc =
BEGIN
d: Vec ← viewMouse.Minus[viewCenter];
adx: Number ← ABS[d.x];
ady: Number ← ABS[d.y];
slope ← IF adx = 0 THEN 1 ELSE ady/adx;
first ← [viewCenter.x-adx, viewCenter.y-ady, viewCenter.x+adx, viewCenter.y+ady];
next ← first;
END;
slope: Number;
ScaleRandomTrack: TrackProc =
BEGIN
d: Vec ← viewMouse.Minus[viewCenter];
adx: Number ← ABS[d.x];
ady: Number ← IF bs.class.common.mayStretch THEN ABS[d.y] ELSE adx*slope;
new: Area ← [viewCenter.x-adx, viewCenter.y-ady, viewCenter.x+adx, viewCenter.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: AreaDiff[next, first]];
};
ScaleRandomTransform: NewTransformProc =
BEGIN
ndx, ndy, odx, ody, sx, sy: Number;
ndx ← next.xmax - next.xmin;
ndy ← next.ymax - next.ymin;
odx ← first.xmax - first.xmin;
ody ← first.ymax - first.ymin;
sx ← IF ndx=0 OR odx=0 THEN 1 ELSE ndx/odx;
sy ← IF ndy=0 OR ody=0 THEN 1 ELSE ndy/ody;
IF NOT bs.class.common.mayStretch THEN sx ← sy ← (sx+sy)/2;
RETURN [old.Translate[-viewCenter.x, -viewCenter.y].ScaleTXY[sx, sy].TranslateV[viewCenter]];
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;
};
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: BOOLEANTRUE] =
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 bs.class.common.preferIntegerCoefficients THEN {
dxdx: INTEGERRI[new.a];
dydx: INTEGERRI[new.b];
dxdy: INTEGERRI[new.c];
dydy: INTEGERRI[new.d];
IF
((dxdx=0) = (new.a=0)) AND
((dydx=0) = (new.b=0)) AND
((dxdy=0) = (new.c=0)) AND
((dydy=0) = (new.d=0))
THEN {new.a ← dxdx; new.b← dydx; new.c ← dxdy; new.d ← dydy};
};
IF new = bl.t THEN RETURN;
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];
ViewerOps.EstablishViewerPosition[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[Scrolling] ← NEW [MouseRec ← [start: ScrollStart,
track: ScrollTrack,
finish: ScrollFinish,
cursor: ScrollCursor,
newTransform: ScrollTransform]];
mice[ScaleRandoming] ← NEW [MouseRec ← [start: ScaleRandomStart,
track: ScaleRandomTrack,
finish: ScaleRandomFinish,
cursor: TextCursor,
newTransform: ScaleRandomTransform]];
RegisterStyle["Buttonless", buttonlessStyle];
END;
Setup[];
END.