-- File: Scratchpad2dUserImpl.mesa
-- Last edited by Bier on December 18, 1982 1:41 am
-- Author: Eric Bier on March 22, 1983 1:37 pm
-- Contents: Functions called by the buttons on a Scratchpad2d viewer.

DIRECTORY
 Containers,
 CoordSys,
 Graphics,
 Menus,
 PadGraphics,
 Scratchpad2dUser,
 SV2d,
 SVPolygon2d,
 SweepGeometry,
 SVDraw,
 SVLines2d,
 SVVector2d,
 ViewerClasses,
 ViewerOps;

Scratchpad2dUserImpl: CEDAR PROGRAM
IMPORTS Graphics, PadGraphics, SVDraw, SVLines2d, SVPolygon2d, SVVector2d, ViewerOps
EXPORTS Scratchpad2dUser =

BEGIN

CoordSystem: TYPE = REF CoordSysObj;
CoordSysObj: TYPE = CoordSys.CoordSysObj;
MouseButton: TYPE = Menus.MouseButton;
Path: TYPE = REF PathObj;
PathObj: TYPE = SV2d.PathObj;
Point2d: TYPE = SV2d.Point2d;
Polygon: TYPE = REF PolygonObj;
PolygonObj: TYPE = SV2d.PolygonObj;
TrigLineSeg: TYPE = SV2d.TrigLineSeg;
Vector2d: TYPE = SVVector2d.Vector2d;
Viewer: TYPE = ViewerClasses.Viewer;

ScratchViewerData: TYPE = REF ScratchViewerDataObj;
ScratchViewerDataObj: TYPE = Scratchpad2dUser.ScratchViewerDataObj;
TextSectionData: TYPE = REF TextSectionDataObj;
TextSectionDataObj: TYPE = Scratchpad2dUser.TextSectionDataObj;

ScratchpadData: TYPE = REF ScratchpadDataObj;
ScratchpadDataObj: TYPE = Scratchpad2dUser.ScratchpadDataObj;
  
ScratchpadMode: TYPE = {off, pointAt, draw};

squareSide: REAL = 6;

Painter: PUBLIC PROC [proc: PROC [Graphics.Context], scratchViewerData: ScratchViewerData ← NIL] = TRUSTED {
 scratchpadData: ScratchpadData ← NARROW[scratchViewerData.scratchpad.data];
 scratchpadData.proc ← proc;
 ViewerOps.PaintViewer[viewer: scratchViewerData.scratchpad,
        hint: client,
        whatChanged: scratchViewerData,
        clearClient: FALSE];
 }; -- end of Painter

PaintRevo: PUBLIC PROC [scratchViewerData: ScratchViewerData] = TRUSTED {
DoPaintRevo: PROC [dc: Graphics.Context] = TRUSTED {
  -- begin at y axis to show user how the final effect will look
  IF scratchpadData.path.len = 0 THEN RETURN;
  -- paint right side
  PadGraphics.MoveTo[dc, [0, scratchpadData.path[0][2]], scratchpadData.origin];
  PadGraphics.DrawSquare[dc, squareSide, [0, scratchpadData.path[0][2]], scratchpadData.origin];
  FOR i: NAT IN[0..scratchpadData.path.len) DO
   PadGraphics.DrawTo[dc, scratchpadData.path[i], scratchpadData.origin];
   PadGraphics.DrawSquare[dc, squareSide, scratchpadData.path[i], scratchpadData.origin];
  ENDLOOP;
    -- end at y axis to show user how the final sweep will look
  PadGraphics.DrawTo[dc, [0, scratchpadData.path[scratchpadData.path.len-1][2]],
   scratchpadData.origin];
  PadGraphics.DrawSquare[dc, squareSide, [0, scratchpadData.path[scratchpadData.path.len-1][2]],
   scratchpadData.origin];
  
  -- now paint left side
  PadGraphics.MirrorMoveTo[dc, [0, scratchpadData.path[0][2]], scratchpadData.origin];
  FOR i: NAT IN[0..scratchpadData.path.len) DO
   PadGraphics.MirrorDrawTo[dc, scratchpadData.path[i], scratchpadData.origin];
   PadGraphics.MirrorDrawSquare[dc, squareSide, scratchpadData.path[i], scratchpadData.origin];
  ENDLOOP;
    -- end at y axis to show user how the final sweep will look
  PadGraphics.MirrorDrawTo[dc,
   [0, scratchpadData.path[scratchpadData.path.len-1][2]],
      scratchpadData.origin];
  }; -- end of DoPaintRevo
 scratchpadData: ScratchpadData ← NARROW[scratchViewerData.scratchpad.data];
 Painter[DoPaintRevo, scratchpadData.scratchViewerData];
 }; -- end of PaintPoly

PaintLin: PUBLIC PROC [scratchViewerData: ScratchViewerData] = TRUSTED {
DoPaintLin: PROC [dc: Graphics.Context] = TRUSTED {
  -- paint right side
  IF scratchpadData.path.len = 0 THEN RETURN;
  PadGraphics.MoveTo[dc, scratchpadData.path[0], scratchpadData.origin];
  PadGraphics.DrawSquare[dc, squareSide, scratchpadData.path[0], scratchpadData.origin];
  FOR i: NAT IN[1..scratchpadData.path.len) DO
   PadGraphics.DrawTo[dc, scratchpadData.path[i], scratchpadData.origin];
   PadGraphics.DrawSquare[dc, squareSide, scratchpadData.path[i], scratchpadData.origin];
  ENDLOOP;
   PadGraphics.DrawTo[dc, scratchpadData.path[0], scratchpadData.origin];
  }; -- end of DoPaintLin
 scratchpadData: ScratchpadData ← NARROW[scratchViewerData.scratchpad.data];
 Painter[DoPaintLin, scratchpadData.scratchViewerData];
 }; -- end of PaintLin

Erase: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
 scratchViewerData: ScratchViewerData ← NARROW[clientData];
 scratchpadData: ScratchpadData ← NARROW[scratchViewerData.scratchpad.data];
DoErase: PROC [dc: Graphics.Context] = TRUSTED {
  Graphics.SetColor[dc, Graphics.white];
  Graphics.DrawBox[dc,Graphics.GetBounds[dc]];
  };
 Painter[DoErase, scratchViewerData];
};

Normals: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
-- go through each segment of the current picture. Find its outward pointing normal and draw it.
 scratchViewerData: ScratchViewerData ← NARROW[clientData];
 scratchpadData: ScratchpadData ← NARROW[scratchViewerData.scratchpad.data];
 path: Path ← scratchpadData.path;
 iPlusOne: NAT;
 p1, p2: Point2d;
 seg: TrigLineSeg;
 normal: Vector2d;
 midpoint: Point2d;
DoDrawNormals: PROC [dc: Graphics.Context] = TRUSTED {
  mark: Graphics.Mark ← Graphics.Save[dc];
  Graphics.SetColor[dc, Graphics.black];
  FOR i: NAT IN [0..path.len) DO
   iPlusOne ← IF i = path.len -1 THEN 0 ELSE i + 1;
   p1 ← path[i];
   p2 ← path[iPlusOne];
   seg ← SVLines2d.CreateTrigLineSeg[p1, p2];
   normal ← SVVector2d.LeftNormalOfTrigLineSeg[seg];
   midpoint[1] ← (p1[1]+p2[1])/2;
   midpoint[2] ← (p1[2] + p2[2])/2;
   PadGraphics.Draw2dVector[dc: dc, vec: normal, at: midpoint, origin: scratchpadData.origin];
  ENDLOOP;
  Graphics.SetColor[dc, Graphics.black];
  Graphics.Restore[dc,mark];
  };
 Painter[DoDrawNormals, scratchViewerData];
};

PlaceOrigin: PUBLIC PROC [viewer: Viewer] = TRUSTED {
-- viewer is the scratchpad window
-- find the center of the scratchpad window in scratchpad window coordinates
 originX, originY: INTEGER;
 scratchpadData: ScratchpadData ← NARROW[viewer.data];
 originX ← viewer.cw; -- convert window width to real
 originY ← viewer.ch; -- convert window height to real
 originX ← originX/2; -- find the midpoint in window coords
 originY ← originY/2;
 scratchpadData.origin ← [originX, originY];
 };

CrossHairs: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
DoCrossHairs: PROC [dc: Graphics.Context] = TRUSTED {
  PadGraphics.CrossHairs[dc, scratchpadData.origin];
  };
 scratchViewerData: ScratchViewerData ← NARROW[clientData];
 scratchpadData: ScratchpadData ← NARROW[scratchViewerData.scratchpad.data];
 Painter[DoCrossHairs, scratchViewerData];
 };

DrawScene: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
 scratchViewerData: ScratchViewerData ← NARROW[clientData];
 scratchpadData: ScratchpadData ← NARROW[scratchViewerData.scratchpad.data];
 Erase[parent, clientData, mouseButton, shift, control];
 CrossHairs[parent, clientData, mouseButton, shift, control];
SELECT scratchpadData.mode FROM
  drawLin => PaintLin[scratchViewerData];
  drawRevo =>PaintRevo[scratchViewerData];
ENDCASE;
 };

DrawLin: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
 scratchViewerData: ScratchViewerData ← NARROW[clientData];
 Erase[parent, clientData, mouseButton, shift, control];
 CrossHairs[parent, clientData, mouseButton, shift, control];
 PaintLin[scratchViewerData];
 };

DrawRevo: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
 scratchViewerData: ScratchViewerData ← NARROW[clientData];
 Erase[parent, clientData, mouseButton, shift, control];
 CrossHairs[parent, clientData, mouseButton, shift, control];
 PaintRevo[scratchViewerData];
 };

NewLin: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
 currentState: ScratchViewerData ← NARROW[clientData];
 scratchpadData: ScratchpadData ←
  NARROW[currentState.scratchpad.data];
 scratchpadData.mode ← drawLin;
 SVPolygon2d.ClearPath[scratchpadData.path];
 DrawScene[parent, clientData, mouseButton, shift, control];
 }; -- end of NewLine

NewRevo: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
 currentState: ScratchViewerData ← NARROW[clientData];
 scratchpadData: ScratchpadData ←
  NARROW[currentState.scratchpad.data];
 scratchpadData.mode ← drawRevo;
 SVPolygon2d.ClearPath[scratchpadData.path];
 DrawScene[parent, clientData, mouseButton, shift, control];
 }; -- end of NewRevo

TestPoints: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
 currentState: ScratchViewerData ← NARROW[clientData];
 scratchpadData: ScratchpadData ←
  NARROW[currentState.scratchpad.data];
 scratchpadData.mode ← pointAt;
 }; -- end of TestPoints

Circle: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
 scratchViewerData: ScratchViewerData ← NARROW[clientData];
 scratchpadData: ScratchpadData ← NARROW[scratchViewerData.scratchpad.data];
DoDrawCircle: PROC [dc: Graphics.Context] = TRUSTED {
  SVDraw.Circle[dc, scratchpadData.origin[1], scratchpadData.origin[2], 100];
  };
 Painter[DoDrawCircle, scratchViewerData];
 }; -- end of Circle

EditMode: TYPE = Scratchpad2dUser.EditMode; -- {lin, revo};

Edit: PUBLIC PROC [path: Path, mode: EditMode, scratchViewerData: ScratchViewerData] = TRUSTED {
 scratchpad: ViewerClasses.Viewer ← scratchViewerData.scratchpad;
 scratchpadData: ScratchpadData ← NARROW[scratchpad.data];
 scratchpadData.path ← path;
SELECT mode FROM
 lin => {scratchpadData.mode ← drawLin;
    DrawLin [scratchpad, scratchpadData.scratchViewerData, red, FALSE, FALSE];
    };
 revo => {scratchpadData.mode ← drawRevo;
    DrawRevo [scratchpad, scratchpadData.scratchViewerData, red, FALSE, FALSE];
    };
ENDCASE => ERROR;
 }; -- end of Edit

END.