-- SceneInternal.mesa: ``Unsynchronized but nice'' operations on scenes.
-- last modified by Stolfi - September 12, 1983 5:56 pm
-- To do: everything
DIRECTORY
Scene USING [SceneViewer],
ScenePrivate USING [Object, Thing, Group],
Graphics USING [Context];
SceneInternal: CEDAR DEFINITIONS
= PRIVATE BEGIN OPEN Cart: COGCart, Homo: COGHomo, Rope, Gr: Graphics;
-- UNSYNCHRONIZED BUT NICE OPERATIONS - - - - - - - - - - - - - - - - - - - - - -
-- The operations below are unsynchronized: Before calling them, the client must first acquire the appropriate access rights to the scene(s) involved. However, they are ``nice'', that is, they will automatically restore the internal invariants of the scene data structure after modifying it. In particular, they will automatically recompute the bounding boxes of the affected objects, and repaint them on the screen.
-- In typical usage, a client writes its own TreeAction procedure P that calls one or more of these operations, and passes P to ScenePrivate.DoWithWriteAccess. The difference between doing this and calling the self-synchronized procedures of the Scene inerface is that in the first case the tree and the viewer will remain locked throughout the execution of P, whereas in the second another process (including the menu/mouse/paint server) may sneak in between two consecutive operations.
SetTree: PROC [scene: SceneViewer, tree: Tree];
-- Unsynchronized; requires write rights to the scene containing the object.
-- Replaces the object tree currently attached to the given scene by the given new tree, and restores the invariants. In particular, recomputes the bounding boxes of the new tree, and schedules its repaint.
-- The current object tree of the scene (if any) becomes detached. Its bounding boxes are not recomputed. If the scene viewer has been destroyed, the operation is a no-op.
Remove: PROC [object: Object] RETURNS [oldParent: Group, oldNext: Object];
-- Unsynchronized; requires write rights to the scene containing the object.
-- The object is disconnected (with all its descendants) from its current parent. The subtree rooted at the object becomes a detached tree by itself.
-- If the object was attached to a scene, the affected portion of the image is repainted.
-- The procedure returns the old parent node (oldParent) of the object, and the old sibling (oldNext) that immediately followed it in the painting order. If the object was the last (topmost) child of oldParent, returns oldNext=NIL.
-- The object must not be a root.
Add: PROC [object: Object, newParent: Group, newNext: Object ← NIL];
-- Unsynchronized; requires write rights to the scene of the newParent.
-- Adds object (with its descendants) one of the children of newParent, immediately before (below) the specified child object newNext. If newNext= NIL, object is inserted as the last (topmost) child of newParent. The given newNext (if not NIL) must be a child of newParent.
-- The object to be added must be a detached root, and the newParent cannot be NIL.
-- If the newParent is attached to a scene, the affected portion of the image will be repainted.
-- PROPERTY LIST - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SetProp: PROC [object: Object, key: Atom, value: REF];
-- Unsynchronized. Requires write access to the object's scene.
-- Sets the value of the property named key for the given object. Removes the property if the value is NIL.
-- If the object is attached to a scene, recomputes the bounding boxes of the object and of all its descendants, adjusts the boxes of its ancestors, and schedules its repainting.
-- OBJECT ENUMERATION AND MODIFICATION - - - - - - - - - - - - - - - - - - - - -
ModifyObject: PROC
[object: Object, Modifier: ObjectModifier, context: Gr.context ← NIL];
-- Unsynchronized. Requires write access to the object's scene.
-- Modifies the object using the client-given Modifier, and restores the data structure invariants. In particular, if the object is attached, the procedure will recompute the bounding boxes of the object and of its descendants, adjust the bounding boxes of its ancestors in the tree, and schedule the object's repaint.
-- The context should be the scene viewer's context (as provided by ScenePrivate.DoWithWriteAccess and cognates) or NIL. It will be passed to the client's Modifier, after being clipped to the object's current bounding box.
ModifyAllObjects: PROC
[object: Object, Modifier: ObjectModifier, context: Gr.context ← NIL];
-- Unsynchronized. Requires write access to the object's scene.
-- Modifies the given object and all its descendants, using the client-given Modifier, and restores the data structure invariants. In particular, if the object is attached, the procedure will recompute the bounding boxes of the object and of its descendants, adjust the bounding boxes of its ancestors in the tree, and schedule the object's repaint. The descendants are visited in preorder (parent before children, and these in painting order).
-- The context should be the scene viewer's context (as provided by ScenePrivate.DoWithWriteAccess and cognates) or NIL. It will be passed to the each call to the client's Modifier, after being clipped to the object's current bounding box.
ModifyAllThings: PROC
[object: Object, Modifier: ObjectModifier, context: Gr.context ← NIL];
-- Unsynchronized. Requires write access to the object's scene.
-- Equivalent to ModifyAllObjects[object, Modifier], except that the Modifier is applied only to Things (not Groups) that are descendant of the the given object.
-- Will restore the data structure invariants. In particular, if the object is attached, the procedure will recompute the bounding boxes of the object and of its descendants, adjust the bounding boxes of its ancestors in the tree, and schedule repaint the affected part of the image. The things will be visited in painting order.
-- The context should be the scene viewer's context (as provided by ScenePrivate.DoWithWriteAccess and cognates) or NIL. It will be passed to the each call to the client's Modifier, after being clipped to the current bounding box of each thing to be modified.
ObjectModifier: TYPE = PROC [object: Object, context: Gr.Context]
RETURNS [changed: BOOL ← TRUE]
-- A client-written procedure for modifying the properties, parameters, class, or descendants of an object. It is applied by ModifyObject, ModifyAllObjects, and ModifyAllThings to one or more objects.
-- The context passed to ModifyObject, ModifyAllObjects, and ModifyAllThings will be passed along to the client's ObjectModifier. Usually, this will be the scene viewer's context (appropriately scaled and clipped). The ObjectModifier can draw at will on this contex, for example to show debugging information. Since the ModifyXXX procedures repaint the affected portion of the image on exit, such scribblings are ephemeral.
-- If the ObjectModifier decides not to modify the object it receives, it may optionally warn the caller (ModifyXXX) of this fact by returning changed=FALSE. This information may enable the caller to save some time in the repainting and restoration of the data structure invriants. This is useful mainly when the ObjectModifier changes only a few of the things enumerated by ModifyAllObjects or ModifyAllThings.
-- CAUTION: ModifyObject, ModifyAllObjects, and ModifyAllThings assume write access to the tree has been previously acquired by the client. Since the same lock is acquired by practically all procedures from the Scene interface, those procedures CANNOT be used inside an ObjectModifier, or a self-deadlock will result. The ObjectModifier may use SceneInternal.GetProp to examine the properties of the object pased to it.
-- Moreover, the three procedures above assume the ObjectModifier affects only the object that was given to it, and possibly its descendants. The ObjectModifier can make arbitrary changes to those nodes, but must not touch any other object, in any tree. In particular, it should not use any ``nice'' modifying procedure from this interface, since these procedures may adjust ancestor boxes. Most procedures from ScenePrivate (like ScenePrivate.SetProp, ScenePrivate.Remove, etc) can be used inside an ObjectModifier.

END.