14.1 Bifrost Interface

ORIGIN '~beta/guienv/guienv';
LIB_DEF 'bifrost' '../lib';
BODY 'private/Impl/BifrostImpl';
INCLUDE '~beta/containers/list';
INCLUDE '~beta/basiclib/math';

(* Bifrost - An Interactive Object Oriented Device 
 * Independent Graphics System
 *
 * Refer to   DAIMI IR-100 - Internal Report
 *            Computer Science Department
 *            Aarhus University, Denmark
 *                    
 * COPYRIGHT
 *       Copyright Mjolner Informatics, 1990-94
 *       All rights reserved.
 *)

14.2 Various Simple Definitions

-- BifrostAttributes: attributes --
(* Specifications used to test for key and/or pointer modification *)
Modifier: 
  (# m: @Integer; enter m do INNER exit m #);
NoModifier: Modifier
  (# ... #);
ShiftModifier: Modifier
  (# ... #);
ControlModifier: Modifier
  (# ... #);
LockModifier: Modifier
  (# ... #);
MetaModifier: Modifier
  (# ... #);
CommandModifier: Modifier
  (# ... #);

(* Constants used to specify fill rules *)
EvenOddRule: (# exit 0 #);
WindingRule: (# exit 1 #);

(* Cap styles *)
CapStyleDesc: (# s: @integer; enter s do INNER exit s #);

CapButt: CapStyleDesc(# ... #);
CapRounded: CapStyleDesc(# ... #);
CapSquare: CapStyleDesc(# ... #);

(* Join styles *)
JoinStyleDesc: (# s: @integer; enter s do INNER exit s #);
JoinMiter: JoinStyleDesc(# ... #);
JoinRound: JoinStyleDesc(# ... #);
JoinBevel: JoinStyleDesc(# ... #);

(* Fontnames to use in TextShape and GraphicText *)
fontName: integerObject(# do INNER #);
Courier: fontname(# ... #);
Times: fontname(# ... #);
Helvetica: fontname(# ... #);

(* Styles to use in TextShape and GraphicText *)
Style: integerObject(# do INNER #);
Plain: Style(# ... #);
Italic: Style(# ... #);
Bold: Style(# ... #);

MaxRGB: (* The upper limit for the range of RGB values *)
  (# max: @Integer
    ... (* Device dependent *)
  exit max
  #);

(* Constants specifying the range for hue, saturation and value *)
DefaultMaxHue: (# exit 360 #);
DefaultMaxSat: (# exit 32768 #); (* (2^15) *)
DefaultMaxVal: (# exit 32768 #); (* (2^15) *)

UnImplemented:
  (* Used to notify the user on features, that are not yet 
   * implemented in Bifrost.
   *)
  (# feature: ^text
  enter feature[]
  ...
  #);
DebugGraphic: (# exit false #);


14.3 Mathematics

Point: 
  (# x, y: @integer;
  enter (x,y)
  exit (x,y)
  #);
Vector: 
  (# x,y: @Real;
  enter (x,y)
  exit (x,y)
  #);
Rectangle: 
  (# x,y: @Integer (* Upper left *);
     width,height: @Integer
  enter (x,y,width,height)
  exit (x,y,width,height)
  #);
EqualPoint: 
  (# p1,p2: @Point;
  enter (p1,p2)
  exit (p1.x=p2.x) and (p1.y=p2.y)
  #);
AddPoints: 
  (# p1,p2: @Point;
  enter (p1,p2)
  exit (p1.x+p2.x,p1.y+p2.y)
  #);
SubPoints: 
  (# p1,p2: @Point;
  enter (p1,p2)
  exit (p1.x-p2.x,p1.y-p2.y)
  #);
ExpandRectangle: 
  (# r: @rectangle;
     e: @integer;
  enter (r,e)
  exit (r.x-e, r.y+e, r.width+2*e, r.height+2*e)
  #);
PointInRect: 
  (# p: @Point;
     r: @Rectangle;
  enter (p,r)
  exit   ((r.x <= p.x) and (p.x <= r.x+r.width) and
     (r.y >= p.y) and (p.y >= r.y-r.height))
  #);
Matrix: 
  (# a,b,c,d,tx,ty: @Real;
     (*   a  b  0
      *   c  d  0
      *   tx ty 1
      *)
     set: 
       (# enter (a,b,c,d,tx,ty) #);
     invalidate:
       (* Call invalidate if you manipulate a, b, c, d, tx, or ty *)
       ...;
     transformPoint: @
       (# p,result: @Point;
       enter p
       ...
       exit result
       #);
     inverseTransformPoint: @
       (# p1,p2: @Point;
       enter p1
       ...
       exit p2
       #);
     transformRectangle: @
       (# r,result: @Rectangle;
       enter r
       do ...
       exit result
       #);
     inverseTransformRectangle: 
       (# r,result: @Rectangle;
       enter r
       ...
       exit result
       #);
     getInverse: @
       (# get: @...;
          inverse: ^Matrix;
       do get;
       exit inverse[]
       #);
     private: @...;
  do INNER;
  exit (a,b,c,d,tx,ty)
  #);
IDMatrix:
  (* Exit an identity matrix *)
  (# ID: ^Matrix 
  ...
  exit ID[]
  #);
MoveMatrix: Matrix   (* A matrix specifying a translation *)
  (# itx,ity: @Integer;
  enter (itx,ity)
  ...
  #);
ScaleMatrix: Matrix  (* A matrix specifying a scaling *)
  (# 
  enter (a,d)
  ...
  #);
RotateMatrix: Matrix (* A matrix specifying a rotation *)
  (# theta: @Real;
  enter theta
  ...
  #);
MatrixMul: (* Multiply two matrices *)
  (# A,B,res: ^Matrix;
  enter (A[],B[])
  ...
  exit res[]
  #);
EllipseAngle: 
  (* Returns the angle a (in radians) and cos(a), sin(a), 
   * assuming that (x,y) is a point on the ellipse with center in
   * (cx,cy) and horizontal radius hr and verticalradius vr,
   * i.e. (x,y) = (cx,cy) + (hr*cos(a),vr*sin(a))
   *)
  (# cx, cy, hr, vr, x, y: @integer;
     a, cos_a, sin_a: @real;
     angle: @...;
  enter (cx, cy, hr, vr, x, y)
  do angle
  exit (a, cos_a, sin_a)
  #);
CircleAngle: 
  (* Returns the angle a (in radians) and cos(a), sin(a), 
   * assuming that (x,y) is a point on the circle with center in
   * (cx,cy) and radius r, for some r
   * i.e. (x,y) = (cx,cy) + (r*cos(a),r*sin(a))
   *)
  (# cx, cy, x, y: @integer;
     a, cos_a, sin_a: @real;
     angle: @...;
  enter (cx, cy, x, y)
  do angle
  exit (a, cos_a, sin_a)
  #);

14.4 Datatypes

PointArray: (* Array of points, extended when needed *)
  (# <<SLOT PointArrayAttributes: Attributes >>;
     
     npoints: @Integer
       (* Number of points currently in THIS(PointArray) *);
     
     initPoints: (* Must be called first *)
       (# initialsize: @integer;
       enter initialsize
       do ...;
       #);
     copy: (* Return a deep copy of THIS(PointArray) *)
       (# p: ^PointArray;
       ...
       exit p[]
       #);
     scanPoints:
       (* scan the points in THIS(PointArray).  Inx will be the index
        * of current
        *)
       (# current: ^Point; inx: @integer
         ...
       #);
     addPoint: @(* Add p as the last point in THIS(PointArray) *)
       (# p: @Point; 
       enter p
       do ...;
       #);
     deletePoint: @(* delete the i'th point in THIS(PointArray) *)
       (# i: @Integer; 
       enter i
       do ...;
       #);
     insertPoint: @(* insert p between the i'th and i+1'th point in THIS(PointArray) *)
       (# i: @Integer; p: @Point; 
       enter (p, i)
       do ...;
       #);
     getPoint: @
       (* Return point no i in THIS(PointArray); 1<=i<=npoints *)
       (# i: @Integer;
          p: @Point;
       enter i
       ...
       exit p
       #);
     setPoint: @
       (* Change the value of point no i to p; 1<=i<=npoints *)
       (# i: @Integer;
          p: @Point;
       enter (p,i)
       do ...;
       #);
     firstPoint: @(* Return first point of THIS(PointArray) *)
       (# exitPoint: @Point;
       ...
       exit exitPoint
       #);
     lastPoint: @(* Return last point of THIS(PointArray) *)
       (# exitPoint: @Point;
       ...
       exit exitPoint
       #);
     
     private: @...;
  #);


TextList: list
  (# element:: Text;
     copy:<(# c: ^TextList;
       ...
       exit c[]
       #);
  do INNER;
  #);


IntegerList: list
  (# IntegerElement: (# i: @integer #);
     element:: IntegerElement;
  #);

PointArrayList: (* List of PointArrays, used internally *)
  (#
     private: @...;
     appendPointArray: 
       (# p: ^PointArray;
       enter p[]
       ... 
       #);
     scanPointArrays: 
       (# p: ^PointArray;
       ... 
       #);
     empty: booleanValue 
       (# ... #);
  #);

14.5 Segment

Segment: 
  (# <<SLOT SegmentAttributes: attributes>>;
     
     firstPoint:< 
       (# p: @Point do INNER exit p #);
     lastPoint:< 
       (# p: @Point do INNER exit p#);
     setFirstPoint:< 
       (# p: @Point enter p do INNER #);
     setLastPoint:< 
       (# p: @Point enter p do INNER #);
     nextToFirstPoint:< 
       (# p: @Point do INNER exit p #);
     nextToLastPoint:< 
       (# p: @Point do INNER exit p #);
     copy:< (* Returns a deep copy of THIS(Segment) *)
       (# aCopy: ^Segment;
       ...
       exit aCopy[]
       #);
     transform:<
       (* Transform all control points in THIS(Segment) by M *)
       (# M: ^Matrix enter M[] do INNER #);
     reverseOrientation:< object;
     
     (* INTERACTION *)
     drawRubberBand:< 
       (* Draw an thin curve along THIS(Segment).  Useful when
        * drawing rubber feedback
        *) 
       (# theCanvas: ^BifrostCanvas
            (* The BifrostCanvas to draw the rubberband on *);
          newPoint: @Point;
          theGOToDevice: ^Matrix;
          controlIndex: @Integer;
          nextSeg: ^Segment;
       enter 
          (theCanvas[],theGOToDevice[],
          newPoint,controlIndex,nextSeg[])
       do INNER
       #);
     getControls:< 
       (* Add all the defining points in THIS(Segment) to spots.  If
        * spots[] is NONE, a PointArray is instantiated.  canvasTM is
        * applied to all controls before they are appended to spots.
        * If canvasTM[] is NONE, IDmatrix is used.
        *)
       (# spots: ^PointArray;
          canvasTM: ^Matrix;
       enter (spots[], canvasTM[])
       ... 
       exit spots[]
       #);
     
     (* PRIVATE, but virtual and hence cannot be in slots *)
     prepareReshape:< (* private *)
       (# theGOToDevice: ^Matrix;
          controlIndex: @Integer;
          nextSeg: ^Segment;
          movingp: @Point;
          theCanvas: ^BifrostCanvas;
       enter (theCanvas[],theGOToDevice[],controlIndex,nextSeg[])
       do INNER;
       #);
     endReshape:< (* private *)
       (# theGOToDevice: ^Matrix;
          finalPoint: @Point;
          controlIndex: @Integer;
          nextSeg: ^Segment;
          theCanvas: ^BifrostCanvas;
       enter 
          (theCanvas[],theGOToDevice[],finalPoint,controlIndex,nextSeg[])
       do INNER;
       #);
     findSegments:< (* private *)
       (# p: @point;
          s1,s2: ^Segment;
          controlIndex: @Integer;
       enter p
       do INNER
       exit (s1[],s2[],controlIndex)
       #);
     calculatePoints:< (* private *)
       (# thePoints: ^PointArray;
          thePointList: ^PointArrayList;
       enter (thePoints[],thePointList[])
       do INNER;
       exit thePointList[]
       #);
     makeOffset:< (* private *)
       (# nextPoint: @Point;
          offsets: ^PointArray;
          width: @Integer;
       enter (offsets[],nextPoint)
       do INNER;
       #);
     makeSecondOffset:< (* private *)
       (# theShape: ^Shape;
          index: @Integer;
          offsets: ^PointArray;
       enter (theShape[],offsets[],index)
       do INNER;
       exit index
       #);
     writePS:<
       (# out: ^stream enter out[] do INNER #);
  do INNER;
  exit THIS(Segment)[]
  #);


14.6 Line- and Spline Segments

LineSegment: Segment
  (# 
     begin,end: @Point;
     firstPoint::< (# do begin -> p #);
     lastPoint::< (# do end -> p #);
     setFirstPoint::< (# do p -> begin #);
     setLastPoint::< (# do p -> end #);
     nextToFirstPoint::< (# do end -> p; #);
     nextToLastPoint::< (# do begin -> p #);
     
     copy::< 
       (# do INNER; ... #);
     transform::< 
       (# ... #);
     reverseOrientation::< 
       (# ... #);
     
     (* INTERACTION *)
     drawRubberBand::< 
       (# ... #);
     getControls::<
       (# ... #);
     
     (* PRIVATE, but virtual and hence cannot be in slots *)
     writePS::<
       (# do ... #);
     prepareReshape::< (* private *)
       (# ... #);
     endReshape::< (* private *)
       (# ... #);
     findSegments::< (* private *)
       (# ... #);
     calculatePoints::< (* private *)
       (# ... #);
     makeOffset::< (* private *)
       (# do ... #);
     makeSecondOffset::< (* private *)
       (# do ... #);
  #);

14.7 Splinesegment

SplineSegment: Segment  (* abstract pattern *)
  (# <<SLOT SplineAttributes: Attributes >>;
     
     controls: ^PointArray;
     smoothness: @Real 
       (* default 1.0 decrease to get a smoother spline increase to
        * get a coarser spline
        *);
     
     firstPoint::< 
       (# ... #);
     lastPoint::< (# ... #);
     setFirstPoint::< 
       (# ... #);
     setLastPoint::< 
       (# ... #);
     nextToFirstPoint::<
       (# ... #);
     
     open:< 
       (* Prepare THIS(SplineSegment) for adding control points *)
       (# startPoint: @Point;
       enter startPoint
       ...
       #);
     addControl:< 
       (* Add p as a control point in THIS(SplineSegment) *)
       (# p: @Point;
       enter p ...
       #);
     insert:< 
       (* Insert p as a control point after the control point at
        * position index
        *) 
       (# p: @point;
          index: @integer;
       enter (p,index)
       do INNER
       #);
     delete:< 
       (* Delete the control point at position index *)
       (# index: @integer;
       enter index
       do INNER
       #);
     copy::< 
       (# do INNER; ... #);
     transform::< 
       (# ... #);
     reverseOrientation::< 
       (# do ... #);
     
     (* PRIVATE *)
     writePS::<
       (# do ... #);
     prepareReshape::< (* private *)
       (# ... #);
     endReshape::< (* private *)
       (# ... #);
     DrawRubberSplineDesc:< (* private *)
       (# track: @Point;
          controlIndex: @Integer;
          theCanvas: ^BifrostCanvas;
       enter (theCanvas[],track,controlIndex)
       do INNER
       #);
     calculatePoints::< (* private *)
       (# splinePoints: ^PointArray;
       ...
       #);
     splineprivate: @...;
     
  do INNER;
  #); (* SplineSegment *)

14.8 CircularSplineSegment

CircularSplineSegment: SplineSegment
  (# nextToLastPoint::< 
       (# ... #);
     copy::<
       (# do ... #);
     drawRubberBand::< 
       (# ... #);
     
     (* PRIVATE *)
     writePS::<
       (# do ... #);
     DrawRubberSplineDesc::< (* private *)
       (# do ... #);
     findSegments::< (* private *)
       (# ... #);
     calculatePoints::< (* private *)
       (# ... #);
     getControls::< (* private *)
       (# ... #);
     makeOffset::< (* private *)
       (# do ... #);
     makeSecondOffset::< (* private *)
       (# do ... #);
  do INNER;
  #);


14.9 NoncircularSplineSegment

NonCircularSplineSegment: SplineSegment
  (# nextToLastPoint::< 
       (# ... #);
     copy::< 
       (# do ... #);
     close: 
       (# ... #);
     isClosed: booleanValue
       (#  ... #);
     open::< 
       (#
       ...
       #);
     addControl::< 
       (#
       ... 
       #);
     drawRubberBand::< 
       (# ... #);
     
     (* PRIVATE *)
     writePS::<
       (# do ... #);
     private: @...;
     DrawRubberSplineDesc::< (* private *)
       (# do ... #);
     findSegments::< (* private *)
       (# ... #);
     calculatePoints::< (* private *)
       (# ... #);
     getControls::< (* private *)
       (# ... #);
     makeOffset::< (* private *)
       (# do ... #);
     makeSecondOffset::< (* private *)
       (# do ...#);
  do INNER;
  #);

14.10 AbstractShape

AbstractShape: Segment
  (# <<SLOT AShapeAttributes: attributes >>;
     
     copy::< 
       (# do INNER; ... #);
     fillRule: @
       (* Rule to determine what is inside and what is outside
        * THIS(AbstractShape). Used, e.g. when filling
        * THIS(AbstractShape) with some Paint. Defaults to 
        * WindingRule.
        *)
       (# r: @Integer;
          changed: @Boolean;  (* initialized as false *)
          changeRule: (# enter r do True -> changed #);
       enter changeRule
       do (if not changed then WindingRule -> r if);
       exit r
       #);
     invalidate:< 
       (* invalidate THIS(AbstractShape), so it will be recalculated
        * next time used in fill or clip operation.
        *)
       (# ... #);
     invalid: 
       (* Answer true if THIS(AbstractShape) has been invalidated *)
       (# b: @Boolean;
       ... 
       exit b
       #);
     getBounds:< 
       (* Return the bounding box of THIS(AbstractShape) *)
       (# bound: @rectangle;
       ...
       exit bound
       #);
     
     (* QUERY *)
     containsPoint:< booleanValue
       (* Answer whether thePoint is inside THIS(AbstractShape),
        * thePoint is assumed to be in coordinates relative to 
        * theCanvas.
        *)
       (# theCanvas: ^BifrostCanvas;
          thePoint: @Point;
       enter (theCanvas[],thePoint)
       ...
       #);
     hotspot: @
       (* The default value of hotspot is firstpoint *)
       (# p: @Point;
          changed: @Boolean;  (* initialized as false *)
          changeHotspot: (# enter p do True -> changed #);
       enter changeHotspot
       do (if not changed then firstPoint -> p if);
       exit p
       #);
     
     (* HIGHLIGHTING *)
     hiliteDesc: (* Qualification for highlighting patterns *)
       (# doneInInner: @boolean;
          theCanvas: ^BifrostCanvas
            (* The BifrostCanvas to do the highlighting on *);
          draw: @boolean
            (* Should the feedback be drawn or erased ? *);
          TM: ^Matrix
            (* TM is applied before the feedback is drawn *);
          copy:< (* Return a deep copy of THIS(HiliteDesc) *)
            (# aCopy: ^hiliteDesc;
            ...
            exit aCopy[]
            #);
       enter (theCanvas[], draw, TM[])
       ...
       #);
     
     (* PREDEFINED HIGHLIGHTING PATTERNS *)
     
     hiliteControls:< hiliteDesc
       (* Highlight control points *)
       (# copy::< (# do INNER; ... #);
       do INNER; ... #);
     hiliteOutline:< hiliteDesc
       (* Highlight outline of THIS(AbstractShape). To be further
        * bound
        *)
       (# hiliteWidth: @integer
            (* The width of the lines used when highlighting outline.
             * 0 means as thin as possible (default).  Should be the
             * same as the corresponding hilitewidth.
             *);
          copy::< (# do ... #);
       do INNER
       #);
     hiliteBound:< hiliteDesc
       (* Highlight bounding box *)
       (# Width: @integer;
          copy::< (# ... #);
       do INNER; ...;
       #);
     
     (* The actual highlight patterns used.  drawhilite points to one
      * of hc, ho, hb or some user supplied specialization of
      * hilitedesc
      *)
     hc, ho, hb: ^hiliteDesc;
     drawHilite: ^hiliteDesc;
     
     (* DEFINITION LANGUAGE *)
     open:< (* Must be called first *)
       (# p: @Point enter p ... #);
     
     (* INTERACTION *)
     Interaction: 
       (* Prefix for interaction patterns *)
       (# theCanvas: ^BifrostCanvas;
          theModifier: @Modifier;
          startPoint: @Point;
       enter (theCanvas[], startPoint, theModifier)
       do INNER;
       #);
     InteractiveCreate:< Interaction 
       (* Provide feedback for creating THIS(AbstractShape)
        * interactively.  Make the feedback constrained if 
        * theModifier is on. Start the interaction in startpoint.
        *);
     InteractiveCombine:< Interaction
       (* Create a Shape interactively and combine that Shape with
        * THIS(AbstractShape).  Make the feedback constrained if
        * theModifier is on. Start the interaction in startpoint.
        *);
     InteractiveReshape:< Interaction
       (* Provide feedback for reshaping THIS(AbstractShape)
        * interactively.  Make the feedback constrained if 
        * theModifier is on. Start the interaction in startpoint.
        *);
     
     transform::< 
       (# ... #);
     getcontrols::< 
       (# ... #);
     
     (* PRIVATE *)
     writePS::<
       (# 
          invisible: @boolean;
       enter invisible
       do INNER
       #);
     privatePart: @...;
     calculatePoints::< (* private *)
       (# do ... #);
     
  do INNER;
  #); (* Abstract Shape *)

14.11 Shape

Shape: AbstractShape
  (* For making user defined objects *)
  (# <<SLOT ShapeAttributes: attributes >>;
     copy::< 
       (# do INNER; ... #);
     getBounds::< 
       (# ... #);
     containsPoint::< 
       (# do ...; INNER #);
     currentPoint:< (* The last control point added *)
       (# p: @Point;
       do ...; INNER;
       exit p
       #);
     firstPoint::< 
       (# do ...; INNER #);
     lastPoint::< 
       (# ... #);
     nextToFirstPoint::<
       (# ... #);
     nextToLastPoint::< 
       (# ... #);
     open::< 
       (# ... #);
     
     (* DEFINITION LANGUAGE *)
     addSpline: 
       (* Add Spline beginning at currentpoint.  Spline.lastpoint
        * becomes new currentpoint
        *)
       (# Spline: ^SplineSegment;
       enter spline[]
       do ...;
       #);
     lineTo: 
       (* If currentPoint is a control point in a spline being
        * defined with splineTo, that spline is ended.  Add a
        * LineSegment beginning at currentPoint and ending at p.  p
        * becomes new currentPoint.
        *)
       (# p: @Point;
       enter p
       do ...;
       #);
     splineTo: 
       (* If currentPoint is the end point in a line segment, a new
        * spline segment is opened. That spline segment becomes the
        * "current spline segment". Add currenPoint as the first
        * control point of the current spline segment.  Add p as a
        * control point to the current spline segment.  p becomes new
        * currentPoint.
        *)
       (# p: @Point;
       enter p
       ... 
       #);
     close:< (* Should be called after the definition is finished *)
       (# ... #);
     
     (* QUERY FUNCTIONS *)
     isClosed: booleanValue 
       (* NOTICE: an empty shape is considered closed!!*)
       (# ... #);
     isEmpty: booleanValue 
       (# ... #);
     isFlat: booleanValue
       (* THIS(AbstractShape) is flat iff it contains no splines *)
       (# ... #);
     
     (* MANIPULATING THE SHAPE *)
     reverseOrientation::< 
       (# do ...; INNER #);
     stroke: 
       (* Change THIS(Shape) to be the shape obtained by stroking a
        * "pen" with the witdh W along THIS(Shape).  When stroking an
        * open Shape, the look of the "ends" of the resulting shape 
        * is specified with capStyle.  At joining points the joining
        * style is specified by joinStyle.
        *)
       (# W: @Integer; 
          capstyle: @capstyledesc; 
          joinstyle: @joinstyledesc;
       enter (W, capstyle, joinstyle)
       do ...;  
       #);
     insert: (* Not Yet Implemented *)
       (* If p1 is in the neighborhood of an existing control point,
        * P2 is added as a new control point is between the neighbor
        * point and the next point.
        *)
       (# p1, p2: @point;
       enter (p1,p2)
       ... 
       #);
     delete: (* Not Yet Implemented *)
       (* If p is in the neighborhood of an existing control point,
        * this control point is deleted
        *)
       (# p: @point;
       enter p
       ... 
       #);
     
     (* COMBINING SHAPES *)
     appendShape: (* Not Yet Implemented *)
       (* Add sourceShape to THIS(Shape).  Place
        * sourceShape.firstPoint in THIS(Shape).lastPoint by
        * translating the entire sourceShape.  This is the only
        * transformation involved.  After the operation,
        * THIS(Shape).lastPoint is the translated
        * sourceShape.lastPoint.  sourceShape cannot consist of
        * circularSplines only.
        *)
       (# sourceShape: ^Shape;
       enter sourceShape[]
       ...
       #);
     connectShape: (* Not Yet Implemented *)
       (* Add sourceShape to THIS(Shape).  TM is applied to
        * sourceShape before the addition.  THIS(Shape).lastpoint is
        * connected to sourceShape.firstPoint with a line segment.
        * After the operation, THIS(Shape).lastPoint is the 
        * translated sourceShape.lastPoint.  
        * sourceShape cannot consist of circularSplines only.
        *)
       (# TM: ^Matrix;
          sourceShape: ^Shape;
       enter (TM[],sourceShape[])
       ...
       #);
     connectShapeSmooth: (* Not Yet Implemented *)
       (* Add sourceShape to THIS(Shape).  TM is applied to
        * sourceShape before the addition.  THIS(Shape).lastpoint is
        * connected to sourceShape.firstPoint with a spline segment
        * constructed from the last two points in THIS(Shape) and
        * sourceShape.firstPoint.  After the operation,
        * THIS(Shape).lastPoint is the translated
        * sourceShape.lastPoint.  sourceShape cannot consist of
        * circularSplines only.
        *)
       (# TM: ^Matrix;
          sourceShape: ^Shape;
       enter (TM[],sourceShape[])
       ...
       #);
     combineShape: 
       (* Add sourceShape to THIS(Shape).  TM is applied to
        * sourceShape before the addition.  sourceShape and
        * THIS(Shape) do *not* become connected.  At least one of
        * THIS(Shape) and sourceShape must be closed.  If sourceShape
        * is closed, THIS(Shape).lastPoint is unchanged.  If
        * sourceShape is open, THIS(Shape).lastPoint is
        * sourceshape.lastPoint after the operation.
        *)
       (# TM: ^Matrix;
          sourceShape: ^Shape;
       enter (TM[],sourceShape[])
       do ...;
       #);
     
     (* HIGHLIGHTING *)
     hiliteOutline::< 
       (# ... #);
     
     (* INTERACTION *)
     InteractiveCreate::< 
       (# do ...; INNER  #);
     InteractiveCombine::< 
       (# do ...; INNER  #);
     
     InteractiveReshape::< 
       (# do ...; INNER  #);
     transform::< 
       (# do ...; INNER  #);
     
     getControls::<
       (# do ... #);
     
     (* PRIVATE *)
     findSegments::< (* private *)
       (# do ... #);
     writePS::<
       (# do ... #);
  do INNER;
  #);  (* Shape *)

14.12 PredefinedShape

PredefinedShape: AbstractShape
  (#
     CalculateShape:< 
       (* Return (approximating) Shape, if possible *)
       (# s: ^Shape
       do INNER
       exit (# ... exit s[] #)
       #);
     invalidate::<
       (# ... #);
     containsPoint::<
       (# ... #);
     transform::<
       (# do ...; INNER #);
     
     (* Patterns behaving like standard "types", but that have the
      * side-effect of invalidating THIS(PredefinedShape) when 
      * changed.
      *)
     invalidatePoint:
       (# p: @Point; enter (# enter p do Invalidate #) exit p #);
     invalidateInteger: integerValue
       (# enter (# enter value do Invalidate #) #);
     invalidateReal:
       (# r: @Real; enter (# enter r do Invalidate #) exit r #);
     invalidateDash:
       (* For instance {1,2,4,2} yields '=  ====  =  ====  =' etc. *)
       (# d: ^IntegerList; 
       enter (# enter d[] do invalidate #) 
       exit d[]
       #);
     invalidateCapStyle:
       (# c: @CapStyleDesc; 
       enter (# enter c do invalidate #) 
       exit c
       #);
     invalidateJoinStyle:
       (# j: @JoinStyleDesc; 
       enter (# enter j do invalidate #)
       exit j 
       #);
     writePS::<
       (# do ... #);
     prePrivate: @...;
  do INNER;
  #);

14.13 LineShape

LineShape: PredefinedShape
  (# <<SLOT LineShapeAttributes: attributes>>;
     
     firstPoint::<
       (# do begin -> p #);
     
     begin: @InvalidatePoint;
     end: @InvalidatePoint;
     width: @InvalidateInteger;
     dashes: @InvalidateDash; (* Not Yet Implemented *)
     cap: @InvalidateCapStyle;
     
     coordinates:
       (# enter (begin, end) exit (begin, end) #);
     open::<
       (# ... #);
     getBounds::< 
       (# do ...; INNER #);
     containsPoint::<
       (# ... #);
     getControls::<
       (# ... #);
     copy::< (# do INNER; ... #);
     
     (* HIGHLIGHTING *)
     hiliteOutline::< 
       (# do INNER; ... #);
     
     (* INTERACTION *)
     interactiveCreate::<
       (# do ...; INNER #);
     interactiveReshape::<
       (# do ...; INNER #);
     
     writePS::<
       (# do ... #);
     transform::<
       (# ... #);
     CalculateShape::<  (* private *)
       (# ... #);
     
  do INNER;
  #);

14.14 MultilineShape

MultiLineShape: PredefinedShape
  (# <<SLOT MultiLineShapeAttributes: attributes>>;
     
     firstPoint::< 
       (# ... #);
     lastPoint::< 
       (# ... #);
     points: @
       (# p: ^PointArray;
       enter (# enter p[] do invalidate #)
       exit p[]
       #);
     width: @InvalidateInteger;
     dashes: @InvalidateDash; (* Not Yet Implemented *)
     cap: @InvalidateCapStyle;
     join: @InvalidateJoinStyle;
     
     open::< 
       (# ... #);
     addPoint: (* Add p at the end of points *)
       (# p: @point;
       enter p
       ... 
       #);
     deletePoint: (* Delete p at from points *)
       (# p: @point;
       enter p
       ... 
       #);
     insertPoint: (* Insert p in points at position i *)
       (# p: @point;
          i: @integer
       enter (p,i)
       ... 
       #);
     getPoint:
       (* Return point no i in THIS(MultiLineShape); 1<=i<=npoints *)
       (# i: @Integer;
          p: @Point;
       enter i
       ... 
       exit p
       #);
     setPoint:
       (* Change the value of point no i to p; 1<=i<=npoints *)
       (# i: @Integer;
          p: @Point;
       enter (p,i)
       ... 
       #);
     closestLineSegment:
       (# p: @point; i: @integer
       enter p
       do ...
       exit i
       #);
     getBounds::<
       (# do ...; INNER #);
     containsPoint::<
       (# ... #);
     getControls::<
       (# ... #);
     copy::< 
       (# do INNER; ... #);
     
     (* HIGHLIGHTING *)
     hiliteOutline::< 
       (# do INNER; ... #);
     
     (* INTERACTION *)
     interactiveCreate::<
       (# do ...; INNER #);
     interactiveReshape::<
       (# do ...; INNER #);
     writePS::<
       (# do ... #);
     transform::<
       (# ... #);
     
     calculateShape::<  (* private *)
       (# ... #);
  do INNER;
  #);

14.15 TextShape

TextShape: PredefinedShape
  (# <<SLOT TextShapeAttributes: attributes>>;
     
     firstPoint::< 
       (# do position -> p #);
     initText: (* Specify several attributes simultaneously *)
       (# 
       enter 
          (position, theFontname, theStyle, size, underline, theText)
       #);
     position: 
       (* Where to place the baseline of the first line of theText *) 
       (# p: @Point; 
       enter (# enter p ... #)
       ... 
       exit p
       #);
     theFontName: (* one of Courier, Times, Helvetica *)
       (# nam: @fontname; 
       enter (# enter nam ... #)
       ... 
       exit nam
       #);
     theStyle: (* Either Plain, Italic or Bold *)
       (# sty: @Style;    
       enter (# enter sty ... #)
       ... 
       exit sty
       #);
     size: (* The size in points (1/72 inch) of the text drawn *)
       (# siz: @Integer; 
       enter (# enter siz ... #)
       ... 
       exit siz
       #);
     underline: (* Specifies if the text is to be underlined *)
       (# ul: @Boolean;
       enter (# enter ul ... #)
       ... 
       exit ul
       #);
     theText:
       (* Holds the characters of THIS(TextShape). i.e. it joins
        * the text lines in theLines into one text, where newlines 
        * are inserted for line breaks.
        *)
       (# t: ^Text;
       enter (# enter t[] ... #)
       ... 
       exit t[]
       #);
     theLines: 
       (* Each text element in this list corresponds to one line
        * of text in THIS(TextShape).
        *)
       (# l: ^TextList;
       enter (# enter l[] ... #)
       ... 
       exit l[]
       #);
     numberOfLines: integerValue
       (* Number of Texts in theLines *)
       (# ...
       #);
     getBounds::<
       (# do ...; INNER #);
     containsPoint::<
       (# ... #);
     getControls::<
       (# do ...; INNER #);
     copy::< 
       (# do INNER; ... #);
     
     (* HIGHLIGHTING *) 
     hiliteOutline::< 
       (# do INNER; ... #);
     
     (* INTERACTION *)
     interactiveCreate::<
       (# lastCh: @char; (* Last character typed in interaction *)
       do ...; INNER
       exit lastCh
       #);
     interactiveReshape::<
       (# lastCh: @char; (* Last character typed in interaction *)
       ... 
       exit lastCh
       #);
     
     writePS::<
       (# do ... #);
     transform::<
       (# ... #);
     TextPrivate: @ ...;
     calculateShape::< (* private *)
       (# ... #);
     
  do INNER;
  #);

14.16 PieShape

PieShape: PredefinedShape
  (# <<SLOT PieShapeAttributes: attributes>>;
     
     firstPoint::<
       (# do center -> p #);
     
     center: @InvalidatePoint;
     horizontalRadius: @InvalidateInteger;
     verticalRadius: @InvalidateInteger;
     (* Use: 0 <= angle1 <= 360 a1 <= angle2 <= 360+angle1      *)
     angle1: @InvalidateReal;
     angle2: @InvalidateReal;
     
     open::<
       (# do ...; INNER #);
     getBounds::<
       (# do ...; INNER #);
     containsPoint::<
       (# do ...; INNER #);
     getControls::< 
       (# do ...; INNER #);
     copy::< 
       (# do INNER; ... #);
     
     (* HIGHLIGHTING *)
     hiliteOutline::< 
       (# do INNER; ... #);
     
     (* INTERACTION *)
     interactiveCreate::<
       (# do ...; INNER #);
     interactiveReshape::<
       (# do ...; INNER #);
     
     writePS::<
       (# do ... #);
     transform::<
       (# ... #);
     calculateShape::< (* private *)
       (# ... #);
  do INNER
  #);

14.17 ArcShape

ArcShape: PredefinedShape
  (# <<SLOT ArcShapeAttributes: attributes>>;
     
     firstPoint::<
       (# do center -> p #);
     
     center: @InvalidatePoint;
     horizontalRadius: @InvalidateInteger;
     verticalRadius: @InvalidateInteger;
     (* Use: 0 <= angle1 <= 360 a1 <= angle2 <= 360+angle1      *)
     angle1: @InvalidateReal;
     angle2: @InvalidateReal;
     arcWidth: @InvalidateInteger;
     
     open::<
       (# ... #);
     getBounds::<
       (# do ...; INNER #);
     containsPoint::<
       (# do ...; INNER #);
     getControls::<
       (# do ...; INNER #);
     copy::< (# do INNER; ... #);
     
     (* HIGHLIGHTING *)
     hiliteOutline::< 
       (# do INNER; ... #);
     
     (* INTERACTION *)
     interactiveCreate::<
       (# do ...; INNER #);
     interactiveReshape::<
       (# do ...; INNER #);
     
     writePS::<
       (# do ... #);
     transform::<
       (# ... #);
     calculateShape::< (* private *)
       (# ... #);
     
  do INNER
  #);

14.18 StrokeableShape

StrokeableShape: PredefinedShape 
  (# stroked: @Boolean;
     strokewidth: @Integer;
     
     writePS::<
       (# do ... #);
     getBounds::<
       (# ... #);
     copy ::<
       (# do INNER; ... #);
  do INNER
  #);

14.19 RectShape

RectShape: StrokeableShape
  (# <<SLOT RectShapeAttributes: attributes>>;
     
     firstPoint::<
       (# do upperleft -> p #);
     
     upperleft: @InvalidatePoint;
     width: @InvalidateInteger;
     height: @InvalidateInteger;      
     
     corners:
       (# lowerright: @Point;
          changeCorners:
            (# enter (upperleft,lowerright) 
            ... 
            #);
       enter changeCorners
       exit 
          (upperleft, 
          ((upperleft.p.x+width),
          (upperleft.p.y+height)) )
       #);
     open::<
       (# ... #);
     getBounds::<
       (# ... #);
     containsPoint::<
       (# ... #);
     getControls::<
       (# ... #);
     copy::<
       (# do INNER; ... #);
     
     (* HIGHLIGHTING *)
     hiliteOutline::< 
       (# do INNER; ... #);
     
     (* INTERACTION *)
     interactiveCreate::<
       (# do ...; INNER #);
     interactiveReshape::<
       (# do ...; INNER #);
     
     writePS::<
       (# do ... #);
     transform::<
       (# ... #);
     calculateShape::< (* Private *)
       (# ... #);
     
  do INNER;
  #);

14.20 EllipseShape

EllipseShape: StrokeableShape
  (# <<SLOT EllipseShapeAttributes: attributes>>;
     
     firstPoint::< (# do center -> p #);
     
     center: @InvalidatePoint;
     horizontalradius: @InvalidateInteger;
     verticalradius: @InvalidateInteger;
     
     geometry:
       (#
       enter (center, verticalradius, horizontalradius)
       exit  (center, verticalradius, horizontalradius)
       #);
     open::<
       (# ... #);
     getBounds::<
       (# ... #);
     containsPoint::<
       (# ... #);
     getControls::<
       (# do ...; INNER #);
     copy::< (# do INNER; ... #);
     
     (* HIGHLIGHTING *)
     hiliteOutline::< 
       (# do INNER; ... #);
     
     (* INTERACTION *)
     interactiveCreate::<
       (# ... #);
     interactiveReshape::<
       (# do ...; INNER #);
     
     writePS::<
       (# do ... #);
     transform::<
       (# ... #);
     calculateShape::< (* private *)
       (# do ... #);
     
  do INNER;
  #);

14.21 Rasters

Raster:
  (* An abstract superpattern for all Rasters. A raster is a
   * rectangular grid of pixels.
   *)
  (# <<SLOT RasterAttributes: attributes>>;
     
     hotspot:
       (* When used in a filling operation hotspot is placed in
        * hotspot of the shape being filled. Defaults to (0,0).
        *)
       (# p: @Point;                 
       enter (# enter p ... #)
       exit  (# ... exit p #)
       #);
     pixel:< Object;
     
     init:<
       (# width, height: @integer;
       enter (width, height)
       ...
       #);
     copy:< (* Return a deep copy of THIS(Raster) *)
       (# aCopy: ^Raster;
       ...
       exit aCopy[]
       #);
     width: integerValue
       (* returns the width set by init or by read operations *)
       (# ... #);
     height: integerValue
       (* returns the height set by init or by read operations *)
       (# ... #);
     
     putPixel:<
       (# i, j: @integer; p: ^pixel;
       enter (i,j,p[])
       ...
       #);
     getPixel:<
       (# i, j: @integer; p: ^pixel;
       enter (i,j)
       ...
       exit p[]
       #);
     
     (* Private *)
     calculate:< (# ... #);
     RasterPrivatePart: @ ...;
     
  do INNER; calculate;
  exit THIS(Raster)[]
  #);

BitMap: Raster
  (* Raster in which the pixels are booleans *)
  (# <<SLOT BitmapAttributes: attributes>>;
     
     pixel::< 
       (# b: @boolean enter b exit b #);
     init::<  
       (# do ...; INNER #);
     putPixel::< 
       (# do ...; INNER #);
     getPixel::< 
       (# do ...; INNER #);
     copy::< 
       (# do INNER; ... #);
     writeToPBMfile: (* Not Yet Implemented *)
       (# pbmfilename: ^text;
          rawbits: @boolean
            (* If true, the RAWBITS format is used *);
       enter (pbmfilename[],rawbits)
       ... 
       #);
     readFromPBMfile:
       (# pbmfilename: ^text;
       enter pbmfilename[]
       do ...;
       #);
     
     (* Private *)
     calculate::< (# ... #);
     BitMapPrivatePart: @ ...;
  do INNER;
  #);

GrayMap: Raster (* Not Yet Implemented *)
  (# <<SLOT GraymapAttributes: attributes>>;
     
     pixel::<
       (# g: @integer enter g exit g #);
     init::< 
       (# ... #);
     putPixel::< 
       (# ... #);
     getPixel::<
       (# ... #);
     copy::<
       (# do INNER; ... #);
     writeToPGMfile:
       (# pgmfilename: ^text;
          rawbits: @boolean
            (* If true, the RAWBITS format is used *);
       enter (pgmfilename[],rawbits)
       ... 
       #);
     readFromPGMfile:
       (# pgmfilename: ^text;
       enter pgmfilename[]
       ... 
       #);
     
     (* Private *)
     calculate::< (# ... #);
     GrayMapPrivatePart: @ ...;
  do INNER;
  #);

PixMap: Raster
  (* Raster in which the pixels are RGB values *)
  (# <<SLOT PixmapAttributes: attributes>>;
     
     pixel::< 
       (# r,g,b: @integer enter (r,g,b) exit (r,g,b) #);
     init::< 
       (# maxVal: @integer; (* Maximum RGB value *)
       enter maxVal
       do ...; INNER
       #);
     putPixel::< 
       (# do ...; INNER #);
     getPixel::< 
       (# ... #);
     copy::< (# do INNER; ... #);
     writeToPPMfile:  (* Not Yet Implemented *)
       (# ppmfilename: ^text;
          rawbits: @boolean
            (* If true, the RAWBITS format is used *);
       enter (ppmfilename[],rawbits)
       ... 
       #);
     readFromPPMfile:  (* Not Yet Implemented *)
       (# ppmfilename: ^text;
       enter ppmfilename[]
       ... 
       #);
     
     (* Private *)
     calculate::< (# ... #);
     PixMapPrivatePart: @ ...;
     
  do INNER;
  #);  

14.22 Paint

Paint: (* An abstract superpattern for all paint *)
  (# <<SLOT PaintAttributes: attributes>>;
     
     init:< object;
     
     copy:< (* Return a deep copy of THIS(Paint) *)
       (# aCopy: ^Paint;
       ...
       exit aCopy[]
       #);
     fill: 
       (* Prefix for fill operations *)
       (# theCanvas: ^BifrostCanvas enter theCanvas[] do INNER #);
     fillShape:< fill
       (* Fill theShape with THIS(Paint) in theCanvas. *)
       (# theShape: ^Shape;
       enter (theShape[])
       ...
       #);
     fillLine:< fill
       (* Fill theLine with THIS(Paint) in theCanvas. *)   
       (# theLine: ^LineShape;
       enter (theLine[])
       ...
       #);
     fillMultiLine:< fill
       (* Fill theMultiLine with THIS(Paint) in theCanvas.
        *)   
       (# theMultiLine: ^MultiLineShape;
       enter (theMultiLine[])
       ...
       #);
     fillText:< fill
       (* Fill the specified text with THIS(Paint) in theCanvas *)
       (# theText: ^TextShape;
       enter (theText[])
       ...
       #);
     fillPie:< fill
       (* Fill thePie with THIS(Paint) in theCanvas. *)   
       (# thePie: ^pieShape;
       enter (thePie[])
       ...
       #);
     fillArc:< fill
       (* Fill theArc with THIS(Paint) in theCanvas. *)   
       (# theArc: ^arcShape;
       enter (theArc[])
       ...
       #);
     fillRect:< fill
       (* Fill theRect with THIS(Paint) in theCanvas. *)   
       (# theRect: ^RectShape;
       enter (theRect[])
       ...
       #);
     fillEllipse:< fill
       (* Fill the theEllipse with THIS(Paint) in theCanvas *)   
       (# theEllipse: ^EllipseShape;
       enter (theEllipse[])
       ...
       #);
     fillOther:< fill
       (* Used to fill other, e.g. user defined, shapes *)
       (# theShape: ^AbstractShape;
       enter theShape[]
       do INNER;
       #);
     
     (* PRIVATE *)
     writePS:<
       (# out: ^stream; shape_hotspot: @point
       enter (out[], shape_hotspot)
       do INNER 
       #);
     paintprivate: @ ...;
     setSpecialPaint: (* Private *)
       (# theCanvas: ^BifrostCanvas;
          doneInInner: @boolean; 
       enter theCanvas[]
       do INNER 
       #);
     setCanvasPaint:< (* Private *) setSpecialPaint;
     setBorderPaint:< (* Private *) setSpecialPaint;
     SetBackgroundPaint:< (* Private *) setSpecialPaint;
  do INNER;
  exit THIS(Paint)[]
  #);

14.23 SolidColor

SolidColor: Paint
  (* A solid color specified relative to the RGB, HSV, or CMY color
   * spaces, or by naming the color, using one of the name patterns
   * in the fragment ColorNames.
   *)
  (# <<SLOT SolidColorAttributes: attributes>>;
     
     init::<
       (# ... #);
     copy::< 
       (# do INNER; ... #);
     Name:
       (* Change THIS(SolidColor) to the color specified.  The color
        * names are define as descriptors in the fragment
        * 'ColorNames'.  NOTICE: This is different from earlier
        * versions of Bifrost.
        *)
       (# enter RGBvalues #);
     RGBvalues:
       (* Set or query the Red-Green-Blue values of THIS(SolidColor)
        * r, g and b all ranges from 0 to MaxRGB.
        *)
       (# r,g,b: @Integer;
          changeRGB:
            (# enter (r,g,b) ... #);
          getRGB: 
            (# ... exit (r,g,b) #);
       enter changeRGB
       exit GetRGB
       #);
     HSVvalues:
       (* Set or query the Hue-Saturation-Value values of
        * THIS(SolidColor).  h, s and v are taken to range from 0 to
        * MaxHue, MaxSat and MaxVal respectively. Specializations may
        * alter the default bindings of these.
        *)
       (# h,s,v: @Integer;
          changeHSV:
            (# enter (h,s,v) do ... #);
          getHSV:
            (# do ... exit (h,s,v) #);
          MaxHue:< integerValue
            (# do DefaultMaxHue -> value; INNER #);
          MaxSat:< integerValue
            (# do DefaultMaxSat -> value; INNER #);
          MaxVal:< integerValue
            (# do DefaultMaxVal -> value; INNER #);
       enter changeHSV
       exit getHSV
       #);
     CMYvalues: (* RGB complementaries *)
       (* Set or query the Cyan-Magenta-Yellow values of
        * THIS(SolidColor).  c, m and y all ranges from 0 to MaxRGB.
        *)
     (# c,m,y: @Integer;
        changeCMY:
          (# enter (c,m,y) do ... #);
        getCMY: 
          (# do ...; exit (c,m,y) #);
     enter changeCMY
     exit getCMY
     #);
     
     fillShape::<
       (# ... #);
     fillLine::<
       (# do INNER; ... #);
     fillMultiLine::<
       (# ... #);
     fillText::<
       (# do INNER; ... #);
     fillPie::<
       (# do INNER; ... #);
     fillArc::<
       (# do INNER; ... #);
     fillRect::<
       (# do INNER; ... #);
     fillEllipse::<
       (# do INNER; ... #);
     
     (* PRIVATE *)
     writePS::<
       (# do ... #);
     setBorderPaint::< (* Private *)
       (# ...#);
     setBackgroundPaint::< (* Private *)
       (# ...#);
     setCanvasPaint::< (* Private *)
       (# ...#);
     privatePart: @ ...;
  do INNER;
  #);

14.24 Predefined Graytones

SolidGray:
  (# g: ^SolidColor;
     percentage: @Integer;
  enter percentage
  ...
  exit g[]
  #);

SolidGrey: SolidGray (# do INNER #);

14.25 RasterPaint

RasterPaint: Paint
  (* Use thePixmap and optionally paddingSolidColor to fill out the
   * shape
   *)
  (# 
     (* If paddingSolidColor[]=NONE thePixmap will be repeated when
      * filling out the shape. If not, paddingSolidColor will be used
      * to fill out any parts of the shape the pixmap doesn't cover.
      *)
     paddingSolidColor: ^SolidColor;
     
     thePixMap: 
       (# p: ^PixMap;
       enter (# enter p[] ... #)
       exit (# ... exit p[] #)
       #);
     init::<
       (# ... #); 
     copy::<
       (# do INNER; ... #);
     fillShape::<
       (# do INNER; ...; #);
     fillLine::<
       (# ... #);
     fillMultiLine::<
       (# ... #);
     fillText::<
       (# ... #);
     fillArc::<
       (# ... #);
     fillPie::<
       (# ... #);
     fillRect::<
       (# ... #);
     fillEllipse::<
       (# ... #);
     
     (* PRIVATE *)
     writePS::<
       (# do ... #);
     private: @...;
     setBorderPaint::<  (* Private *)
       (# do INNER; ... #);
     setBackgroundPaint::<  (* Private *)
       (# do INNER; ... #);
     setCanvasPaint::< (* Private *)
       (# do INNER; ... #);
  do INNER;
  #);

14.26 TiledSolidColor

TiledSolidColor: SolidColor
  (* A SolidColor extended with a BitMap. The BitMap will be tiled in
   * the Shape before the SolidColor is applied, and only where the
   * bits of the BitMap are true, the SolidColor will be visible.
   *)
  (# 
     theTile: 
       (# t: ^BitMap;
       enter (# enter t[] ... #)
       exit (# ... exit t[] #)
       #);
     init::<
       (# ... #); 
     copy::<
       (# do INNER; ... #);
     fillShape::<
       (# ... #);
     fillLine::<
       (# ... #);
     fillMultiLine::<
       (# ... #);
     fillText::<
       (# ... #);
     fillArc::<
       (# ... #);
     fillPie::<
       (# ... #);
     fillRect::<
       (# ... #);
     fillEllipse::<
       (# ... #);
     
     (* PRIVATE *)
     writePS::<
       (# do ... #);
     tiledPrivate: @ ...;
     setBorderPaint::<  (* Private *)
       (# do INNER; ... #);
     setBackgroundPaint::< (* Private *)
       (# do INNER; ... #);
     setCanvasPaint::< (* Private *)
       (# do INNER; ... #);
  do INNER;
  #);

14.27 AbstractGraphicalObject

AbstractGraphicalObject: (* To be further specialized *)
  (* The graphical object is the smallest entity that can be drawn
   * in a BifrostCanvas.  It is a aggregation of a Paint and a Shape.
   * ANY graphical object MUST be initialized before used (init).
   * After a paint and a shape has been specified, it can be drawn by
   * giving the reference of it as enter parameter to the method
   * "draw" in a BifrostCanvas.  Graphical objects may also be
   * created by using InteractiveCreateShape.
   *)
(# <<SLOT AbstractGraphicalObjectAttributes: attributes>>;
   shapeDesc:< AbstractShape
     (* Specify actual shape in specializations *);
   TMDesc:< 
     (# m: ^Matrix;
        transformpoint: @
          (# p: @Point enter p do p->m.transformpoint->p exit p #);
        CalcCanvasTM:< 
          (# theTM: ^Matrix 
          enter theTM[]
          ...
          #);
        enterTM:< (# enter m[] ... #);
        enterIt: @enterTM;
     enter enterIt
     do INNER;
     exit m[]
     #);
   (* TM describes the transformation from the coordinate system of
    * theShape (also known as GO coordinates) to the the Picture it
    * is part of, if any.
    *)
   TM: @TMDesc;
   
   init:< (* MUST be called first *)
     (# ... #);
   readUserData:<
     (#
        userdata: ^text;
        success: @boolean;
        parseNotification: notification
          (#
          do
             false -> success;
             INNER
          #);
        parseError:< parseNotification
     enter userdata[]
     do
        true -> success;
        INNER
     exit success
     #);
   writeUserData:<
     (# 
        userdata: ^text
     do &text[] -> userdata[]; INNER
     exit userdata[]
     #);
   setPaint:<
     (* Specify the paint to use for THIS(AbstractGraphicalObject) *)
     (# enter thePaint[] do INNER #);
   getPaint:< 
     (* Obtain the paint to use *)
     (# do INNER exit thePaint[] #);
   getShape:<
     (* Obtain the shape to use.  The specialization
      * PredefinedGraphicalObject returns an approximating Shape.
      * Only the specialization Shape has a corresponding SetShape.
      *)
     (# s: ^Shape
     do INNER
     exit s[]
     #);  
   draw:<
     (* Draw THIS(AbstractGraphicalObject) in theCanvas.
      * Normally this is not used by the user directly.  Instead
      * THIS(AbstractGraphicalObject)[] should be given to the draw
      * method of a BifrostCanvas.
      *)
     (# doneInInner: @boolean;
        theCanvas: ^BifrostCanvas
          (* BifrostCanvas to draw THIS(AbstractGraphicalObject) on *);
     enter theCanvas[]
     ...
     #);
   erase:<
     (* Erase THIS(AbstractGraphicalObject) from theCanvas.
      * Normally this is not used by the user directly.  Instead
      * THIS(AbstractGraphicalObject)[] should be given to the erase
      * method of a BifrostCanvas.
      *)
     (# doneInInner: @boolean;
        theCanvas: ^BifrostCanvas
          (* BifrostCanvas to erase THIS(AbstractGraphicalObject) from *);
     enter theCanvas[]
     ... 
     #);
   copy:< (* Return a deep copy of THIS(AbstractGraphicalObject) *)
     (# aCopy: ^AbstractGraphicalObject;
     ...
     exit aCopy[]
     #);
   getBounds:<
     (* Exit a Rectangle containing the bounding box of
      * THIS(AbstractGraphicalObject) in BifrostCanvas coordinates.
      *)
     (# r: @rectangle;
        doneInInner: @boolean;
     ...
     exit r
     #);
   hilite:< (* Highlight THIS(AbstractGraphicalObject) *)
     (# doneInInner: @boolean;
        theCanvas: ^BifrostCanvas
          (* The BifrostCanvas to do the highlighting on *)
     enter theCanvas[]
     ...
     #);
   unHilite:< (* Unhighlight THIS(AbstractGraphicalObject) *)
     (# doneInInner: @boolean;
        theCanvas: ^BifrostCanvas
          (* The BifrostCanvas to do the unhighlighting on *)
     enter theCanvas[]
     ...
     #);
   
   (* INTERACTION *)
   hitControl:<
     (* Answer whether thePoint is inside a 2x2mm box around a
      * control point of THIS(AbstractGraphicalObject).  thePoint is
      * in BifrostCanvas coordinates.  Exits reference to exact point
      * if hit, NONE otherwise.
      *)   
     (# thePoint: @Point;
        res: ^Point;
     enter thePoint
     do ...;
        INNER;
     exit res[]
     #);
   interaction: 
     (* Prefix for interactive operations *)
     (# theCanvas: ^BifrostCanvas
          (* The BifrostCanvas to show feedback in *);
        startPoint: @Point;
        theModifier: @Modifier;
        doneInInner: @boolean;
     enter (theCanvas[], startPoint, theModifier)
     do INNER;
     #);
   interactiveCreateShape:< interaction
     (* Initialize the shape of THIS(AbstractGraphicalObject) by
      * providing feedback in a BifrostCanvas.  Normally this is not
      * used by the user directly.  Instead
      * THIS(AbstractGraphicalObject)[] should be given to the
      * interactiveCreateShape method of a BifrostCanvas.
      *)
     (# ... #);
   interactiveCombineShape:< interaction 
     (* Combine a shape with the shape of
      * THIS(AbstractGraphicalObject) by providing feedback for
      * creating the new shape in a BifrostCanvas, and then combining
      * the shape of THIS(AbstractGraphicalObject) with the obtained
      * shape.  Normally this is not used by the user directly.
      * Instead THIS(AbstractGraphicalObject)[] should be given to
      * the interactiveCombineShape method of a BifrostCanvas.
      *)
     (# ... #);
   interactiveReshape:< interaction
     (* Change the shape of THIS(AbstractGraphicalObject) by
      * providing feedback in a BifrostCanvas.  Normally this is not
      * used by the user directly.  Instead
      * THIS(AbstractGraphicalObject)[] should be given to the
      * interactiveReShape method of a BifrostCanvas.
      *)
     (# do ... #);
   interactiveMove:< interaction
     (* Move the shape of THIS(AbstractGraphicalObject) using
      * theshape.(un)hiliteoutline for feedback in the BifrostCanvas
      * THIS(AbstractGraphicalObject) is drawn in.  Calls "move" to
      * do the transformation.  Normally this is not used by the user
      * directly.  Instead THIS(AbstractGraphicalObject)[] should be
      * given to the interactiveMove method of a BifrostCanvas.
      *)
     (# 
     do INNER; ...;
     #);
   interactiveScale:< interaction (* Not Yet Implemented *)
     (* Scale the shape of THIS(AbstractGraphicalObject) using
      * theshape.(un)hiliteoutline for feedback in the BifrostCanvas
      * THIS(AbstractGraphicalObject) is drawn in.  Calls "scale" to
      * do the transformation.  Normally this is not used by the user
      * directly.  Instead THIS(AbstractGraphicalObject)[] should be
      * given to the interactiveScale method of a BifrostCanvas.
      *)
     (# ... #);
   interactiveRotate:< interaction (* Not Yet Implemented *)
     (* Rotate the shape of THIS(AbstractGraphicalObject) using
      * theshape.(un)hiliteoutline for feedback in the BifrostCanvas
      * THIS(AbstractGraphicalObject) is drawn in.  Calls "rotate" to
      * do the transformation.  Normally this is not used by the user
      * directly.  Instead THIS(AbstractGraphicalObject)[] should be
      * given to the interactiveRotate method of a BifrostCanvas.
      *)
     (# ... #);
   
   (* TRANSFORMATIONS *)
   transform:< 
     (* Transform THIS(AbstractGraphicalObject) by M, by multiplying
      * THIS(AbstractGraphicalObject).TM with M
      *)
     (# M: ^Matrix; 
     enter M[]
     ...
     #);
   move:< (* Translate THIS(AbstractGraphicalObject) by offset *)
     (# offset: @Point;
     enter offset
     do ...; INNER;
     #);
   moveTo:< 
     (* Move THIS(AbstractGraphicalObject).theShape.hotSpot to pos *)
     (# pos: @Point;
     enter pos
     do ...; INNER;
     #);
   scale:< (* Scale THIS(AbstractGraphicalObject) by factor *)
     (# factor: @Vector; (* Real point *)
     enter factor
     do ...; INNER;
     #);
   rotate:< 
     (* Rotate THIS(AbstractGraphicalObject) by angle (degrees) *)
     (# angle: @Real;
     enter angle
     do ...; INNER;
     #);
   
   (* QUERY *)
   containsPoint:< booleanValue
     (* Answer if thePoint is inside the shape of
      * THIS(AbstractGraphicalObject).  thePoint is assumed to be in
      * coordinates relative to theCanvas.
      *)
     (# theCanvas: ^BifrostCanvas;
        thePoint: @Point;
        doneInInner: @boolean;
     enter (theCanvas[], thePoint)
     ...
     #);
   
   (* The aggregation parts *)
   theShape: ^ShapeDesc;
   thePaint: ^Paint;
   
   (* PRIVATE *)
   writePS:<
     (# out: ^stream; invisible: @boolean 
     enter out[] 
     do ...
     #);
   private: @ ...;
   recalculateShape:< (* private *)
     (# theCanvas: ^BifrostCanvas enter theCanvas[] do INNER #);
do INNER;
exit THIS(AbstractGraphicalObject)[]
#);  


14.28 GraphicalObject

GraphicalObject: AbstractGraphicalObject
  (#
     shapeDesc::< (* The real shape with lines and splines *)
       Shape; 
     setShape: (* Set the Shape of THIS(GraphicalObject) *)
       (# enter theShape[] #);
     getShape::< (* Get the Shape of THIS(GraphicalObject) *)
       (# do theShape[] -> s[] #);
     copy::< 
       (# ... #);
     draw::< 
       (# ... #);
     writePS::<
       (# do ... #);
     hilite::< 
       (# ... #);
     unHilite::< 
       (# ... #);
     recalculateShape::< (* private *)
       (# ... #);
  do INNER
  #);

14.29 PictureShape

PictureShape: AbstractShape (* To be further specialized *)
  (# <<SLOT PictureShapeAttributes: attributes>>;
     
     firstpoint::< 
       (# ... #);
     copy::< 
       (# do INNER; ... #);
     getBounds::< 
       (# do ... #);
     containsPoint::<
       (# ... #);
     getControls::<
       (# ... #);
     hiliteControls::<   
       (# ... #);
     hiliteOutline::< 
       (# ... #);
     transform::<
       (# do ...; INNER #);
     
     (* Private *)
     writePS::<
       (# do ... #);
     pictureprivate: @...;
  do INNER
  #);

14.30 Picture

Picture: AbstractGraphicalObject
  (* A collection of graphical objects *)
  (# <<SLOT PictureAttributes: attributes >>;
     
     shapeDesc::< PictureShape;
     TMDesc::<
       (# CalcCanvasTM::<(# do ...; INNER #);
          enterTM::< (# do ...; INNER #);
       do INNER;
       #);
     init::< 
       (# ... #);
     add:<
       (* Add go to THIS(Picture) *)
       (# go: ^AbstractGraphicalObject;
       enter go[]                            
       ... 
       #);
     delete:<
       (* Delete go from THIS(Picture) *)
       (# go: ^AbstractGraphicalObject;
       enter go[]
       ... 
       #);
     drawOnPixmap:  (* Not Yet Implemented *)
       (* Draw THIS(Picture) on pm *)
       (# pm: ^Pixmap;
       enter pm[]
       do ...;
       #);
     draw::< 
       (# ... #);
     erase::< 
       (# ... #);
     copy::< 
       (# do INNER; ... #);
     setPaint::< 
       (* Specify the paint to use for all AbstractGraphicalObjects
        * in THIS(Picture). If they are shown on the Canvas, their
        * visual appearance is changed instantly.
        *)
       (# theCanvas: ^BifrostCanvas;
       enter theCanvas[]
       ...
       #);
     getBounds::< 
       (# ... #);
     hilite::< 
       (# ... #);
     unHilite::< 
       (# ... #);
     bringForward:
       (* Make aGO the last AbstractGraphicalObject of THIS(Picture)
        * aGO must already be a member of THIS(Picture)
        *)
       (# aGO: ^AbstractGraphicalObject;
       enter aGO[]                                                        
       ... 
       #);
     sendBehind:
       (* Make aGO the first AbstractGraphicalObject of THIS(Picture)
        * aGO must already be a member of THIS(Picture)
        *)
       (# aGO: ^AbstractGraphicalObject;
       enter aGO[]                                                        
       ... 
       #);
     scanGOs: 
       (* Scan through each AbstractGraphicalObject in THIS(Picture)
        * in order from the bottommost to the frontmost one.
        *)
       (# go: ^AbstractGraphicalObject;
       ...
       #);
     scanGOsReverse: 
       (* Scan through each AbstractGraphicalObject in THIS(Picture)
        * in order from the frontmost to the bottommost one.
        *)
       (# go: ^AbstractGraphicalObject;
       ...
       #);
     
     (* INTERACTION *)
     interactiveCreateShape::<
       (# ... #);
     interactiveCombineShape::<
       (# ... #);
     interactiveReshape::<
       (# ... #);
     
     (* QUERY *)
     lastGO:
       (* Exit reference to last AbstractGraphicalObject in
        * THIS(Picture)
        *)
       (# aGO: ^AbstractGraphicalObject;
       ... 
       exit aGO[]
       #);
     firstGO:
       (* Exit reference to last AbstractGraphicalObject in
        * THIS(Picture)
        *)
       (# aGO: ^AbstractGraphicalObject;
       ... 
       exit aGO[]
       #);
     noOfGOs: integerValue
       (* Exit number of AbstractGraphicalObjects in THIS(Picture) *)
       (# ... #);
     isEmpty: booleanValue
       (* True iff no graphical objects has been added to
        * THIS(Picture)
        *)
       (# ... #);
     isMember: booleanValue
       (* True iff aGO has been added to THIS(Picture) *)
       (# aGO: ^AbstractGraphicalObject;
       enter aGO[]
       ...
       #);
     containsPoint::<
       (* Answer if thePoint (canvascoordinates) is inside the shape
        * of any graphical object of THIS(Picture)
        *)
       (# ... #);
     firstContaining:< 
       (* Returns reference to first AbstractGraphicalObject in
        * THIS(Abstract) that contains thePoint.
        * thePoint is assumed to be in coordinates relative to 
        * theCanvas.
        *)
       (# theCanvas: ^BifrostCanvas;
          thePoint: @Point;
          aGO: ^AbstractGraphicalObject;
       enter (theCanvas[], thePoint)
       ...
       exit aGO[] 
       #);
     lastContaining:< 
       (* Returns reference to last AbstractGraphicalObject in
        * THIS(Picture) that contains thePoint.
        * thePoint is assumed to be in coordinates relative to 
        * theCanvas.
        *)
       (# theCanvas: ^BifrostCanvas;
          thePoint: @Point;
          aGO: ^AbstractGraphicalObject;
       enter (theCanvas[], thePoint)
       ...
       exit aGO[] 
       #);
     writePS::<
       (# do ... #);
  do INNER;
  #);  (* Picture *)

14.31 BifrostCanvas

(* The BifrostCanvas is the connection between the graphic
 * definitions and the device. Graphical objects become visible on
 * the output device when they are added to a BifrostCanvas by the
 * use of the draw-method.
 *)

BifrostCanvas: Canvas
  (# <<SLOT CanvasAttributes: attributes >>;
     
     thePicture: 
       (* Picture holding the graphical objects *)
       ^Picture; 
     visualShape: 
       (* The part of THIS(BifrostCanvas) that is visible *)
       ^Shape; 
     clipShape: 
       (* Shape used for clipping in THIS(BifrostCanvas). Defaults to
        * visualShape
        *)
       ^Shape;
     draw:  (* Put GO on THIS(BifrostCanvas) *)
       (# GO: ^AbstractGraphicalObject
       enter GO[]
       ...
       #);
     erase: (* Erase GO from THIS(BifrostCanvas) *)
       (# aGO: ^AbstractGraphicalObject;
       enter aGO[]
       ...
       #);
     refresh: (* Mark entire BifrostCanvas as damaged and repair *)
       ...;
     scanThePicture: 
       (* Scan through each AbstractGraphicalObject in thePicture in
        * order from the bottommost to the frontmost one.
        *)
       (# go: ^AbstractGraphicalObject;
       ...
       #);
     scanThePictureReverse: 
       (* Scan through each AbstractGraphicalObject in thePicture in
        * order from the frontmost to the bottommost one.
        *)
       (# go: ^AbstractGraphicalObject;
       ...
       #);
     firstContaining:
       (* Returns reference to first AbstractGraphicalObject in
        * thePicture that contains thePoint.
        * thePoint is assumed to be in coordinates relative to 
        * THIS(BifrostCanvas).
        *)
       (# thePoint: @Point;
       enter thePoint
       exit (THIS(BifrostCanvas)[],thePoint)
            ->thePicture.firstContaining
       #);
     lastContaining:
       (* Returns reference to last AbstractGraphicalObject in
        * thePicture that contains thePoint.
        * thePoint is assumed to be in coordinates relative to 
        * THIS(BifrostCanvas).
        *)
       (# thePoint: @Point;
       enter thePoint
       exit (THIS(BifrostCanvas)[],thePoint)
            ->thePicture.lastContaining
       #);
     
     (* EVENT HANDLING *)
     eventHandler::<
       (# 
          onOpen:< 
            (* Called immediately after the BifrostCanvas has been
             * made visible.
             *)
            (#
            ...
            #);
          onMouseDown::< 
            (* Called when a mouse button is pressed *)
            (# mousePos: @Point 
                 (* the position of the mouse in device coordinates *);
               button: (# exit buttonState #);
               shiftModified: (# exit shiftKey #);
               (*lockModified: (# exit capsLock #);*)
               controlModified: (# exit controlKey #);
               metaModified: (# exit metaKey #);
               altModified: (# exit altKey #);
            ...
            #);
          onKeyDown::< (* Called when a key is pressed *)
            (# ... #);
          onRefresh::<
            (* Called when THIS(BifrostCanvas) is being refreshed *)
            (# do ... #);
          onFrameChanged::<
            (* Called when THIS(BifrostCanvas) changes its frame
             * (size).
             *)
            (# ... #);
          onActivate::< 
            (* Called when the BifrostCanvas is activated, e.g. by
             * entering it with the mouse.
             *)
            (# ... #);
          onDeactivate::< 
            (* Called when the BifrostCanvas is deactivated, e.g. by
             * leaving it with the mouse.
             *)
            (# ... #);
          onFatalError:< (# err: ^text; enter err[] do INNER #);
       #);
     borderwidth: @
       (* The width of the border if present. Defaults to 0 *)
       (# value: @integer;
       enter (# enter value ... #)
       exit  (# ... exit value #)
       #);
     borderpaint: @
       (* The Paint used to fill the border if present. Defaults to
        * black
        *)
       (# p: ^Paint;
       enter (# enter p[] ... #)
       exit  (# ... exit p[] #)
       #);
     backgroundpaint: @
       (* The Paint used as background. Defaults to white *)
       (# p: ^Paint;
       enter (# enter p[] ... #)
       exit  (# ... exit p[] #)
       #);
     
     size: 
       (* The size of THIS(BifrostCanvas) *)
       (# w, h: @integer;
       enter (# enter (w, h) ... #)
       exit THIS(Canvas).size
       #);
     open::<
       (* Open the BifrostCanvas, i.e. make it visible and start to
        * handle events.
        *)
       (# create::< (# ... #);
          defaultbackground: @boolean
            (* If defaultbackground is set to true,
             * THIS(BifrostCanvas) will appear with the same
             * background color as the surrounding window, otherwise
             * it will be set to white (unless otherwise specified by
             * backgroundpaint
             *);
       ...
       #);
     close::<
       (* Close the BifrostCanvas, i.e. make it disappear and forget
        * all information stored in it.
        *)
       (# ... #);
     writeEPS:<
       (* Write Encapsulated PostScript to the stream out *)
       (# out: ^Stream;
          pagesize: @rectangle;
          vertical: @boolean;
          noOfCopies: @integer;
       enter (pagesize, vertical, noOfCopies, out[])
       do ...
       #);
     readEPS:< 
       (* Reads an EPS file written with writeEPS from stream inFile *)
       (# 
          inFile: ^Stream;
       enter inFile[]
       ...
       #);
     setClip:
       (* Make clipShape the new clipping region in
        * THIS(BifrostCanvas)
        *)
       (# 
       enter clipShape[]
       do ...;
       #);
     getClip:
       (* Exit the clipping region of THIS(BifrostCanvas) *)
       (# exit clipShape[] #);
     deviceToCanvas:
       (* Transform p1 from Device coordinates to BifrostCanvas
        * coordinates.
        *)
       (# p1,p2: @Point;
       enter p1
       ...
       exit p2
       #);
     canvasToDevice:
       (* Transform p1 from BifrostCanvas coordinates to Device
        * coordinates.
        *)
       (# p1,p2: @Point;
       enter p1
       ... 
       exit p2
       #);
     
     canvasToDeviceRectangle:
       (* Transform r from BifrostCanvas coordinates to Device coordinates. *)
       (# r: @Rectangle;
       enter r
       do r -> TM.transformRectangle -> r;
       exit r
       #);
     
     deviceToCanvasRectangle:
       (* Transform r from BifrostCanvas coordinates to Device coordinates. *)
       (# r: @Rectangle;
       enter r
       do r -> TM.inverseTransformRectangle -> r;
       exit r
       #);

     (* DAMAGE / REPAIR *)
     damaged:
       (* Inform THIS(BifrostCanvas) that r has been damaged, and
        * thus should be a part of the area redrawn upon the next
        * repair.
        *)
       (# r: @Rectangle;
       enter r
       do ...;
       #);
     repair: 
       (* Redraw all damaged areas in THIS(BifrostCanvas) *)
       (# do ... #);
     
     
     (* INTERACTION *)
     interactionHandler:
       (* Specialize THIS(BifrostCanvas).InteractionHandler to
        * perform an interaction.  Specialize the different virtuals
        * inside THIS(InteractionHandler) to perform actions in
        * response to various events.  Of course, using an
        * InteractionHandler only gives meaning if a pointing device
        * and/or a keyboard is connected to the actual device.
        * 
        * NOTICE: At most one InteractionHandler may active at any
        * given time
        *)
       (# initialize:<
            (* Called before THIS(InteractionHandler) is started *)
            (# ... #);
          motion:< 
            (* Called when the the pointing device has been moved *)
            object;
          idle:<
            (* Called repeatedly when no events are ready *)
            object;
          buttonPress:<
            (* Called when a button of the pointing device has been
             * pressed.
             *)
            (# button: @Integer enter button do INNER; #);
          buttonRelease:< object
            (* Called when a button of the pointing device has been
             * released
             *);
          keyPress:<
            (* Called when a key on the keyboard has been pressed *)
            (# ch: @Char; enter ch do INNER #);
          keyRelease:<
            (* Called when a key on the keyboard has been released *)
            (# ch: @Char; enter ch do INNER #);
          terminateCondition:< booleanObject
            (* Specifies under what condition to stop
             * THIS(InteractionHandler)
             *)
            (# ... #);
          terminated:<
            (* Called just before THIS(InteractionHandler) ends *)
            (# ... #);
          getPointerLocation: @
            (* Returns the current pointer location in device
             * coordinates
             *)
            (# thePoint: @Point;
            do ...;
            exit thePoint
            #);
          getGlobalPointerLocation: @
            (* Returns the current pointer location in screen
             * coordinates
             *)
            (# thePoint: @Point;
            do ...;
            exit thePoint
            #);
          isModifierOn: @booleanValue
            (* Tell if theModifier is currently being pressed *)
            (# theModifier: @Modifier;
            enter theModifier
            do ...;
            #);
          doubleClick: @booleanValue
            (* Answer if the last button press on the pointing device
             * was a double click
             *)
            (# ... #);
       do ...;
       #);
     interactiveCreateShape:
       (* Tell GO to start an interaction for creation on
        * THIS(BifrostCanvas)
        *)
       (# GO: ^AbstractGraphicalObject;
          p: @Point (* start interaction at p *);
          theModifier: @Modifier;
       enter (GO[],p,theModifier)
       ... 
       #);
     interactiveCombineShape:
       (* Tell GO to start an interaction for combination on
        * THIS(BifrostCanvas)
        *)
       (# GO: ^AbstractGraphicalObject;
          p: @Point (* start interaction at p *);
          theModifier: @Modifier;
       enter (GO[],p,theModifier)
       ... 
       #);
     interactiveReshape:
       (* Tell GO to start an interaction for reshaping on
        * THIS(BifrostCanvas)
        *)
       (# GO: ^AbstractGraphicalObject;
          p: @Point (* start interaction at p *);
          theModifier: @Modifier;
       enter (GO[],p,theModifier)
       ... 
       #);
     interactiveMove:
       (* Tell GO to start an interaction for motion on
        * THIS(BifrostCanvas).
        *)
       (# GO: ^AbstractGraphicalObject;
          p: @Point (* start interaction at p *);
          theModifier: @Modifier;
       enter (GO[],p,theModifier)
       ... 
       #);
     interactiveRotate: (* Not Yet Implemented *)
       (* Tell pict to start an interaction for rotation on
        * THIS(BifrostCanvas)
        *)
       (# GO: ^AbstractGraphicalObject;
          p: @Point (* start interaction at p *);
          theModifier: @Modifier;
       enter (GO[],p,theModifier)
       ... 
       #);
     interactiveScale: (* Not Yet Implemented *)
       (* Tell pict to start an interaction for scaling on
        * THIS(BifrostCanvas)
        *)
       (# GO: ^AbstractGraphicalObject;
          p: @Point (* start interaction at p *);
          theModifier: @Modifier;
       enter (GO[],p,theModifier)
       ... 
       #);
     bringForward:
       (* Bring aGO forward in THIS(BifrostCanvas).thePicture *)
       (# aGO: ^AbstractGraphicalObject;
       enter aGO[]                                                       
       ...
       #);
     sendBehind:
       (* Send aGO behind in THIS(BifrostCanvas).thePicture *)
       (# aGO: ^AbstractGraphicalObject;
       enter aGO[]                                                       
       ... 
       #);
     
     hitControl:
       (* Answer whether p is within 2 mm of a control point of aGO
        * Exits exact point if hit, NONE otherwise
        *)
       (# aGO: ^AbstractGraphicalObject;
          p: @Point;
          res: ^Point;
       enter (aGO[],p)
       ... 
       exit res[]
       #);
     hilite:
       (* Tell GO to highlight itself on THIS(BifrostCanvas) *)
       (# GO: ^AbstractGraphicalObject
       enter GO[]
       ... 
       #);
     unHilite:
       (* Tell GO to unhighlight itself on THIS(BifrostCanvas) *)
       (#  GO: ^AbstractGraphicalObject
       enter GO[]
       ... 
       #);
     
     (* Primitives for immediate drawing (sometimes also known as
      * transient drawing).  For efficiency all of these use DEVICE
      * coordinates.  Nothing drawn by means of these primitives can
      * be repaired automatically by THIS(BifrostCanvas).  Uses an
      * arbitrary color, that is guarentied to be different to what
      * is underneath.  May be erased by repeating the draw-request,
      * and is thus very useful for feedback in interaction.
      *)
     
     setImmediateLineWidth:
       (* Set the width used for immediate lines and arcs  *)
       (# lineWidth: @Integer;
       enter lineWidth
       ...
       #);
     immediatespot:
       (* Draw a small filled rectangle around center *)
       (# center: @Point;
       enter (center)
       ...
       #);
     immediateLine:
       (* Draw an immediate line from p1 to p2 *)
       (# p1,p2: @Point;
       enter (p1,p2)
       ...
       #);   
     immediateDot:
       (* Draw a dot of the size of one device-pixel at p *)
       (# p1: @Point;
       enter (p1)
       ...
       #);
     immediateMultiLine:
       (* Draw an immediate multiline specified by the points in p.
        * If close is true, the multiline will be closed by a line
        * from the first point to the last point.
        *)
       (# p: ^PointArray;
          close: @Boolean;
       enter (p[], close)
       do ...;
       #);
     immediateArc:
       (# cx, cy: @integer; (* Center coordinates *)
          hr, vr: @integer; (* Horizontal/vertical radius *)
          a1, a2: @integer; (* Defining angles in degrees *)
       enter (cx, cy, hr, vr, a1, a2)
       ...
       #); 
     immediaterect:
       (* Draw the outline of r *)
       (# r: @Rectangle;
       enter r
       ...
       #);
     immediateText:
       (* Draw theString at pos, with appearance as specified with
        * theFontName, theStyle, theSize, and underline
        *)
       (# pos: @Point;
          theFontName: @FontName;
          theStyle: @Style;
          theSize: @integer;
          underline: @boolean;
          theString: ^text;
       enter (pos, theFontName, theStyle, theSize, 
              underline, theString[])
       do ...
       #);
     
     (* Utility functions to convert between pixels and
      * milimeter.
      *)
     MMToPixel: (* Exits p scaled from mm to pixels *)
       (# p: @Point;    
       enter p
       do ...
       exit p
       #);
     pixelToMM: (* Exits p scaled from pixels to mm *)
       (# p: @Point;    
       enter p
       do ...
       exit p
       #);
     
     (* Utility to set zoom factor of THIS(BifrostCanvas).
      * The value 1.0 correponds to unzoomed state.
      *)
     ZoomFactor:
       (# set:
            (# z: @vector;
            enter z
            do ...
            #);
          get: 
            (# z: @vector;
            ...
            exit z
            #)
       enter set
       exit get
       #);
     
     (* PRIVATE *)
     
     privatePart: @ ...;
     TM: ^Matrix
       (* Transformation from THIS(BifrostCanvas) to the actual
        * device
        *);
  #);

14.32 Bifrost

-- LIB: attributes --
Bifrost: Guienv(# do INNER #)


14.1 Bifrost Interface
© 1991-2002 Mjølner Informatics
[Modified: Thursday September 23rd 1999 at 10:32]