trestle_by_example/src/rubber/Rubber.m3


MODULE Rubber EXPORTS Main;
IMPORT Trestle, VBT, RigidVBT, BorderedVBT, Point, Rect, Path, Region,
       PaintOp;
FROM VBT IMPORT ClickType;
TYPE
  T = VBT.Leaf OBJECT
        nw, se : Point.T;
        path   : Path.T;
        banding            := FALSE;
      OVERRIDES
        repaint  := Repaint;
        mouse    := Mouse;
        position := Position;
      END;

PROCEDURE Repaint (v: T; READONLY rgn: Region.T) =
  BEGIN
    VBT.PaintRegion(v, rgn, PaintOp.Bg);
  END Repaint;

PROCEDURE Mouse (v: T; READONLY cd: VBT.MouseRec) =
  BEGIN
    IF (cd.clickType = ClickType.FirstDown) THEN
      v.banding := TRUE;
      v.nw := cd.cp.pt;
      Path.Reset(v.path);
      VBT.SetCage(v, VBT.CageFromPosition(cd.cp));
    ELSIF (v.banding AND cd.clickType = ClickType.LastUp) THEN
      v.banding := FALSE;
      v.se := cd.cp.pt;
    ELSIF (v.banding) THEN       (* Chord Cancel *)
      v.banding := FALSE;
    END;
  END Mouse;

PROCEDURE Position (v: T; READONLY cd: VBT.PositionRec) =
  BEGIN
    IF NOT v.banding THEN
      VBT.SetCage(v, VBT.EverywhereCage);
    ELSIF cd.cp.gone THEN
      VBT.SetCage(v, VBT.GoneCage)
    ELSE
      VBT.Stroke(v, Rect.Full, v.path, op := PaintOp.Swap); (* Erase old *)
      Path.Reset(v.path);
      Path.MoveTo(v.path, v.nw);
      Path.LineTo(v.path, Point.T{v.nw.h, cd.cp.pt.v});
      Path.LineTo(v.path, cd.cp.pt);
      Path.LineTo(v.path, Point.T{cd.cp.pt.h, v.nw.v});
      Path.Close(v.path);
      VBT.Stroke(v, Rect.Full, v.path, op := PaintOp.Swap); (* Draw new *)
      VBT.SetCage(v, VBT.CageFromPosition(cd.cp));
    END;
  END Position;

VAR
  leaf := NEW(T, path := NEW(Path.T));
  main := BorderedVBT.New(RigidVBT.FromHV(leaf, 35.0, 35.0));
BEGIN
  Trestle.Install(main);
  Trestle.AwaitDelete(main)
END Rubber.