When moving the Stations, there are two things to do to make the Rails 'stick' to the Station being moved: During the move, feedback of the Rails connecting the Station with other Stations, must be shown, and after the Station has been moved, the Rails must be physically moved too.
When a Station is moved by InteractiveMove, Bifrost automatically supplies feedback during the move. This is done by repeatedly executing an instance of the HiliteOutline virtual of the shape of the Station. When calling HiliteOutline, the drawing is done in XOR mode, meaning that drawings may be erased simply by drawing again. A Station is a Picture, and thus feedback for all graphical objects that have been added to this Picture is automatically provided. The Rails belonging to a Station, however, is not added to the Picture, and thus feedback for the rails is not supplied automatically. In subway6.bet, by further binding the HiliteOutline virtual of the Station pattern, the extra feedback is easily supplied:
Station: (# ...... shapedesc:: (# hiliteoutline:: (# do rails.scan (# do (if TM[]=NONE then (* No transformation *) (current.otherpoint -> CanvasToDevice, position -> CanvasToDevice) -> immediateline; else (current.otherpoint -> CanvasToDevice, position -> TM.transformpoint -> CanvasToDevice) -> immediateline; if); #); #); #); #)
HiliteOutline enters a reference to a Matrix called TM. If this reference is not NONE, it describes the transformation to apply to the feedback. E.g., if the Station has been moved a distance, TM will describe this translation. If the reference is NONE, no transformation is to be applied.
The feedback for a Rail will be a simple line from the position of the Station in question to the other end point of the Rail. To draw the actual feedback the 'immediate' drawing operations of Canvas are used. These operations draw directly into the Canvas, without adding the drawing to the 'memory' of the Canvas. The operations expect device coordinates. This is the reason why the coordinates are transformed by CanvasToDevice before being entered to immediateline. Instead of using position as the first end point of the immediate line, of course current.mypoint could have been used. Since the Station at the other end of the Rail considered is not moved, TM is only applied to the position of the Station being moved. Thus the feedback will be a 'rubber line' stuck to the two Stations it connects.
When the interaction is finished in InteractiveMove, as mentioned in "Making Rails", it calls the move virtual to actually move the graphical object considered. Again, since the Rails are not added to the Picture, move will not change the Rails, when the Picture is moved by InteractiveMove. Instead, this may be accomplished by further binding move:
Station: (# ...... move:: (# do (* Move is called by interactiveMove. * Furtherbind to move the rails too *) ... rails.scan (# do current.r.getbounds -> damaged; position -> current.mypoint; (* Changes either current.r.begin or * current.r.end *) current.r.getbounds -> damaged; #); #); ...... #)
In rails.scan, current.r is a reference to one of the rails connecting the Station with other Stations. First the bounding box of the rail is reported to myCanvas as being damaged. Then the newly transformed position is entered as the new end point of the Rail, belonging to the Station considered. Of course the other end point of the Rail should not be changed - this is also the reason why the Rails are not added to the Picture (the Station), since all members of a Picture are moved rigidly when the Picture is moved.
After the Rail has been changed, the new bounding box of it is also reported as being damaged. After InteractiveMove has called move, it also calls myCanvas.repair. This will make all damaged areas of myCanvas be redrawn, and since the areas the Rails have covered are now marked as damaged, this will complete the moving of the rails too.
The Bifrost Graphics System - Tutorial | © 1991-2004 Mjølner Informatics |
[Modified: Sunday October 15th 2000 at 15:36]
|