123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893 |
- MODULE StdLinks;
- (* THIS IS TEXT COPY OF BlackBox 1.6-rc6 Std/Mod/Links.odc *)
- IMPORT Kernel, Services,
- Stores, Ports, Fonts, Models, Views, Controllers, Properties, Dialog, Containers,
- TextModels, TextMappers, TextViews, TextControllers, TextSetters, TextRulers,
- Strings, StdCmds;
- CONST
- kind* = 0; cmd* = 1; close* = 2; (* constants for Prop.valid *)
- always* = 0; ifShiftDown* = 1; never* = 2; (* constants for close attrubute *)
- minLinkVersion = 0; maxLinkVersion = 1;
- minTargVersion = 0; maxTargVersion = 0;
- TYPE
- Directory* = POINTER TO ABSTRACT RECORD END;
- Link* = POINTER TO RECORD (Views.View)
- leftSide-: BOOLEAN;
- cmd: POINTER TO ARRAY OF CHAR;
- close: INTEGER
- END;
- Target* = POINTER TO RECORD (Views.View)
- leftSide-: BOOLEAN;
- ident: POINTER TO ARRAY OF CHAR
- END;
- Prop* = POINTER TO RECORD (Properties.Property)
- cmd*: POINTER TO ARRAY OF CHAR;
- link-: BOOLEAN;
- close*: INTEGER
- END;
-
- ChangeAttrOp = POINTER TO RECORD (Stores.Operation)
- v: Views.View;
- cmd: POINTER TO ARRAY OF CHAR;
- close: INTEGER;
- valid: SET
- END;
-
- StdDirectory = POINTER TO RECORD (Directory) END;
- TrapCleaner = POINTER TO RECORD (Kernel.TrapCleaner) END;
- VAR
- dir-, stdDir-: Directory;
- par-: Link;
- iconFont: Fonts.Typeface;
- linkLeft, linkRight, targetLeft, targetRight: ARRAY 8 OF SHORTCHAR;
- coloredBackg: BOOLEAN;
-
- cleaner: TrapCleaner;
- dialog*: RECORD
- cmd*: ARRAY 512 OF CHAR;
- type-: ARRAY 32 OF CHAR;
- close*: Dialog.List;
- known, valid: SET;
- END;
- fingerprint: INTEGER;
- (** Cleaner **)
- PROCEDURE (c: TrapCleaner) Cleanup;
- BEGIN
- par := NIL
- END Cleanup;
- (** Properties **)
- PROCEDURE (p: Prop) IntersectWith* (q: Properties.Property; OUT equal: BOOLEAN);
- VAR valid: SET;
- BEGIN
- WITH q: Prop DO
- valid := p.valid * q.valid; equal := TRUE;
- IF (cmd IN valid) & (p.cmd^ # q.cmd^) THEN EXCL(valid, cmd) END;
- IF (kind IN valid) & (p.link # q.link) THEN EXCL(valid, kind) END;
- IF (close IN valid) & (p.close # q.close) THEN EXCL (valid, close) END;
- IF p.valid # valid THEN p.valid := valid; equal := FALSE END
- END
- END IntersectWith;
-
- PROCEDURE (op: ChangeAttrOp) Do;
- VAR v: Views.View; s: POINTER TO ARRAY OF CHAR; c: INTEGER;
- BEGIN
- v := op.v;
- WITH
- | v: Link DO
- IF cmd IN op.valid THEN s := op.cmd; op.cmd := v.cmd; v.cmd := s END;
- IF close IN op.valid THEN c := op.close; op.close := v.close; v.close := c END
- | v: Target DO
- IF cmd IN op.valid THEN s := op.cmd; op.cmd := v.ident; v.ident := s END
- END
- END Do;
- PROCEDURE DoChangeAttrOp (v: Views.View; s: POINTER TO ARRAY OF CHAR; c: INTEGER; valid: SET);
- VAR op: ChangeAttrOp;
- BEGIN
- NEW(op); op.v := v; op.valid := valid;
- IF close IN valid THEN
- op.close := c END;
- IF cmd IN valid THEN NEW(op.cmd, LEN(s)+1); op.cmd^ := s$ END;
- Views.Do(v, "#Std:LinkChange", op)
- END DoChangeAttrOp;
-
- PROCEDURE SetProp(v: Views.View; msg: Properties.SetMsg);
- VAR p: Properties.Property;
- BEGIN
- p := msg.prop;
- WHILE p # NIL DO
- WITH p: Prop DO
- IF (cmd IN p.valid) OR (close IN p.valid) THEN DoChangeAttrOp(v, p.cmd, p.close, p.valid) END
- ELSE
- END;
- p := p.next
- END
- END SetProp;
-
- PROCEDURE PollProp(v: Views.View; VAR msg: Properties.PollMsg);
- VAR p: Prop;
- BEGIN
- NEW(p);
- WITH v: Link DO
- p.known := {kind, cmd, close};
- p.link := TRUE;
- p.cmd := v.cmd;
- p.close := v.close
- | v: Target DO
- p.known := {kind, cmd};
- p.link := FALSE;
- p.cmd := v.ident
- ELSE
- END;
- p.valid := p.known;
- Properties.Insert(msg.prop, p)
- END PollProp;
-
- PROCEDURE InitDialog*;
- VAR p: Properties.Property;
- BEGIN
- dialog.cmd := ""; dialog.type := ""; dialog.close.index := -1;
- dialog.known := {}; dialog.valid := {};
- Properties.CollectProp(p);
- WHILE p # NIL DO
- WITH p: Prop DO
- dialog.valid := p.valid; dialog.known := p.known;
- IF cmd IN p.valid THEN
- dialog.cmd := p.cmd$
- END;
- IF kind IN p.valid THEN
- IF p.link THEN Dialog.MapString("#Std:Link", dialog.type)
- ELSE Dialog.MapString("#Std:Target", dialog.type)
- END
- END;
- IF close IN p.valid THEN
- dialog.close.index := p.close
- END
- ELSE
- END;
- p := p.next
- END;
- Dialog.Update(dialog)
- END InitDialog;
-
- PROCEDURE Set*;
- VAR p: Prop;
- BEGIN
- NEW(p);
- p.valid := dialog.valid;
- IF cmd IN p.valid THEN
- NEW(p.cmd, LEN(dialog.cmd) + 1);
- p.cmd^ := dialog.cmd$
- END;
- p.close := dialog.close.index;
- Properties.EmitProp(NIL, p);
- fingerprint := 0 (* force actualization of fields *)
- END Set;
-
- PROCEDURE CmdGuard* (VAR par: Dialog.Par);
- VAR c: Containers.Controller; v: Views.View; fp: INTEGER;
- BEGIN
- IF ~(cmd IN dialog.known) THEN par.disabled := TRUE
- ELSIF ~(cmd IN dialog.valid) THEN par.undef := TRUE
- END;
- Controllers.SetCurrentPath(Controllers.targetPath);
- fp := 0;
- c := Containers.Focus();
- IF c # NIL THEN
- c.GetFirstView(Containers.selection, v);
- WHILE v # NIL DO fp := fp + Services.AdrOf(v); c.GetNextView(TRUE, v) END
- END;
- IF fp # fingerprint THEN fingerprint := fp; InitDialog END;
- Controllers.ResetCurrentPath()
- END CmdGuard;
-
- PROCEDURE CloseGuard* (VAR par: Dialog.Par);
- BEGIN
- IF ~(close IN dialog.known) THEN par.disabled := TRUE
- ELSIF ~(close IN dialog.valid) THEN par.undef := TRUE
- END;
- END CloseGuard;
-
- PROCEDURE Notifier* (idx, op, from, to: INTEGER);
- BEGIN
- IF op = Dialog.changed THEN INCL(dialog.valid, idx) END
- END Notifier;
- PROCEDURE (d: Directory) NewLink* (IN cmd: ARRAY OF CHAR): Link, NEW, ABSTRACT;
- PROCEDURE (d: Directory) NewTarget* (IN ident: ARRAY OF CHAR): Target, NEW, ABSTRACT;
- PROCEDURE InFrame (f: Views.Frame; x, y: INTEGER): BOOLEAN;
- BEGIN
- RETURN (f.l <= x) & (x < f.r) & (f.t <= y) & (y < f.b)
- END InFrame;
- PROCEDURE Mark (f: Views.Frame; show: BOOLEAN);
- BEGIN
- f.MarkRect(f.l, f.t, f.r, f.b, Ports.fill, Ports.hilite, show)
- END Mark;
- PROCEDURE ThisPos (v: TextViews.View; f: Views.Frame; x, y: INTEGER): INTEGER;
- (* "corrected" v.ThisPos: does not adjust position when crossing 50% boundary of characters *)
- VAR loc: TextViews.Location; pos: INTEGER;
- BEGIN
- pos := v.ThisPos(f, x, y); v.GetThisLocation(f, pos, loc);
- IF (loc.y <= y) & (y < loc.y + loc.asc + loc.dsc) & (x < loc.x) THEN DEC(pos) END;
- RETURN pos
- END ThisPos;
- PROCEDURE GetLinkPair (this: Link; VAR l, r: Link);
- (* POST: BalancedPair(l, r) & (l # r) & (l = this OR r = this) OR (l = r = NIL) *)
- VAR t: TextModels.Model; rd: TextModels.Reader; v: Views.View; level: INTEGER;
- BEGIN
- l := NIL; r := NIL; level := 1;
- IF (this.context # NIL) & (this.context IS TextModels.Context) THEN
- t := this.context(TextModels.Context).ThisModel();
- rd := t.NewReader(NIL);
- IF this.leftSide THEN
- rd.SetPos(this.context(TextModels.Context).Pos() + 1);
- REPEAT
- rd.ReadView(v);
- IF (v # NIL) & (v IS Link) THEN
- IF v(Link).leftSide THEN INC(level) ELSE DEC(level) END
- END
- UNTIL (v = NIL) OR (level = 0);
- IF v # NIL THEN l := this; r := v(Link) END
- ELSE
- rd.SetPos(this.context(TextModels.Context).Pos());
- REPEAT
- rd.ReadPrevView(v);
- IF (v # NIL) & (v IS Link) THEN
- IF v(Link).leftSide THEN DEC(level) ELSE INC(level) END
- END
- UNTIL (v = NIL) OR (level = 0);
- IF v # NIL THEN l := v(Link); r := this END
- END
- END
- END GetLinkPair;
- PROCEDURE GetTargetPair (this: Target; VAR l, r: Target);
- (* POST: BalancedPair(l, r) & (l # r) & (l = this OR r = this) OR (l = r = NIL) *)
- VAR t: TextModels.Model; rd: TextModels.Reader; v: Views.View; level: INTEGER;
- BEGIN
- l := NIL; r := NIL; level := 1;
- IF (this.context # NIL) & (this.context IS TextModels.Context) THEN
- t := this.context(TextModels.Context).ThisModel();
- rd := t.NewReader(NIL);
- IF this.leftSide THEN
- rd.SetPos(this.context(TextModels.Context).Pos() + 1);
- REPEAT
- rd.ReadView(v);
- IF (v # NIL) & (v IS Target) THEN
- IF v(Target).leftSide THEN INC(level) ELSE DEC(level) END
- END
- UNTIL (v = NIL) OR (level = 0);
- IF v # NIL THEN l := this; r := v(Target) END
- ELSE
- rd.SetPos(this.context(TextModels.Context).Pos());
- REPEAT
- rd.ReadPrevView(v);
- IF (v # NIL) & (v IS Target) THEN
- IF v(Target).leftSide THEN DEC(level) ELSE INC(level) END
- END
- UNTIL (v = NIL) OR (level = 0);
- IF v # NIL THEN l := v(Target); r := this END
- END
- END
- END GetTargetPair;
- PROCEDURE GetRange (l, r: Link; VAR beg, end: INTEGER);
- BEGIN
- beg := l.context(TextModels.Context).Pos();
- end := r.context(TextModels.Context).Pos() + 1
- END GetRange;
- PROCEDURE MarkRange (v: TextViews.View; f: Views.Frame; beg, end: INTEGER; show: BOOLEAN);
- VAR b, e: TextViews.Location; r, t: INTEGER;
- BEGIN
- ASSERT(beg < end, 20);
- v.GetThisLocation(f, beg, b); v.GetThisLocation(f, end, e);
- IF (b.pos < e.pos) OR (b.pos = e.pos) & (b.x < e.x) THEN
- IF b.start # e.start THEN
- r := f.r; t := b.y + b.asc + b.dsc;
- f.MarkRect(b.x, b.y, r, t, Ports.fill, Ports.hilite, show);
- IF t < e.y THEN f.MarkRect(0, t, r, e.y, Ports.fill, Ports.hilite, show) END;
- b.x := f.l; b.y := e.y
- END;
- f.MarkRect(b.x, b.y, e.x, e.y + e.asc + e.dsc, Ports.fill, Ports.hilite, show)
- END
- END MarkRange;
- PROCEDURE Reveal (left, right: Views.View; str: ARRAY OF CHAR; opname: Stores.OpName);
- VAR con: TextModels.Context; t: TextModels.Model; pos: INTEGER;
- w: TextMappers.Formatter; op: Stores.Operation;
- BEGIN
- con := left.context(TextModels.Context);
- t := con.ThisModel(); pos := con.Pos();
- w.ConnectTo(t); w.SetPos(pos);
- IF con.Attr() # NIL THEN w.rider.SetAttr(con.Attr()) END;
- Models.BeginScript(t, opname, op);
- t.Delete(pos, pos + 1);
- w.WriteChar("<");
- IF str # "" THEN w.WriteString(str) END;
- w.WriteChar(">");
- con := right.context(TextModels.Context);
- pos := con.Pos();
- w.SetPos(pos);
- IF con.Attr() # NIL THEN w.rider.SetAttr(con.Attr()) END;
- t.Delete(pos, pos + 1);
- w.WriteString("<>");
- Models.EndScript(t, op)
- END Reveal;
-
- PROCEDURE RevealCmd (v: Link);
- VAR left, right: Link;
- BEGIN GetLinkPair(v, left, right);
- IF left # NIL THEN
- IF v.cmd # NIL THEN Reveal(left, right, v.cmd^, "#StdLinks:Reveal Link Command")
- ELSE Reveal(left, right, "", "#StdLinks:Reveal Link Command")
- END
- END
- END RevealCmd;
- PROCEDURE RevealTarget (targ: Target);
- VAR left, right: Target;
- BEGIN GetTargetPair(targ, left, right);
- IF left # NIL THEN
- IF left.ident # NIL THEN Reveal(left, right, left.ident^, "#SdtLinks:Reveal Target Ident")
- ELSE Reveal(left, right, "", "#SdtLinks:Reveal Target Ident")
- END
- END
- END RevealTarget;
-
- PROCEDURE CallCmd (v: Link; close: BOOLEAN);
- VAR res: INTEGER;
- BEGIN
- Kernel.PushTrapCleaner(cleaner);
- par := v;
- IF v.cmd^ # "" THEN
- IF close & (v.close = ifShiftDown) OR (v.close = always) THEN
- StdCmds.CloseDialog
- END;
- Dialog.Call(v.cmd^, "#StdLinks:Link Call Failed", res)
- END;
- par := NIL;
- Kernel.PopTrapCleaner(cleaner)
- END CallCmd;
- PROCEDURE TrackSingle (f: Views.Frame; VAR in: BOOLEAN);
- VAR x, y: INTEGER; modifiers: SET; in0, isDown: BOOLEAN;
- BEGIN
- in := FALSE;
- REPEAT
- f.Input(x, y, modifiers, isDown);
- in0 := in; in := InFrame(f, x, y);
- IF in # in0 THEN Mark(f, in) END
- UNTIL ~isDown;
- IF in THEN Mark(f, FALSE) END
- END TrackSingle;
- PROCEDURE TrackRange (v: TextViews.View; f: Views.Frame; l, r: Link; x, y: INTEGER;
- VAR in: BOOLEAN);
- VAR pos, beg, end: INTEGER; modifiers: SET; in0, isDown: BOOLEAN;
- BEGIN
- in := FALSE;
- GetRange(l, r, beg, end); pos := ThisPos(v, f, x, y);
- IF (beg <= pos) & (pos < end) THEN
- REPEAT
- f.Input(x, y, modifiers, isDown); pos := ThisPos(v, f, x, y);
- in0 := in; in := (beg <= pos) & (pos < end);
- IF in # in0 THEN MarkRange(v, f, beg, end, in) END
- UNTIL ~isDown;
- IF in THEN
- MarkRange(v, f, beg, end, FALSE)
- END
- END
- END TrackRange;
- PROCEDURE Track (v: Link; f: Views.Frame; c: TextControllers.Controller;
- x, y: INTEGER; modifiers: SET);
- (* PRE: (c # NIL) & (f.view.ThisModel() = v.context.ThisModel()) OR (c = NIL) & (f.view = v) *)
- VAR l, r: Link; in: BOOLEAN;
- BEGIN
- GetLinkPair(v, l, r);
- IF l # NIL THEN
- IF c # NIL THEN TrackRange(c.view, f, l, r, x, y, in)
- ELSE TrackSingle(f, in)
- END;
- IF in THEN
- IF (Controllers.modify IN modifiers) & ((c = NIL) OR ~(Containers.noCaret IN c.opts)) THEN
- RevealCmd(l)
- ELSE
- CallCmd(l, Controllers.extend IN modifiers)
- END
- END
- END
- END Track;
- PROCEDURE TrackTarget (targ: Target; f: Views.Frame; modifiers: SET);
- VAR in: BOOLEAN;
- BEGIN
- TrackSingle(f, in);
- IF in & (Controllers.modify IN modifiers) THEN RevealTarget(targ) END
- END TrackTarget;
- PROCEDURE (v: Link) CopyFromSimpleView- (source: Views.View);
- BEGIN
- WITH source: Link DO
- ASSERT(source.leftSide = (source.cmd # NIL), 100);
- v.leftSide := source.leftSide;
- v.close := source.close;
- IF source.cmd # NIL THEN
- NEW(v.cmd, LEN(source.cmd^));
- v.cmd^ := source.cmd^$
- ELSE v.cmd := NIL
- END
- END
- END CopyFromSimpleView;
- PROCEDURE (t: Target) CopyFromSimpleView- (source: Views.View);
- BEGIN
- WITH source: Target DO
- ASSERT(source.leftSide = (source.ident # NIL), 100);
- t.leftSide := source.leftSide;
- IF source.ident # NIL THEN
- NEW(t.ident, LEN(source.ident^));
- t.ident^ := source.ident^$
- ELSE t.ident := NIL
- END
- END
- END CopyFromSimpleView;
- PROCEDURE (v: Link) Internalize- (VAR rd: Stores.Reader);
- VAR len: INTEGER; version: INTEGER; pos: INTEGER;
- BEGIN
- v.Internalize^(rd);
- IF rd.cancelled THEN RETURN END;
- rd.ReadVersion(minLinkVersion, maxLinkVersion, version);
- IF rd.cancelled THEN RETURN END;
- rd.ReadBool(v.leftSide);
- rd.ReadInt(len);
- IF len = 0 THEN v.cmd := NIL
- ELSE NEW(v.cmd, len); rd.ReadXString(v.cmd^)
- END;
- v.leftSide := v.cmd # NIL;
- IF v.leftSide THEN
- IF version = 1 THEN
- rd.ReadInt(v.close)
- ELSE
- Strings.Find(v.cmd, "StdLinks.ShowTarget", 0, pos);
- IF (pos # 0) THEN v.close := ifShiftDown
- ELSE v.close := never
- END
- END
- END
- END Internalize;
- PROCEDURE (v: Link) Externalize- (VAR wr: Stores.Writer);
- VAR pos, version: INTEGER;
- BEGIN
- v.Externalize^(wr);
- IF v.leftSide THEN
- Strings.Find(v.cmd, "StdLinks.ShowTarget", 0, pos);
- IF (pos = 0) & (v.close = never) OR (v.close = ifShiftDown) THEN version := 0
- ELSE version := 1
- END
- ELSE
- version := 0
- END;
- wr.WriteVersion(version);
- wr.WriteBool(v.cmd # NIL);
- IF v.cmd = NIL THEN wr.WriteInt(0)
- ELSE wr.WriteInt(LEN(v.cmd^)); wr.WriteXString(v.cmd^)
- END;
- IF version = 1 THEN wr.WriteInt(v.close) END
- END Externalize;
- PROCEDURE (t: Target) Internalize- (VAR rd: Stores.Reader);
- VAR len: INTEGER; version: INTEGER;
- BEGIN
- t.Internalize^(rd);
- IF rd.cancelled THEN RETURN END;
- rd.ReadVersion(minTargVersion, maxTargVersion, version);
- IF rd.cancelled THEN RETURN END;
- rd.ReadBool(t.leftSide);
- rd.ReadInt(len);
- IF len = 0 THEN t.ident := NIL
- ELSE NEW(t.ident, len); rd.ReadXString(t.ident^)
- END;
- t.leftSide := t.ident # NIL
- END Internalize;
- PROCEDURE (t: Target) Externalize- (VAR wr: Stores.Writer);
- BEGIN
- t.Externalize^(wr);
- wr.WriteVersion(maxTargVersion);
- wr.WriteBool(t.ident # NIL);
- IF t.ident = NIL THEN wr.WriteInt(0)
- ELSE wr.WriteInt(LEN(t.ident^)); wr.WriteXString(t.ident^)
- END
- END Externalize;
- PROCEDURE RestoreView (v: Views.View; f: Views.Frame; icon: ARRAY OF SHORTCHAR);
- VAR c: Models.Context; a: TextModels.Attributes; font: Fonts.Font; color: Ports.Color;
- asc, dsc, w: INTEGER;
- BEGIN
- c := v.context;
- IF (c # NIL) & (c IS TextModels.Context) THEN
- a := c(TextModels.Context).Attr();
- font := Fonts.dir.This(iconFont, a.font.size, {}, Fonts.normal);
- color := a.color
- ELSE font := Fonts.dir.Default(); color := Ports.black
- END;
- IF coloredBackg THEN
- f.DrawRect(f.l, f.t, f.r, f.b, Ports.fill, Ports.grey25) END;
- font.GetBounds(asc, dsc, w);
- f.DrawSString(1*Ports.mm DIV 2, asc, color, icon, font)
- END RestoreView;
- PROCEDURE (v: Link) Restore* (f: Views.Frame; l, t, r, b: INTEGER);
- BEGIN
- IF v.leftSide THEN RestoreView(v, f, linkLeft)
- ELSE RestoreView(v, f, linkRight)
- END
- END Restore;
- PROCEDURE (targ: Target) Restore* (f: Views.Frame; l, t, r, b: INTEGER);
- BEGIN
- IF targ.leftSide THEN RestoreView(targ, f, targetLeft)
- ELSE RestoreView(targ, f, targetRight)
- END
- END Restore;
- PROCEDURE SizePref (v: Views.View; icon: ARRAY OF SHORTCHAR; VAR msg: Properties.SizePref);
- VAR c: Models.Context; a: TextModels.Attributes; font: Fonts.Font;
- asc, dsc, w: INTEGER;
- BEGIN
- c := v.context;
- IF (c # NIL) & (c IS TextModels.Context) THEN
- a := c(TextModels.Context).Attr();
- font := Fonts.dir.This(iconFont, a.font.size, {}, Fonts.normal)
- ELSE
- font := Fonts.dir.Default()
- END;
- msg.w := font.SStringWidth(icon) + 1*Ports.mm;
- font.GetBounds(asc, dsc, w);
- msg.h := asc + dsc
- END SizePref;
-
- PROCEDURE (v: Link) HandlePropMsg- (VAR msg: Properties.Message);
- VAR a: TextModels.Attributes; c: Models.Context; asc, dsc, w: INTEGER; l, r: Link;
- BEGIN
- WITH msg: Properties.SizePref DO
- IF v.leftSide THEN SizePref(v, linkLeft, msg)
- ELSE SizePref(v, linkRight, msg)
- END
- | msg: Properties.FocusPref DO
- msg.hotFocus := TRUE
- | msg: Properties.ResizePref DO
- msg.fixed := TRUE
- | msg: TextModels.Pref DO
- msg.opts := {TextModels.hideable}
- | msg: TextControllers.FilterPref DO
- msg.filter := TRUE
- | msg: TextSetters.Pref DO c := v.context;
- IF (c # NIL) & (c IS TextModels.Context) THEN
- a := c(TextModels.Context).Attr();
- a.font.GetBounds(asc, dsc, w);
- msg.dsc := dsc
- END
- | msg: Properties.PollMsg DO
- IF v.leftSide THEN PollProp(v, msg)
- ELSE
- GetLinkPair(v, l, r);
- IF l # NIL THEN PollProp(l, msg) END
- END
- | msg: Properties.SetMsg DO
- IF v.leftSide THEN SetProp(v, msg)
- ELSE GetLinkPair(v, l, r); SetProp(l, msg)
- END
- ELSE
- END
- END HandlePropMsg;
-
- PROCEDURE (targ: Target) HandlePropMsg- (VAR msg: Properties.Message);
- VAR a: TextModels.Attributes; c: Models.Context; asc, dsc, w: INTEGER; l, r: Target;
- BEGIN
- WITH msg: Properties.SizePref DO
- IF targ.leftSide THEN SizePref(targ, targetLeft, msg)
- ELSE SizePref(targ, targetRight, msg)
- END
- | msg: Properties.FocusPref DO
- msg.hotFocus := TRUE
- | msg: Properties.ResizePref DO
- msg.fixed := TRUE
- | msg: TextModels.Pref DO
- msg.opts := {TextModels.hideable}
- | msg: TextSetters.Pref DO c := targ.context;
- IF (c # NIL) & (c IS TextModels.Context) THEN
- a := c(TextModels.Context).Attr();
- a.font.GetBounds(asc, dsc, w);
- msg.dsc := dsc
- END
- | msg: Properties.PollMsg DO
- IF targ.leftSide THEN PollProp(targ, msg)
- ELSE
- GetTargetPair(targ, l, r);
- IF l # NIL THEN PollProp(l, msg) END
- END
- | msg: Properties.SetMsg DO
- IF targ.leftSide THEN SetProp(targ, msg)
- ELSE GetTargetPair(targ, l, r); SetProp(l, msg)
- END
- ELSE
- END
- END HandlePropMsg;
- PROCEDURE (v: Link) HandleCtrlMsg* (f: Views.Frame;
- VAR msg: Controllers.Message; VAR focus: Views.View);
- PROCEDURE isHot(c: TextControllers.Controller; x, y: INTEGER; mod: SET): BOOLEAN;
- VAR pos, beg, end: INTEGER;
- BEGIN
- (* ignore alt, cmd, and middle clicks in edit mode *)
- IF ~(Containers.noCaret IN c.opts) & (mod * {17, 27, 28} # {}) THEN RETURN FALSE END;
- pos := ThisPos(c.view, f, x, y);
- (* ignore clicks in selection *)
- c.GetSelection(beg, end);
- IF (end > beg) & (pos >= beg) & (pos <= end) THEN RETURN FALSE END;
- IF v.leftSide THEN RETURN pos >= v.context(TextModels.Context).Pos()
- ELSE RETURN pos < v.context(TextModels.Context).Pos()
- END
- END isHot;
-
- BEGIN
- WITH msg: Controllers.PollCursorMsg DO
- msg.cursor := Ports.refCursor
- | msg: TextControllers.FilterPollCursorMsg DO
- IF isHot(msg.controller, msg.x, msg.y, {}) THEN
- msg.cursor := Ports.refCursor; msg.done := TRUE
- END
- | msg: Controllers.TrackMsg DO
- Track(v, f, NIL, msg.x, msg.y, msg.modifiers)
- | msg: TextControllers.FilterTrackMsg DO
- IF isHot(msg.controller, msg.x, msg.y, msg.modifiers) THEN
- Track(v, f, msg.controller, msg.x, msg.y, msg.modifiers);
- msg.done := TRUE
- END
- ELSE
- END
- END HandleCtrlMsg;
- PROCEDURE (targ: Target) HandleCtrlMsg* (f: Views.Frame; VAR msg: Controllers.Message;
- VAR focus: Views.View);
- BEGIN
- WITH msg: Controllers.TrackMsg DO TrackTarget(targ, f, msg.modifiers)
- ELSE
- END
- END HandleCtrlMsg;
- PROCEDURE (v: Link) GetCmd* (OUT cmd: ARRAY OF CHAR), NEW;
- BEGIN
- ASSERT(v.leftSide, 20);
- ASSERT(v.cmd # NIL, 100);
- cmd := v.cmd$
- END GetCmd;
- PROCEDURE (t: Target) GetIdent* (OUT ident: ARRAY OF CHAR), NEW;
- BEGIN
- ASSERT(t.leftSide, 20);
- ASSERT(t.ident # NIL, 100);
- ident := t.ident$
- END GetIdent;
- (* --------------- create commands and menu guards ------------------------ *)
- PROCEDURE GetParam (c: TextControllers.Controller; VAR param: ARRAY OF CHAR;
- VAR lbrBeg, lbrEnd, rbrBeg, rbrEnd: INTEGER);
- VAR rd: TextModels.Reader; i, beg, end: INTEGER;
- ch0, ch1, ch2: CHAR;
- BEGIN
- param[0] := 0X;
- IF (c # NIL) & c.HasSelection() THEN
- c.GetSelection(beg, end);
- IF end - beg > 4 THEN
- rd := c.text.NewReader(NIL);
- rd.SetPos(beg); rd.ReadChar(ch0);
- rd.SetPos(end-2); rd.ReadChar(ch1); rd.ReadChar(ch2);
- IF (ch0 = "<") & (ch1 = "<") & (ch2 = ">") THEN
- rd.SetPos(beg+1); rd.ReadChar(ch0); i := 0;
- WHILE ~rd.eot & (ch0 # ">") DO
- IF i < LEN(param) - 1 THEN param[i] := ch0; INC(i) END;
- rd.ReadChar(ch0)
- END;
- param[i] := 0X;
- lbrBeg := beg; lbrEnd := rd.Pos();
- rbrBeg := end -2; rbrEnd := end
- END
- END
- END
- END GetParam;
-
- PROCEDURE CreateGuard* (VAR par: Dialog.Par);
- VAR param: ARRAY 512 OF CHAR; lbrBeg, lbrEnd, rbrBeg, rbrEnd: INTEGER;
- BEGIN
- GetParam(TextControllers.Focus(), param, lbrBeg, lbrEnd, rbrBeg, rbrEnd);
- par.disabled := param = ""
- END CreateGuard;
- PROCEDURE InsertionAttr (c: TextControllers.Controller; pos: INTEGER): TextModels.Attributes;
- VAR rd: TextModels.Reader; r: TextRulers.Ruler; a: TextModels.Attributes; ch: CHAR;
- BEGIN
- rd := c.text.NewReader(NIL); a := NIL;
- rd.SetPos(pos); rd.ReadChar(ch); a := rd.attr;
- IF a = NIL THEN c.view.PollDefaults(r, a) END;
- RETURN a
- END InsertionAttr;
- PROCEDURE CreateLink*;
- VAR lbrBeg, lbrEnd, rbrBeg, rbrEnd: INTEGER;
- left, right: Link; c: TextControllers.Controller;
- cmd: ARRAY 512 OF CHAR;
- op: Stores.Operation;
- w: TextModels.Writer; a: TextModels.Attributes;
- BEGIN
- c := TextControllers.Focus();
- GetParam(TextControllers.Focus(), cmd, lbrBeg, lbrEnd, rbrBeg, rbrEnd);
- IF cmd # "" THEN
- w := c.text.NewWriter(NIL);
- Models.BeginScript(c.text, "#StdLinks:Create Link", op);
- a := InsertionAttr(c, rbrBeg);
- c.text.Delete(rbrBeg, rbrEnd);
- right := dir.NewLink("");
- w.SetPos(rbrBeg);
- IF a # NIL THEN w.SetAttr(a) END;
- w.WriteView(right, 0, 0);
- a := InsertionAttr(c, lbrBeg);
- c.text.Delete(lbrBeg, lbrEnd);
- left := dir.NewLink(cmd);
- w.SetPos(lbrBeg);
- IF a # NIL THEN w.SetAttr(a) END;
- w.WriteView(left, 0, 0);
- Models.EndScript(c.text, op)
- END
- END CreateLink;
- PROCEDURE CreateTarget*;
- VAR lbrBeg, lbrEnd, rbrBeg, rbrEnd: INTEGER;
- left, right: Target; c: TextControllers.Controller;
- ident: ARRAY 512 OF CHAR;
- op: Stores.Operation;
- w: TextModels.Writer; a: TextModels.Attributes;
- BEGIN
- c := TextControllers.Focus();
- GetParam(TextControllers.Focus(), ident, lbrBeg, lbrEnd, rbrBeg, rbrEnd);
- IF ident # "" THEN
- w := c.text.NewWriter(NIL);
- Models.BeginScript(c.text, "#StdLinks:Create Target", op);
- a := InsertionAttr(c, rbrBeg);
- c.text.Delete(rbrBeg, rbrEnd);
- right := dir.NewTarget("");
- w.SetPos(rbrBeg);
- IF a # NIL THEN w.SetAttr(a) END;
- w.WriteView(right, 0, 0);
- a := InsertionAttr(c, lbrBeg);
- c.text.Delete(lbrBeg, lbrEnd);
- left := dir.NewTarget(ident);
- w.SetPos(lbrBeg);
- IF a # NIL THEN w.SetAttr(a) END;
- w.WriteView(left, 0, 0);
- Models.EndScript(c.text, op)
- END
- END CreateTarget;
- PROCEDURE ShowTarget* (IN ident: ARRAY OF CHAR);
- VAR c: TextControllers.Controller; rd: TextModels.Reader;
- v: Views.View; left, right: Target; beg, end: INTEGER;
- BEGIN
- c := TextControllers.Focus();
- IF c # NIL THEN
- rd := c.text.NewReader(NIL);
- REPEAT rd.ReadView(v)
- UNTIL rd.eot OR (v # NIL) & (v IS Target) & v(Target).leftSide & (v(Target).ident^ = ident);
- IF ~rd.eot THEN
- GetTargetPair(v(Target), left, right);
- IF (left # NIL) & (right # NIL) THEN
- beg := left.context(TextModels.Context).Pos();
- end := right.context(TextModels.Context).Pos() + 1;
- c.SetSelection(beg, end);
- c.view.SetOrigin(beg, 0)
- ELSE
- Dialog.ShowParamMsg("target '^0' not found", ident, "", "")
- END
- ELSE
- Dialog.ShowParamMsg("target '^0' not found", ident, "", "")
- END
- END
- END ShowTarget;
- (* programming interface *)
- PROCEDURE (d: StdDirectory) NewLink (IN cmd: ARRAY OF CHAR): Link;
- VAR link: Link; i: INTEGER;
- BEGIN
- NEW(link); link.leftSide := cmd # "";
- IF link.leftSide THEN
- i := 0; WHILE cmd[i] # 0X DO INC(i) END;
- NEW(link.cmd, i + 1); link.cmd^ := cmd$
- ELSE
- link.cmd := NIL
- END;
- link.close := ifShiftDown;
- RETURN link
- END NewLink;
- PROCEDURE (d: StdDirectory) NewTarget (IN ident: ARRAY OF CHAR): Target;
- VAR t: Target; i: INTEGER;
- BEGIN
- NEW(t); t.leftSide := ident # "";
- IF t.leftSide THEN
- i := 0; WHILE ident[i] # 0X DO INC(i) END;
- NEW(t.ident, i + 1); t.ident^ := ident$
- ELSE
- t.ident := NIL
- END;
- RETURN t
- END NewTarget;
- PROCEDURE SetDir* (d: Directory);
- BEGIN
- ASSERT(d # NIL, 20);
- dir := d
- END SetDir;
- PROCEDURE Init;
- VAR font: Fonts.Font; d: StdDirectory;
- PROCEDURE DefaultAppearance;
- BEGIN font := Fonts.dir.Default(); iconFont := font.typeface;
- linkLeft := "Link"; linkRight := "~";
- targetLeft := "Targ"; targetRight := "~";
- coloredBackg := TRUE
- END DefaultAppearance;
- BEGIN
- NEW(d); dir := d; stdDir := d;
- IF Dialog.platform DIV 10 = 1 THEN (* Windows *)
- iconFont := "Wingdings";
- font := Fonts.dir.This(iconFont, 10*Fonts.point (*arbitrary*), {}, Fonts.normal);
- IF font.IsAlien() THEN DefaultAppearance
- ELSE
- linkLeft[0] := SHORT(CHR(246)); linkLeft[1] := 0X;
- linkRight[0] := SHORT(CHR(245)); linkRight[1] := 0X;
- targetLeft[0] := SHORT(CHR(164)); targetLeft[1] := 0X;
- targetRight[0] := SHORT(CHR(161)); targetRight[1] := 0X;
- coloredBackg := FALSE
- END
- ELSIF Dialog.platform DIV 10 = 2 THEN (* Mac *)
- DefaultAppearance
- ELSE
- DefaultAppearance
- END;
- NEW(cleaner);
- dialog.close.SetResources("#Std:links")
- END Init;
- BEGIN
- Init
- END StdLinks.
|