home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 August / macformat-027.iso / mac / Shareware City / Developers / Oberon⁄F / Samples / Mod / Ex9 (.txt) < prev    next >
Encoding:
Oberon Document  |  1994-06-07  |  10.1 KB  |  245 lines  |  [oODC/obnF]

  1. Documents.StdDocumentDesc
  2. Documents.DocumentDesc
  3. Containers.ViewDesc
  4. Views.ViewDesc
  5. Stores.StoreDesc
  6. Documents.ModelDesc
  7. Containers.ModelDesc
  8. Models.ModelDesc
  9. Stores.ElemDesc
  10. TextViews.StdViewDesc
  11. TextViews.ViewDesc
  12. TextModels.StdModelDesc
  13. TextModels.ModelDesc
  14. TextModels.AttributesDesc
  15. Geneva
  16. Geneva
  17. Geneva
  18. DevCommanders.StdViewDesc
  19. DevCommanders.ViewDesc
  20. Example 9
  21. This example implements a view which allows to draw lines with the mouse. Beyond line entry, the only interaction with such a view is through the keyboard: some characters are interpreted as colors, e.g. typing in an "r" sets a view's foreground color (in which the lines are drawn) to red. These two operations don't constitute a graphics editor yet, but can serve as a sketch for a more useful implementation. Full undo/redo of the two operations is supported, however.
  22. The implementation of SamplesEx9 is simple: there is a view, a model, and a line data structure. The model represents a view's graph, which consists of a linear list of lines. A line is described by its two end points (x0, y0) and (x1, y1). Each view has its own independent foreground color. There is an operation object for the entry of a line (a model operation), and an operation for the change of a foreground color (a view operation).
  23. When a line is entered (or the entry is undone), its bounding box is restored. For this purpose, a suitable update message is defined.
  24. There are two interesting aspects about the SamplesEx9 implementation:
  25. The contents of a graph, i.e. the linear list of lines, is immutable. This means that a line which has been inserted in a graph is never modified again. The list may become longer by having another line point at the existing line, but the existing line itself remains unchanged. For example, an undo operation merely changes the graph to show a shorter piece of its line list, redo shows a larger piece of it again.
  26. An immutable data structure has the nice property that it can be freely shared: copying can be implemented merely by letting another pointer point to the same data structure. This is used in the example below when copying the model.
  27. The second interesting feature of SamplesEx9 is the way rubberbanding is implemented. Rubberbanding is the feedback given when drawing a new line, as long as the mouse button is held down. Procedure HandleCtrlMsg shows a typical implementation of such a mechanism: it consists of a polling loop, which repeatedly polls the mouse button's state. When the mouse has moved, the old rubberband line must be erased, and a new one must be draw.
  28. Erasing the old rubberband line is done using a temporary buffer. Before entering the polling loop, the frame's visible area is saved in the frame's buffer (one buffer can be opened simultaneously per frame). In the polling loop, when the rubberband line must be erased, its bounding box is restored from the buffer. After the polling loop, the last rubberband line is erased the same way, except that the temporary buffer is disposed of simultaneously.
  29. MODULE SamplesEx9;
  30.     IMPORT Domains, Stores, Ports, Models, Views, Controllers;
  31.     CONST minVersion = 0; maxVersion = 0;
  32.     TYPE
  33.         Line = POINTER TO LineDesc;
  34.         LineDesc = RECORD
  35.             next: Line;
  36.             x0, y0, x1, y1: LONGINT
  37.         END;
  38.         Model = POINTER TO ModelDesc;
  39.         ModelDesc = RECORD (Models.ModelDesc)
  40.             lines: Line
  41.         END;
  42.         View = POINTER TO ViewDesc;
  43.         ViewDesc = RECORD (Views.ViewDesc)
  44.             color: Ports.Color;
  45.             graph: Model
  46.         END;
  47.         UpdateMsg = RECORD (Models.UpdateMsg)
  48.             l, t, r, b: LONGINT
  49.         END;
  50.         LineOp = POINTER TO LineOpDesc;
  51.         LineOpDesc = RECORD (Domains.OperationDesc)
  52.             graph: Model;
  53.             line: Line
  54.         END;
  55.         ColorOp = POINTER TO ColorOpDesc;
  56.         ColorOpDesc = RECORD (Domains.OperationDesc)
  57.             view: View;
  58.             color: Ports.Color
  59.         END;
  60.     PROCEDURE GetBox (x0, y0, x1, y1: LONGINT; VAR l, t, r, b: LONGINT);
  61.     BEGIN
  62.         IF x0 > x1 THEN l := x1; r := x0 ELSE l := x0; r := x1 END;
  63.         IF y0 > y1 THEN t := y1; b := y0 ELSE t := y0; b := y1 END;
  64.         INC(r, Ports.point); INC(b, Ports.point)
  65.     END GetBox;
  66.     PROCEDURE (op: LineOp) Do;
  67.         VAR l: Line; msg: UpdateMsg;
  68.     BEGIN
  69.         l := op.line;
  70.         IF l # op.graph.lines THEN    (* insert op.line *)
  71.             ASSERT(l # NIL, 100); ASSERT(l.next = op.graph.lines, 101);
  72.             op.graph.lines := l
  73.         ELSE    (* delete op.line *)
  74.             ASSERT(l = op.graph.lines, 102);
  75.             op.graph.lines := l.next
  76.         END;
  77.         GetBox(l.x0, l.y0, l.x1, l.y1, msg.l, msg.t, msg.r, msg.b); Models.Broadcast(op.graph, msg)
  78.     END Do;
  79.     PROCEDURE (m: Model) Clone (): Model;
  80.         VAR s: Stores.Store;
  81.     BEGIN
  82.         s := Stores.Clone(m); RETURN s(Model)
  83.     END Clone;
  84.     PROCEDURE (m: Model) Internalize (VAR rd: Stores.Reader);
  85.         VAR thisVersion: SHORTINT; x0: LONGINT; p: Line;
  86.     BEGIN
  87.         m.Internalize^(rd);
  88.         IF rd.cancelled THEN RETURN END;
  89.         rd.ReadVersion(minVersion, maxVersion, thisVersion);
  90.         IF rd.cancelled THEN RETURN END;
  91.         rd.ReadLInt(x0); m.lines := NIL;
  92.         WHILE x0 # MIN(LONGINT) DO
  93.             NEW(p); p.next := m.lines; m.lines := p;
  94.             p.x0 := x0; rd.ReadLInt(p.y0); rd.ReadLInt(p.x1); rd.ReadLInt(p.y1);
  95.             rd.ReadLInt(x0)
  96.         END
  97.     END Internalize;
  98.     PROCEDURE (m: Model) Externalize (VAR wr: Stores.Writer);
  99.         VAR p: Line;
  100.     BEGIN
  101.         m.Externalize^(wr);
  102.         wr.WriteVersion(maxVersion);
  103.         p := m.lines;
  104.         WHILE p # NIL DO
  105.             wr.WriteLInt(p.x0); wr.WriteLInt(p.y0); wr.WriteLInt(p.x1); wr.WriteLInt(p.y1);
  106.             p := p.next
  107.         END;
  108.         wr.WriteLInt(MIN(LONGINT))
  109.     END Externalize;
  110.     PROCEDURE (m: Model) CopyFrom (source: Model);
  111.     BEGIN
  112.         m.lines := source.lines; m.Init    (* lines can be shared *)
  113.     END CopyFrom;
  114.     PROCEDURE (m: Model) Insert (x0, y0, x1, y1: LONGINT);
  115.         VAR op: LineOp; p: Line;
  116.     BEGIN
  117.         NEW(op); op.graph := m;
  118.         NEW(p); p.next := m.lines; op.line := p;
  119.         p.x0 := x0; p.y0 := y0; p.x1 := x1; p.y1 := y1;
  120.         Models.Do(m, "Insert Line", op)
  121.     END Insert;
  122.     PROCEDURE (op: ColorOp) Do;
  123.         VAR color: Ports.Color;
  124.     BEGIN
  125.         color := op.view.color;    (* save old state *)
  126.         op.view.color := op.color;    (* set new state *)
  127.         Views.Update(op.view, Views.keepFrames);    (* restore everything *)
  128.         op.color := color    (* old state becomes new state for undo *)
  129.     END Do;
  130.     PROCEDURE (v: View) Internalize (VAR rd: Stores.Reader);
  131.         VAR thisVersion: SHORTINT; s: Stores.Store;
  132.     BEGIN
  133.         v.Internalize^(rd);
  134.         IF rd.cancelled THEN RETURN END;
  135.         rd.ReadVersion(minVersion, maxVersion, thisVersion);
  136.         IF rd.cancelled THEN RETURN END;
  137.         rd.ReadLInt(v.color);
  138.         rd.ReadStore(s); ASSERT(s # NIL, 100);
  139.         IF s IS Model THEN
  140.             v.graph := s(Model)
  141.         ELSE
  142.             rd.TurnIntoAlien(Stores.alienComponent)
  143.         END
  144.     END Internalize;
  145.     PROCEDURE (v: View) Externalize (VAR wr: Stores.Writer);
  146.     BEGIN
  147.         v.Externalize^(wr);
  148.         wr.WriteVersion(maxVersion);
  149.         wr.WriteLInt(v.color);
  150.         wr.WriteStore(v.graph)
  151.     END Externalize;
  152.     PROCEDURE (v: View) CopyFrom (source: Views.View);
  153.     BEGIN
  154.         v.CopyFrom^(source);
  155.         WITH source: View DO
  156.             v.color := source.color
  157.         END
  158.     END CopyFrom;
  159.     PROCEDURE (v: View) CopyModelFrom (source: Views.View; shallow: BOOLEAN);
  160.     BEGIN
  161.         WITH source: View DO
  162.             IF shallow THEN
  163.                 v.graph := source.graph    (* graph is shared *)
  164.             ELSE    (* clone and copy *)
  165.                 v.graph := source.graph.Clone(); v.graph.CopyFrom(source.graph)
  166.             END
  167.         END
  168.     END CopyModelFrom;
  169.     PROCEDURE (v: View) ThisModel (): Models.Model;
  170.     BEGIN
  171.         RETURN v.graph
  172.     END ThisModel;
  173.     PROCEDURE (v: View) Restore (f: Views.Frame; l, t, r, b: LONGINT);
  174.         VAR p: Line;
  175.     BEGIN
  176.         p := v.graph.lines;
  177.         WHILE p # NIL DO
  178.             f.DrawLine(p.x0, p.y0, p.x1, p.y1, f.dot, v.color);
  179.             p := p.next
  180.         END
  181.     END Restore;
  182.     PROCEDURE (v: View) HandleModelMsg (VAR msg: Models.Message);
  183.     BEGIN
  184.         WITH msg: UpdateMsg DO
  185.             Views.UpdateIn(v, msg.l, msg.t, msg.r, msg.b, Views.keepFrames)
  186.         ELSE
  187.         END
  188.     END HandleModelMsg;
  189.     PROCEDURE (v: View) SetColor (color: Ports.Color);
  190.         VAR op: ColorOp;
  191.     BEGIN
  192.         NEW(op); op.view := v; op.color := color; Views.Do(v, "Set Color", op)
  193.     END SetColor;
  194.     PROCEDURE (v: View) HandleCtrlMsg (f: Views.Frame; VAR msg: Views.CtrlMessage;
  195.                                                                 VAR focus: Views.View);
  196.         VAR x0, y0, x1, y1, x, y, res, l, t, r, b: LONGINT; isDown: BOOLEAN;
  197.     BEGIN
  198.         WITH msg: Controllers.TrackMsg DO
  199.             x0 := msg.x; y0 := msg.y; x1 := x0; y1 := y0;
  200.             f.SaveRect(f.l, f.t, f.r, f.b, res);    (* operation was successful if res = 0 *)
  201.             IF res = 0 THEN f.DrawLine(x0, y0, x1, y1, Ports.point, v.color) END;
  202.             REPEAT
  203.                 f.Input(x, y, isDown);
  204.                 IF (x # x1) OR (y # y1) THEN
  205.                     GetBox(x0, y0, x1, y1, l, t, r, b); f.RestoreRect(l, t, r, b, Ports.keepBuffer);
  206.                     x1 := x; y1 := y;
  207.                     IF res = 0 THEN f.DrawLine(x0, y0, x1, y1, Ports.point, v.color) END
  208.                 END
  209.             UNTIL ~isDown;
  210.             GetBox(x0, y0, x1, y1, l, t, r, b); f.RestoreRect(l, t, r, b, Ports.disposeBuffer);
  211.             v.graph.Insert(x0, y0, x1, y1)
  212.         | msg: Controllers.EditMsg DO
  213.             IF msg.op = Controllers.pasteChar THEN
  214.                 CASE msg.char OF
  215.                 | "B": v.SetColor(Ports.black)
  216.                 | "r": v.SetColor(Ports.red)
  217.                 | "g": v.SetColor(Ports.green)
  218.                 | "b": v.SetColor(Ports.blue)
  219.                 ELSE
  220.                 END
  221.             END
  222.         ELSE
  223.         END
  224.     END HandleCtrlMsg;
  225.     PROCEDURE Deposit*;
  226.         VAR m: Model; v: View;
  227.     BEGIN
  228.         NEW(m); m.lines := NIL; m.Init;
  229.         NEW(v); v.color := Ports.black; v.graph := m; v.Init;
  230.         Views.Deposit(v)
  231.     END Deposit;
  232. END SamplesEx9.
  233.  "SamplesEx9.Deposit; Open"
  234. TextControllers.StdCtrlDesc
  235. TextControllers.ControllerDesc
  236. Containers.ControllerDesc
  237. Controllers.ControllerDesc
  238. TextRulers.StdRulerDesc
  239. TextRulers.RulerDesc
  240. TextRulers.StdStyleDesc
  241. TextRulers.StyleDesc
  242. TextRulers.AttributesDesc
  243. Geneva
  244. Documents.ControllerDesc
  245.