Sam Pieters hai 1 ano
pai
achega
17274898ab

+ 2 - 2
README.md

@@ -97,5 +97,5 @@ python3 runner.py
 ### Timer
 
 ## TODO
-1) Is there no < or > in the condition transition
-
+1) How to do in_ui??
+2) Problem with getInstances --> with dissacociate it thinks that it still exists

+ 0 - 1
examples/BouncingBalls/sccd.xml

@@ -350,7 +350,6 @@
                 <state id="creating_circle">
                     <onentry>
                         <raise port="ui" event="create_circle">
-                            canvas_id, x, y, r, style, res_port
                             <parameter expr="self.canvas_id"/><!-- canvas_id -->
                             <parameter expr="self.pos['x']"/><!-- x -->
                             <parameter expr="self.pos['y']"/><!-- y -->

+ 9 - 1
examples/ElevatorBalls/PyDEVS/runner.py

@@ -15,7 +15,15 @@ class OutputListener:
 
 if __name__ == '__main__':
 	model = target.Controller(name="controller")
-	refs = {"ui": model.in_ui, "field_ui": model.atomic0.field_ui, "floor_ui": model.atomic1.floor_ui, "elevator_ui": model.atomic2.elevator_ui, "ball_ui": model.atomic3.ball_ui}
+	refs = {
+		"ui": model.in_ui,  
+		"field_ui": model.atomic0.field_ui, 
+		"floor_ui": model.atomic1.floor_ui, 
+		"control_ui": model.atomic2.control_ui,
+		"button_ui": model.atomic3.button_ui,
+		"elevator_ui": model.atomic4.elevator_ui, 
+		"ball_ui": model.atomic5.ball_ui
+		}
 
 	tkroot = tk.Tk()
 	tkroot.withdraw()

+ 374 - 80
examples/ElevatorBalls/PyDEVS/target.py

@@ -14,7 +14,7 @@ import time
 CANVAS_DIMS = (800, 550)
 FLOOR_LENGTH = 350
 FLOOR_SPACE = 50
-FLOORS = 4
+FLOORS = 3
 
 # package "Elevator Balls"
 
@@ -23,6 +23,7 @@ class MainAppInstance(RuntimeClassBase):
         RuntimeClassBase.__init__(self, atomdevs)
         self.associations = {}
         self.associations["floor"] = Association("Floor", 2, -1)
+        self.associations["controls"] = Association("ElevatorControls", 1, 1)
         self.associations["elevator"] = Association("Elevator", 1, 1)
         
         self.semantics.big_step_maximality = StatechartSemantics.TakeMany
@@ -76,20 +77,28 @@ class MainAppInstance(RuntimeClassBase):
         # state /wait
         self.states["/wait"] = State(4, "/wait", self)
         
+        # state /create_controls
+        self.states["/create_controls"] = State(5, "/create_controls", self)
+        
+        # state /creating_controls
+        self.states["/creating_controls"] = State(6, "/creating_controls", self)
+        
         # state /create_elevator
-        self.states["/create_elevator"] = State(5, "/create_elevator", self)
+        self.states["/create_elevator"] = State(7, "/create_elevator", self)
         
         # state /creating
-        self.states["/creating"] = State(6, "/creating", self)
+        self.states["/creating"] = State(8, "/creating", self)
         
         # state /waiting
-        self.states["/waiting"] = State(7, "/waiting", self)
+        self.states["/waiting"] = State(9, "/waiting", self)
         
         # add children
         self.states[""].addChild(self.states["/creating_window"])
         self.states[""].addChild(self.states["/creating_canvas"])
         self.states[""].addChild(self.states["/create_floors"])
         self.states[""].addChild(self.states["/wait"])
+        self.states[""].addChild(self.states["/create_controls"])
+        self.states[""].addChild(self.states["/creating_controls"])
         self.states[""].addChild(self.states["/create_elevator"])
         self.states[""].addChild(self.states["/creating"])
         self.states[""].addChild(self.states["/waiting"])
@@ -109,7 +118,7 @@ class MainAppInstance(RuntimeClassBase):
         self.states["/creating_canvas"].addTransition(_creating_canvas_0)
         
         # transition /create_floors
-        _create_floors_0 = Transition(self, self.states["/create_floors"], [self.states["/create_elevator"]])
+        _create_floors_0 = Transition(self, self.states["/create_floors"], [self.states["/create_controls"]])
         _create_floors_0.setTrigger(None)
         _create_floors_0.setGuard(self._create_floors_0_guard)
         self.states["/create_floors"].addTransition(_create_floors_0)
@@ -128,6 +137,18 @@ class MainAppInstance(RuntimeClassBase):
         _wait_1.setTrigger(Event("instance_started", None))
         self.states["/wait"].addTransition(_wait_1)
         
+        # transition /create_controls
+        _create_controls_0 = Transition(self, self.states["/create_controls"], [self.states["/creating_controls"]])
+        _create_controls_0.setAction(self._create_controls_0_exec)
+        _create_controls_0.setTrigger(None)
+        self.states["/create_controls"].addTransition(_create_controls_0)
+        
+        # transition /creating_controls
+        _creating_controls_0 = Transition(self, self.states["/creating_controls"], [self.states["/create_elevator"]])
+        _creating_controls_0.setAction(self._creating_controls_0_exec)
+        _creating_controls_0.setTrigger(Event("instance_created", None))
+        self.states["/creating_controls"].addTransition(_creating_controls_0)
+        
         # transition /create_elevator
         _create_elevator_0 = Transition(self, self.states["/create_elevator"], [self.states["/creating"]])
         _create_elevator_0.setAction(self._create_elevator_0_exec)
@@ -170,6 +191,13 @@ class MainAppInstance(RuntimeClassBase):
         association_name = parameters[0]
         self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
     
+    def _create_controls_0_exec(self, parameters):
+        self.big_step.outputEventOM(Event("create_instance", None, [self, "controls", "ElevatorControls", self.canvas_id]))
+    
+    def _creating_controls_0_exec(self, parameters):
+        association_name = parameters[0]
+        self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
+    
     def _create_elevator_0_exec(self, parameters):
         self.big_step.outputEventOM(Event("create_instance", None, [self, "elevator", "Elevator", self.canvas_id]))
     
@@ -189,6 +217,7 @@ class MainApp(ObjectManagerBase):
         self.input = self.addInPort("input")
         self.output = self.addOutPort("ui")
         self.outputs["floor"] = self.addOutPort("floor")
+        self.outputs["controls"] = self.addOutPort("controls")
         self.outputs["elevator"] = self.addOutPort("elevator")
         self.field_ui = self.addInPort("field_ui")
         self.instances[self.next_instance] = MainAppInstance(self)
@@ -281,10 +310,6 @@ class FloorInstance(RuntimeClassBase):
         _running_create_random_ball_0.setAction(self._running_create_random_ball_0_exec)
         _running_create_random_ball_0.setTrigger(Event("_0after"))
         self.states["/running/create_random_ball"].addTransition(_running_create_random_ball_0)
-        _running_create_random_ball_1 = Transition(self, self.states["/running/create_random_ball"], [self.states["/running/create_random_ball"]])
-        _running_create_random_ball_1.setAction(self._running_create_random_ball_1_exec)
-        _running_create_random_ball_1.setTrigger(Event("delete_ball", None))
-        self.states["/running/create_random_ball"].addTransition(_running_create_random_ball_1)
         
         # transition /running/wait
         _running_wait_0 = Transition(self, self.states["/running/wait"], [self.states["/running/create_random_ball"]])
@@ -304,10 +329,6 @@ class FloorInstance(RuntimeClassBase):
     def _running_create_random_ball_0_exec(self, parameters):
         self.big_step.outputEventOM(Event("create_instance", None, [self, "balls", "Ball", self.canvas_id, self.floor_num, 10, self.pos['y']]))
     
-    def _running_create_random_ball_1_exec(self, parameters):
-        association_name = parameters[0]
-        self.big_step.outputEventOM(Event("delete_instance", None, [self, association_name]))
-    
     def _running_wait_0_exec(self, parameters):
         association_name = parameters[0]
         self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
@@ -331,6 +352,271 @@ class Floor(ObjectManagerBase):
         new_instance = FloorInstance(self, parameters[2], parameters[3])
         return new_instance
 
+class ElevatorControlsInstance(RuntimeClassBase):
+    def __init__(self, atomdevs, canvas_id):
+        RuntimeClassBase.__init__(self, atomdevs)
+        self.associations = {}
+        self.associations["button"] = Association("ElevatorButton", 0, -1)
+        self.associations["balls"] = Association("Ball", 0, -1)
+        self.associations["parent"] = Association("Elevator", 1, 1)
+        
+        self.semantics.big_step_maximality = StatechartSemantics.TakeMany
+        self.semantics.internal_event_lifeline = StatechartSemantics.Queue
+        self.semantics.input_event_lifeline = StatechartSemantics.FirstComboStep
+        self.semantics.priority = StatechartSemantics.SourceParent
+        self.semantics.concurrency = StatechartSemantics.Single
+        
+        # build Statechart structure
+        self.build_statechart_structure()
+        
+        # call user defined constructor
+        ElevatorControlsInstance.user_defined_constructor(self, canvas_id)
+        port_name = Ports.addInputPort("<narrow_cast>", self)
+        atomdevs.addInPort(port_name)
+        port_name = Ports.addInputPort("control_ui", self)
+        atomdevs.addInPort(port_name)
+        atomdevs.port_mappings[port_name] = atomdevs.next_instance
+        self.inports["control_ui"] = port_name
+    
+    def user_defined_constructor(self, canvas_id):
+        self.canvas_id = canvas_id;
+        self.button_num = FLOORS;
+        self.dim = {'x': 120, 'y': (50 + (FLOORS * 30))}
+        self.pos = {'x': CANVAS_DIMS[0] - ((self.dim['x'] / 2) + 10), 'y': (self.dim['y'] / 2) + 10}
+    
+    def user_defined_destructor(self):
+        pass
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, "", self)
+        
+        # state /creating
+        self.states["/creating"] = State(1, "/creating", self)
+        
+        # state /creating/create_rect
+        self.states["/creating/create_rect"] = State(2, "/creating/create_rect", self)
+        self.states["/creating/create_rect"].setEnter(self._creating_create_rect_enter)
+        
+        # state /creating/create_buttons
+        self.states["/creating/create_buttons"] = State(3, "/creating/create_buttons", self)
+        
+        # state /creating/create_buttons/create_a_button
+        self.states["/creating/create_buttons/create_a_button"] = State(4, "/creating/create_buttons/create_a_button", self)
+        self.states["/creating/create_buttons/create_a_button"].setEnter(self._creating_create_buttons_create_a_button_enter)
+        
+        # state /creating/create_buttons/start_a_button
+        self.states["/creating/create_buttons/start_a_button"] = State(5, "/creating/create_buttons/start_a_button", self)
+        
+        # state /creating/create_buttons/check_next
+        self.states["/creating/create_buttons/check_next"] = State(6, "/creating/create_buttons/check_next", self)
+        
+        # state /running
+        self.states["/running"] = State(7, "/running", self)
+        
+        # add children
+        self.states[""].addChild(self.states["/creating"])
+        self.states[""].addChild(self.states["/running"])
+        self.states["/creating"].addChild(self.states["/creating/create_rect"])
+        self.states["/creating"].addChild(self.states["/creating/create_buttons"])
+        self.states["/creating/create_buttons"].addChild(self.states["/creating/create_buttons/create_a_button"])
+        self.states["/creating/create_buttons"].addChild(self.states["/creating/create_buttons/start_a_button"])
+        self.states["/creating/create_buttons"].addChild(self.states["/creating/create_buttons/check_next"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/creating"]
+        self.states["/creating"].default_state = self.states["/creating/create_rect"]
+        self.states["/creating/create_buttons"].default_state = self.states["/creating/create_buttons/create_a_button"]
+        
+        # transition /creating/create_rect
+        _creating_create_rect_0 = Transition(self, self.states["/creating/create_rect"], [self.states["/creating/create_buttons"]])
+        _creating_create_rect_0.setTrigger(None)
+        self.states["/creating/create_rect"].addTransition(_creating_create_rect_0)
+        
+        # transition /creating/create_buttons/create_a_button
+        _creating_create_buttons_create_a_button_0 = Transition(self, self.states["/creating/create_buttons/create_a_button"], [self.states["/creating/create_buttons/start_a_button"]])
+        _creating_create_buttons_create_a_button_0.setAction(self._creating_create_buttons_create_a_button_0_exec)
+        _creating_create_buttons_create_a_button_0.setTrigger(Event("instance_created", None))
+        self.states["/creating/create_buttons/create_a_button"].addTransition(_creating_create_buttons_create_a_button_0)
+        
+        # transition /creating/create_buttons/start_a_button
+        _creating_create_buttons_start_a_button_0 = Transition(self, self.states["/creating/create_buttons/start_a_button"], [self.states["/creating/create_buttons/check_next"]])
+        _creating_create_buttons_start_a_button_0.setTrigger(Event("instance_started", None))
+        self.states["/creating/create_buttons/start_a_button"].addTransition(_creating_create_buttons_start_a_button_0)
+        
+        # transition /creating/create_buttons/check_next
+        _creating_create_buttons_check_next_0 = Transition(self, self.states["/creating/create_buttons/check_next"], [self.states["/creating/create_buttons/create_a_button"]])
+        _creating_create_buttons_check_next_0.setAction(self._creating_create_buttons_check_next_0_exec)
+        _creating_create_buttons_check_next_0.setTrigger(None)
+        _creating_create_buttons_check_next_0.setGuard(self._creating_create_buttons_check_next_0_guard)
+        self.states["/creating/create_buttons/check_next"].addTransition(_creating_create_buttons_check_next_0)
+        _creating_create_buttons_check_next_1 = Transition(self, self.states["/creating/create_buttons/check_next"], [self.states["/running"]])
+        _creating_create_buttons_check_next_1.setTrigger(None)
+        _creating_create_buttons_check_next_1.setGuard(self._creating_create_buttons_check_next_1_guard)
+        self.states["/creating/create_buttons/check_next"].addTransition(_creating_create_buttons_check_next_1)
+        
+        # transition /running
+        _running_0 = Transition(self, self.states["/running"], [self.states["/running"]])
+        _running_0.setAction(self._running_0_exec)
+        _running_0.setTrigger(Event("button_pressed", None))
+        self.states["/running"].addTransition(_running_0)
+    
+    def _creating_create_rect_enter(self):
+        self.big_step.outputEvent(Event("create_rectangle", self.getOutPortName("ui"), [self.canvas_id, self.pos['x'], self.pos['y'], self.dim['x'], self.dim['y'], {'fill':'grey', 'outline': 'black'}, self.inports['control_ui']]))
+        self.big_step.outputEvent(Event("create_text", self.getOutPortName("ui"), [self.canvas_id, self.pos['x'], 20, 'Elevator Controls', self.inports['control_ui']]))
+        self.big_step.outputEvent(Event("bind_event", self.getOutPortName("ui"), [self.canvas_id, ui.EVENTS.MOUSE_MOVE, 'mouse_move', self.inports['control_ui']]))
+    
+    def _creating_create_buttons_create_a_button_enter(self):
+        self.big_step.outputEventOM(Event("create_instance", None, [self, "button", "ElevatorButton", self.canvas_id, self.button_num]))
+    
+    def _creating_create_buttons_create_a_button_0_exec(self, parameters):
+        association_name = parameters[0]
+        self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
+    
+    def _creating_create_buttons_check_next_0_exec(self, parameters):
+        self.button_num -= 1
+    
+    def _creating_create_buttons_check_next_0_guard(self, parameters):
+        return self.button_num != 0
+    
+    def _creating_create_buttons_check_next_1_guard(self, parameters):
+        return self.button_num == 0
+    
+    def _running_0_exec(self, parameters):
+        floor = parameters[0]
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("move_elevator", None, [0])]))
+    
+    def initializeStatechart(self):
+        # enter default state
+        self.default_targets = self.states["/creating"].getEffectiveTargetStates()
+        RuntimeClassBase.initializeStatechart(self)
+
+class ElevatorControls(ObjectManagerBase):
+    def __init__(self, name):
+        ObjectManagerBase.__init__(self, name)
+        self.input = self.addInPort("input")
+        self.output = self.addOutPort("ui")
+        self.outputs["button"] = self.addOutPort("button")
+        self.outputs["balls"] = self.addOutPort("balls")
+        self.outputs["parent"] = self.addOutPort("parent")
+        self.control_ui = self.addInPort("control_ui")
+    
+    def constructObject(self, parameters):
+        new_instance = ElevatorControlsInstance(self, parameters[2])
+        return new_instance
+
+class ElevatorButtonInstance(RuntimeClassBase):
+    def __init__(self, atomdevs, canvas_id, number):
+        RuntimeClassBase.__init__(self, atomdevs)
+        self.associations = {}
+        self.associations["parent"] = Association("ElevatorControls", 1, 1)
+        
+        self.semantics.big_step_maximality = StatechartSemantics.TakeMany
+        self.semantics.internal_event_lifeline = StatechartSemantics.Queue
+        self.semantics.input_event_lifeline = StatechartSemantics.FirstComboStep
+        self.semantics.priority = StatechartSemantics.SourceParent
+        self.semantics.concurrency = StatechartSemantics.Single
+        
+        # build Statechart structure
+        self.build_statechart_structure()
+        
+        # call user defined constructor
+        ElevatorButtonInstance.user_defined_constructor(self, canvas_id, number)
+        port_name = Ports.addInputPort("<narrow_cast>", self)
+        atomdevs.addInPort(port_name)
+        port_name = Ports.addInputPort("button_ui", self)
+        atomdevs.addInPort(port_name)
+        atomdevs.port_mappings[port_name] = atomdevs.next_instance
+        self.inports["button_ui"] = port_name
+    
+    def user_defined_constructor(self, canvas_id, number):
+        self.canvas_id = canvas_id;
+        self.button_id = None;
+        
+        self.dim = {'x': 120, 'y': (50 + (FLOORS * 30))}
+        self.pos = {'x': CANVAS_DIMS[0] - ((self.dim['x'] / 2) + 10), 'y': (self.dim['y'] / 2) + 10}
+        self.r = 10
+        self.number = number;
+    
+    def user_defined_destructor(self):
+        pass
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, "", self)
+        
+        # state /creating
+        self.states["/creating"] = State(1, "/creating", self)
+        self.states["/creating"].setEnter(self._creating_enter)
+        
+        # state /running
+        self.states["/running"] = State(2, "/running", self)
+        
+        # add children
+        self.states[""].addChild(self.states["/creating"])
+        self.states[""].addChild(self.states["/running"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/creating"]
+        
+        # transition /creating
+        _creating_0 = Transition(self, self.states["/creating"], [self.states["/running"]])
+        _creating_0.setAction(self._creating_0_exec)
+        _creating_0.setTrigger(Event("circle_created", None))
+        self.states["/creating"].addTransition(_creating_0)
+        
+        # transition /running
+        _running_0 = Transition(self, self.states["/running"], [self.states["/running"]])
+        _running_0.setAction(self._running_0_exec)
+        _running_0.setTrigger(Event("button_click", self.getInPortName("button_ui")))
+        _running_0.setGuard(self._running_0_guard)
+        self.states["/running"].addTransition(_running_0)
+    
+    def _creating_enter(self):
+        self.big_step.outputEvent(Event("create_circle", self.getOutPortName("ui"), [self.canvas_id, CANVAS_DIMS[0] - 70, 45 + (30 * (FLOORS - self.number)) , 10, {'fill':'black', 'outline': 'black'}, self.inports['button_ui']]))
+        self.big_step.outputEvent(Event("create_text", self.getOutPortName("ui"), [self.canvas_id, CANVAS_DIMS[0] - 70, 45 + (30 * (FLOORS - self.number)) , str(self.number), self.inports['button_ui']]))
+    
+    def _creating_0_exec(self, parameters):
+        canvas_id = parameters[0]
+        circle_id = parameters[1]
+        self.button_id = circle_id
+        self.big_step.outputEvent(Event("bind_canvas_event", self.getOutPortName("ui"), [canvas_id, circle_id, ui.EVENTS.MOUSE_PRESS, 'button_click', self.inports['button_ui']]))
+        self.big_step.outputEvent(Event("bind_canvas_event", self.getOutPortName("ui"), [self.canvas_id, circle_id, ui.EVENTS.MOUSE_MOVE, 'mouse_move', self.inports['button_ui']]))
+    
+    def _running_0_exec(self, parameters):
+        x = parameters[0]
+        y = parameters[1]
+        button = parameters[2]
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("button_pressed", None, [self.number])]))
+        self.big_step.outputEvent(Event("set_element_color", self.getOutPortName("ui"), [self.canvas_id, self.button_id, '#ff0']))
+    
+    def _running_0_guard(self, parameters):
+        x = parameters[0]
+        y = parameters[1]
+        button = parameters[2]
+        return button == ui.MOUSE_BUTTONS.LEFT
+    
+    def initializeStatechart(self):
+        # enter default state
+        self.default_targets = self.states["/creating"].getEffectiveTargetStates()
+        RuntimeClassBase.initializeStatechart(self)
+
+class ElevatorButton(ObjectManagerBase):
+    def __init__(self, name):
+        ObjectManagerBase.__init__(self, name)
+        self.input = self.addInPort("input")
+        self.output = self.addOutPort("ui")
+        self.outputs["parent"] = self.addOutPort("parent")
+        self.button_ui = self.addInPort("button_ui")
+    
+    def constructObject(self, parameters):
+        new_instance = ElevatorButtonInstance(self, parameters[2], parameters[3])
+        return new_instance
+
 class ElevatorInstance(RuntimeClassBase):
     def __init__(self, atomdevs, canvas_id):
         RuntimeClassBase.__init__(self, atomdevs)
@@ -363,19 +649,14 @@ class ElevatorInstance(RuntimeClassBase):
     
     def user_defined_constructor(self, canvas_id):
         self.canvas_id = canvas_id;
-        self.button_ids = {
-            'up': None,
-            'down': None,
-            'open': None
-        };
-        self.open_button = None;
+        
         self.is_open = False;
         
         elevator_height = (CANVAS_DIMS[1] - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
         
         self.dim = {'x': elevator_height, 'y': elevator_height};
-        self.vel = {'x': 0, 'y': -2};
-        self.pos = {'x': FLOOR_LENGTH + (elevator_height / 2), 'y': 75};
+        self.vel = -2;
+        self.pos = {'x': FLOOR_LENGTH + (elevator_height / 2), 'y': (CANVAS_DIMS[1] - (elevator_height / 2))};
         self.smooth = 0.6; # value between 0 and 1
     
     def user_defined_destructor(self):
@@ -400,17 +681,26 @@ class ElevatorInstance(RuntimeClassBase):
         
         # state /root/running
         self.states["/root/running"] = State(4, "/root/running", self)
-        self.states["/root/running"].setEnter(self._root_running_enter)
-        self.states["/root/running"].setExit(self._root_running_exit)
+        
+        # state /root/running/waiting
+        self.states["/root/running/waiting"] = State(5, "/root/running/waiting", self)
+        
+        # state /root/running/move
+        self.states["/root/running/move"] = State(6, "/root/running/move", self)
+        self.states["/root/running/move"].setEnter(self._root_running_move_enter)
+        self.states["/root/running/move"].setExit(self._root_running_move_exit)
         
         # add children
         self.states[""].addChild(self.states["/root"])
         self.states["/root"].addChild(self.states["/root/waiting"])
         self.states["/root"].addChild(self.states["/root/creating_elevator"])
         self.states["/root"].addChild(self.states["/root/running"])
+        self.states["/root/running"].addChild(self.states["/root/running/waiting"])
+        self.states["/root/running"].addChild(self.states["/root/running/move"])
         self.states[""].fixTree()
         self.states[""].default_state = self.states["/root"]
         self.states["/root"].default_state = self.states["/root/waiting"]
+        self.states["/root/running"].default_state = self.states["/root/running/waiting"]
         
         # transition /root/waiting
         _root_waiting_0 = Transition(self, self.states["/root/waiting"], [self.states["/root/creating_elevator"]])
@@ -424,27 +714,28 @@ class ElevatorInstance(RuntimeClassBase):
         _root_creating_elevator_0.setTrigger(Event("rectangle_created", None))
         self.states["/root/creating_elevator"].addTransition(_root_creating_elevator_0)
         
-        # transition /root/running
-        _root_running_0 = Transition(self, self.states["/root/running"], [self.states["/root/running"]])
-        _root_running_0.setAction(self._root_running_0_exec)
-        _root_running_0.setTrigger(Event("_0after"))
-        self.states["/root/running"].addTransition(_root_running_0)
-        _root_running_1 = Transition(self, self.states["/root/running"], [self.states["/root/running"]])
-        _root_running_1.setAction(self._root_running_1_exec)
-        _root_running_1.setTrigger(Event("right_click", self.getInPortName("elevator_ui")))
-        self.states["/root/running"].addTransition(_root_running_1)
-        _root_running_2 = Transition(self, self.states["/root/running"], [self.states["/root/running"]])
-        _root_running_2.setAction(self._root_running_2_exec)
-        _root_running_2.setTrigger(Event("instance_created", None))
-        self.states["/root/running"].addTransition(_root_running_2)
+        # transition /root/running/waiting
+        _root_running_waiting_0 = Transition(self, self.states["/root/running/waiting"], [self.states["/root/running/move"]])
+        _root_running_waiting_0.setTrigger(Event("move_elevator", None))
+        self.states["/root/running/waiting"].addTransition(_root_running_waiting_0)
+        
+        # transition /root/running/move
+        _root_running_move_0 = Transition(self, self.states["/root/running/move"], [self.states["/root/running/move"]])
+        _root_running_move_0.setAction(self._root_running_move_0_exec)
+        _root_running_move_0.setTrigger(Event("_0after"))
+        self.states["/root/running/move"].addTransition(_root_running_move_0)
+        _root_running_move_1 = Transition(self, self.states["/root/running/move"], [self.states["/root/running/waiting"]])
+        _root_running_move_1.setTrigger(None)
+        _root_running_move_1.setGuard(self._root_running_move_1_guard)
+        self.states["/root/running/move"].addTransition(_root_running_move_1)
     
     def _root_creating_elevator_enter(self):
         self.big_step.outputEvent(Event("create_rectangle", self.getOutPortName("ui"), [self.canvas_id, self.pos['x'], self.pos['y'], self.dim['x'], self.dim['y'], {'fill':'white', 'outline': 'black'}, self.inports['elevator_ui']]))
     
-    def _root_running_enter(self):
+    def _root_running_move_enter(self):
         self.addTimer(0, 0.02)
     
-    def _root_running_exit(self):
+    def _root_running_move_exit(self):
         self.removeTimer(0)
     
     def _root_waiting_0_exec(self, parameters):
@@ -459,27 +750,13 @@ class ElevatorInstance(RuntimeClassBase):
         canvas_id = parameters[0]
         rect_id = parameters[1]
         self.elevator_id = rect_id
-        self.big_step.outputEvent(Event("bind_event", self.getOutPortName("ui"), [canvas_id, ui.EVENTS.MOUSE_RIGHT_CLICK, 'right_click', self.inports['elevator_ui']]))
     
-    def _root_running_0_exec(self, parameters):
-        # Invert velocity when colliding with canvas border:
-        if self.pos['y']-(self.dim['y']/2) <= 0 or self.pos['y']+(self.dim['y']/2) >= CANVAS_DIMS[1]:
-            self.vel['y'] = -self.vel['y'];
-        self.big_step.outputEvent(Event("move_element", self.getOutPortName("ui"), [self.canvas_id, self.elevator_id, self.vel['x'], self.vel['y']]))
-        self.pos['x'] += self.vel['x']
-        self.pos['y'] += self.vel['y']
-        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'balls', Event("update_bounds", None, [self.pos, self.dim, self.vel])]))
-    
-    def _root_running_1_exec(self, parameters):
-        x = parameters[0]
-        y = parameters[1]
-        button = parameters[2]
-        self.big_step.outputEventOM(Event("create_instance", None, [self, "balls", "Ball", self.canvas_id, -1, x, y]))
+    def _root_running_move_0_exec(self, parameters):
+        self.big_step.outputEvent(Event("set_element_pos", self.getOutPortName("ui"), [self.canvas_id, self.elevator_id, self.pos['x'], self.pos['y']]))
+        self.pos['y'] += self.vel
     
-    def _root_running_2_exec(self, parameters):
-        association_name = parameters[0]
-        self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
-        self.big_step.outputEventOM(Event("narrow_cast", None, [self, association_name, Event("set_association_name", None, [association_name])]))
+    def _root_running_move_1_guard(self, parameters):
+        return (self.pos['y'] - (self.dim['y']/2)) < 0
     
     def initializeStatechart(self):
         # enter default state
@@ -566,8 +843,11 @@ class BallInstance(RuntimeClassBase):
         # state /main_behaviour/selected
         self.states["/main_behaviour/selected"] = State(6, "/main_behaviour/selected", self)
         
+        # state /main_behaviour/ball_delete
+        self.states["/main_behaviour/ball_delete"] = State(7, "/main_behaviour/ball_delete", self)
+        
         # state /deleted
-        self.states["/deleted"] = State(7, "/deleted", self)
+        self.states["/deleted"] = State(8, "/deleted", self)
         
         # add children
         self.states[""].addChild(self.states["/main_behaviour"])
@@ -577,6 +857,7 @@ class BallInstance(RuntimeClassBase):
         self.states["/main_behaviour"].addChild(self.states["/main_behaviour/bouncing"])
         self.states["/main_behaviour"].addChild(self.states["/main_behaviour/dragging"])
         self.states["/main_behaviour"].addChild(self.states["/main_behaviour/selected"])
+        self.states["/main_behaviour"].addChild(self.states["/main_behaviour/ball_delete"])
         self.states[""].fixTree()
         self.states[""].default_state = self.states["/main_behaviour"]
         self.states["/main_behaviour"].default_state = self.states["/main_behaviour/initializing"]
@@ -598,8 +879,7 @@ class BallInstance(RuntimeClassBase):
         _main_behaviour_bouncing_0.setAction(self._main_behaviour_bouncing_0_exec)
         _main_behaviour_bouncing_0.setTrigger(Event("_0after"))
         self.states["/main_behaviour/bouncing"].addTransition(_main_behaviour_bouncing_0)
-        _main_behaviour_bouncing_1 = Transition(self, self.states["/main_behaviour/bouncing"], [self.states["/main_behaviour/bouncing"]])
-        _main_behaviour_bouncing_1.setAction(self._main_behaviour_bouncing_1_exec)
+        _main_behaviour_bouncing_1 = Transition(self, self.states["/main_behaviour/bouncing"], [self.states["/main_behaviour/ball_delete"]])
         _main_behaviour_bouncing_1.setTrigger(None)
         _main_behaviour_bouncing_1.setGuard(self._main_behaviour_bouncing_1_guard)
         self.states["/main_behaviour/bouncing"].addTransition(_main_behaviour_bouncing_1)
@@ -629,10 +909,12 @@ class BallInstance(RuntimeClassBase):
         _main_behaviour_selected_0.setTrigger(Event("mouse_press", self.getInPortName("ball_ui")))
         _main_behaviour_selected_0.setGuard(self._main_behaviour_selected_0_guard)
         self.states["/main_behaviour/selected"].addTransition(_main_behaviour_selected_0)
-        _main_behaviour_selected_1 = Transition(self, self.states["/main_behaviour/selected"], [self.states["/deleted"]])
-        _main_behaviour_selected_1.setAction(self._main_behaviour_selected_1_exec)
-        _main_behaviour_selected_1.setTrigger(Event("delete_self", None))
-        self.states["/main_behaviour/selected"].addTransition(_main_behaviour_selected_1)
+        
+        # transition /main_behaviour/ball_delete
+        _main_behaviour_ball_delete_0 = Transition(self, self.states["/main_behaviour/ball_delete"], [self.states["/deleted"]])
+        _main_behaviour_ball_delete_0.setAction(self._main_behaviour_ball_delete_0_exec)
+        _main_behaviour_ball_delete_0.setTrigger(Event("delete_self", None))
+        self.states["/main_behaviour/ball_delete"].addTransition(_main_behaviour_ball_delete_0)
     
     def _main_behaviour_creating_circle_enter(self):
         self.big_step.outputEvent(Event("create_circle", self.getOutPortName("ui"), [self.canvas_id, self.pos['x'], self.pos['y'], self.r, {'fill':'#000'}, self.inports['ball_ui']]))
@@ -694,11 +976,8 @@ class BallInstance(RuntimeClassBase):
         self.pos['x'] += self.vel['x']
         self.pos['y'] += self.vel['y']
     
-    def _main_behaviour_bouncing_1_exec(self, parameters):
-        self.big_step.outputEvent(Event("destroy_element", self.getOutPortName("ui"), [self.canvas_id, self.circle_id]))
-    
     def _main_behaviour_bouncing_1_guard(self, parameters):
-        return self.pos['x'] - self.r < 6
+        return self.pos['x'] - self.r < 2
     
     def _main_behaviour_bouncing_2_exec(self, parameters):
         x = parameters[0]
@@ -756,9 +1035,9 @@ class BallInstance(RuntimeClassBase):
         button = parameters[2]
         return button == ui.MOUSE_BUTTONS.LEFT
     
-    def _main_behaviour_selected_1_exec(self, parameters):
+    def _main_behaviour_ball_delete_0_exec(self, parameters):
         self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("delete_ball", None, [self.association_name])]))
-        self.big_step.outputEvent(Event("destroy_element", self.getOutPortName("ui"), [self.canvas_id, self.element_id]))
+        self.big_step.outputEvent(Event("destroy_element", self.getOutPortName("ui"), [self.canvas_id, self.circle_id]))
     
     def initializeStatechart(self):
         # enter default state
@@ -788,6 +1067,8 @@ class ObjectManager(TheObjectManager):
         self.input = self.addInPort("input")
         self.output["MainApp"] = self.addOutPort()
         self.output["Floor"] = self.addOutPort()
+        self.output["ElevatorControls"] = self.addOutPort()
+        self.output["ElevatorButton"] = self.addOutPort()
         self.output["Elevator"] = self.addOutPort()
         self.output["Ball"] = self.addOutPort()
 
@@ -801,24 +1082,37 @@ class Controller(CoupledDEVS):
         self.objectmanager = self.addSubModel(ObjectManager("ObjectManager"))
         self.atomic0 = self.addSubModel(MainApp("MainApp"))
         self.atomic1 = self.addSubModel(Floor("Floor"))
-        self.atomic2 = self.addSubModel(Elevator("Elevator"))
-        self.atomic3 = self.addSubModel(Ball("Ball"))
+        self.atomic2 = self.addSubModel(ElevatorControls("ElevatorControls"))
+        self.atomic3 = self.addSubModel(ElevatorButton("ElevatorButton"))
+        self.atomic4 = self.addSubModel(Elevator("Elevator"))
+        self.atomic5 = self.addSubModel(Ball("Ball"))
         self.connectPorts(self.atomic0.obj_manager_out, self.objectmanager.input)
         self.connectPorts(self.objectmanager.output["MainApp"], self.atomic0.obj_manager_in)
         self.connectPorts(self.atomic0.outputs["floor"], self.atomic1.input)
-        self.connectPorts(self.atomic0.outputs["elevator"], self.atomic2.input)
+        self.connectPorts(self.atomic0.outputs["controls"], self.atomic2.input)
+        self.connectPorts(self.atomic0.outputs["elevator"], self.atomic4.input)
         self.connectPorts(self.atomic1.obj_manager_out, self.objectmanager.input)
         self.connectPorts(self.objectmanager.output["Floor"], self.atomic1.obj_manager_in)
-        self.connectPorts(self.atomic1.outputs["balls"], self.atomic3.input)
+        self.connectPorts(self.atomic1.outputs["balls"], self.atomic5.input)
         self.connectPorts(self.atomic1.outputs["parent"], self.atomic0.input)
         self.connectPorts(self.atomic2.obj_manager_out, self.objectmanager.input)
-        self.connectPorts(self.objectmanager.output["Elevator"], self.atomic2.obj_manager_in)
-        self.connectPorts(self.atomic2.outputs["balls"], self.atomic3.input)
-        self.connectPorts(self.atomic2.outputs["parent"], self.atomic0.input)
+        self.connectPorts(self.objectmanager.output["ElevatorControls"], self.atomic2.obj_manager_in)
+        self.connectPorts(self.atomic2.outputs["button"], self.atomic3.input)
+        self.connectPorts(self.atomic2.outputs["balls"], self.atomic5.input)
+        self.connectPorts(self.atomic2.outputs["parent"], self.atomic4.input)
         self.connectPorts(self.atomic3.obj_manager_out, self.objectmanager.input)
-        self.connectPorts(self.objectmanager.output["Ball"], self.atomic3.obj_manager_in)
-        self.connectPorts(self.atomic3.outputs["parent"], self.atomic0.input)
+        self.connectPorts(self.objectmanager.output["ElevatorButton"], self.atomic3.obj_manager_in)
+        self.connectPorts(self.atomic3.outputs["parent"], self.atomic2.input)
+        self.connectPorts(self.atomic4.obj_manager_out, self.objectmanager.input)
+        self.connectPorts(self.objectmanager.output["Elevator"], self.atomic4.obj_manager_in)
+        self.connectPorts(self.atomic4.outputs["balls"], self.atomic5.input)
+        self.connectPorts(self.atomic4.outputs["parent"], self.atomic0.input)
+        self.connectPorts(self.atomic5.obj_manager_out, self.objectmanager.input)
+        self.connectPorts(self.objectmanager.output["Ball"], self.atomic5.obj_manager_in)
+        self.connectPorts(self.atomic5.outputs["parent"], self.atomic0.input)
         self.connectPorts(self.atomic0.output, self.out_ui)
         self.connectPorts(self.atomic1.output, self.out_ui)
         self.connectPorts(self.atomic2.output, self.out_ui)
-        self.connectPorts(self.atomic3.output, self.out_ui)
+        self.connectPorts(self.atomic3.output, self.out_ui)
+        self.connectPorts(self.atomic4.output, self.out_ui)
+        self.connectPorts(self.atomic5.output, self.out_ui)

+ 102 - 63
examples/ElevatorBalls/Python/target.py

@@ -81,8 +81,8 @@ class MainApp(RuntimeClassBase):
         # state /creating
         self.states["/creating"] = State(8, "/creating", self)
         
-        # state /waiting
-        self.states["/waiting"] = State(9, "/waiting", self)
+        # state /running
+        self.states["/running"] = State(9, "/running", self)
         
         # add children
         self.states[""].addChild(self.states["/creating_window"])
@@ -93,7 +93,7 @@ class MainApp(RuntimeClassBase):
         self.states[""].addChild(self.states["/creating_controls"])
         self.states[""].addChild(self.states["/create_elevator"])
         self.states[""].addChild(self.states["/creating"])
-        self.states[""].addChild(self.states["/waiting"])
+        self.states[""].addChild(self.states["/running"])
         self.states[""].fixTree()
         self.states[""].default_state = self.states["/creating_window"]
         
@@ -148,10 +148,24 @@ class MainApp(RuntimeClassBase):
         self.states["/create_elevator"].addTransition(_create_elevator_0)
         
         # transition /creating
-        _creating_0 = Transition(self, self.states["/creating"], [self.states["/waiting"]])
+        _creating_0 = Transition(self, self.states["/creating"], [self.states["/running"]])
         _creating_0.setAction(self._creating_0_exec)
         _creating_0.setTrigger(Event("instance_created", None))
         self.states["/creating"].addTransition(_creating_0)
+        
+        # transition /running
+        _running_0 = Transition(self, self.states["/running"], [self.states["/running"]])
+        _running_0.setAction(self._running_0_exec)
+        _running_0.setTrigger(Event("create_ball", None))
+        self.states["/running"].addTransition(_running_0)
+        _running_1 = Transition(self, self.states["/running"], [self.states["/running"]])
+        _running_1.setAction(self._running_1_exec)
+        _running_1.setTrigger(Event("instance_created", None))
+        self.states["/running"].addTransition(_running_1)
+        _running_2 = Transition(self, self.states["/running"], [self.states["/running"]])
+        _running_2.setAction(self._running_2_exec)
+        _running_2.setTrigger(Event("update_bounds", None))
+        self.states["/running"].addTransition(_running_2)
     
     def _creating_window_enter(self):
         self.big_step.outputEvent(Event("create_window", self.getOutPortName("ui"), [CANVAS_DIMS[0], CANVAS_DIMS[1], "Bouncing Balls Elevator", self.inports['field_ui']]))
@@ -198,6 +212,23 @@ class MainApp(RuntimeClassBase):
         self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
         self.big_step.outputEventOM(Event("narrow_cast", None, [self, association_name, Event("set_association_name", None, [association_name, self.canvas_id, self.window_id])]))
     
+    def _running_0_exec(self, parameters):
+        floor_num = parameters[0]
+        x = parameters[1]
+        y = parameters[2]
+        self.big_step.outputEventOM(Event("create_instance", None, [self, "ball", "Ball", self.canvas_id, floor_num, x, y]))
+    
+    def _running_1_exec(self, parameters):
+        association_name = parameters[0]
+        self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, association_name, Event("set_association_name", None, [association_name])]))
+    
+    def _running_2_exec(self, parameters):
+        pos = parameters[0]
+        dim = parameters[1]
+        vel = parameters[2]
+        self.big_step.outputEventOM(Event("broad_cast", None, [self, Event("update_bounds", None, [pos, dim, vel])]))
+    
     def initializeStatechart(self):
         # enter default state
         self.default_targets = self.states["/creating_window"].getEffectiveTargetStates()
@@ -233,7 +264,12 @@ class Floor(RuntimeClassBase):
         y_dim = (CANVAS_DIMS[1] - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
         
         self.dim = {'x': FLOOR_LENGTH, 'y': y_dim};
-        self.pos = {'x': FLOOR_LENGTH / 2, 'y': (y_dim /2) + (self.floor_num * (y_dim + FLOOR_SPACE))};
+        
+        
+        # start position from the bottom instead of from the top
+        # self.pos = {'x': FLOOR_LENGTH / 2, 'y': (y_dim /2) + (self.floor_num * (y_dim + FLOOR_SPACE))};
+        
+        self.pos = {'x': FLOOR_LENGTH / 2, 'y': CANVAS_DIMS[1] - (y_dim /2) - ( self.floor_num * (y_dim + FLOOR_SPACE)  )};
     
     def user_defined_destructor(self):
         pass
@@ -257,14 +293,10 @@ class Floor(RuntimeClassBase):
         self.states["/running/create_random_ball"].setEnter(self._running_create_random_ball_enter)
         self.states["/running/create_random_ball"].setExit(self._running_create_random_ball_exit)
         
-        # state /running/wait
-        self.states["/running/wait"] = State(4, "/running/wait", self)
-        
         # add children
         self.states[""].addChild(self.states["/creating_floor"])
         self.states[""].addChild(self.states["/running"])
         self.states["/running"].addChild(self.states["/running/create_random_ball"])
-        self.states["/running"].addChild(self.states["/running/wait"])
         self.states[""].fixTree()
         self.states[""].default_state = self.states["/creating_floor"]
         self.states["/running"].default_state = self.states["/running/create_random_ball"]
@@ -275,16 +307,10 @@ class Floor(RuntimeClassBase):
         self.states["/creating_floor"].addTransition(_creating_floor_0)
         
         # transition /running/create_random_ball
-        _running_create_random_ball_0 = Transition(self, self.states["/running/create_random_ball"], [self.states["/running/wait"]])
+        _running_create_random_ball_0 = Transition(self, self.states["/running/create_random_ball"], [self.states["/running/create_random_ball"]])
         _running_create_random_ball_0.setAction(self._running_create_random_ball_0_exec)
         _running_create_random_ball_0.setTrigger(Event("_0after"))
         self.states["/running/create_random_ball"].addTransition(_running_create_random_ball_0)
-        
-        # transition /running/wait
-        _running_wait_0 = Transition(self, self.states["/running/wait"], [self.states["/running/create_random_ball"]])
-        _running_wait_0.setAction(self._running_wait_0_exec)
-        _running_wait_0.setTrigger(Event("instance_created", None))
-        self.states["/running/wait"].addTransition(_running_wait_0)
     
     def _creating_floor_enter(self):
         self.big_step.outputEvent(Event("create_rectangle", self.getOutPortName("ui"), [self.canvas_id, self.pos['x'], self.pos['y'], self.dim['x'], self.dim['y'], {'fill':'white', 'outline': 'black'}, self.inports['floor_ui']]))
@@ -296,12 +322,7 @@ class Floor(RuntimeClassBase):
         self.removeTimer(0)
     
     def _running_create_random_ball_0_exec(self, parameters):
-        self.big_step.outputEventOM(Event("create_instance", None, [self, "balls", "Ball", self.canvas_id, self.floor_num, 10, self.pos['y']]))
-    
-    def _running_wait_0_exec(self, parameters):
-        association_name = parameters[0]
-        self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
-        self.big_step.outputEventOM(Event("narrow_cast", None, [self, association_name, Event("set_association_name", None, [association_name])]))
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("create_ball", None, [self.floor_num, 10, self.pos['y']])]))
     
     def initializeStatechart(self):
         # enter default state
@@ -328,8 +349,8 @@ class ElevatorControls(RuntimeClassBase):
     
     def user_defined_constructor(self, canvas_id):
         self.canvas_id = canvas_id;
-        self.button_num = FLOORS;
-        self.dim = {'x': 120, 'y': (50 + (FLOORS * 30))}
+        self.button_num = (FLOORS - 1);
+        self.dim = {'x': 120, 'y': (50 + ((FLOORS - 1) * 30))}
         self.pos = {'x': CANVAS_DIMS[0] - ((self.dim['x'] / 2) + 10), 'y': (self.dim['y'] / 2) + 10}
     
     def user_defined_destructor(self):
@@ -414,7 +435,6 @@ class ElevatorControls(RuntimeClassBase):
     def _creating_create_rect_enter(self):
         self.big_step.outputEvent(Event("create_rectangle", self.getOutPortName("ui"), [self.canvas_id, self.pos['x'], self.pos['y'], self.dim['x'], self.dim['y'], {'fill':'grey', 'outline': 'black'}, self.inports['control_ui']]))
         self.big_step.outputEvent(Event("create_text", self.getOutPortName("ui"), [self.canvas_id, self.pos['x'], 20, 'Elevator Controls', self.inports['control_ui']]))
-        self.big_step.outputEvent(Event("bind_event", self.getOutPortName("ui"), [self.canvas_id, ui.EVENTS.MOUSE_MOVE, 'mouse_move', self.inports['control_ui']]))
     
     def _creating_create_buttons_create_a_button_enter(self):
         self.big_step.outputEventOM(Event("create_instance", None, [self, "button", "ElevatorButton", self.canvas_id, self.button_num]))
@@ -500,26 +520,25 @@ class ElevatorButton(RuntimeClassBase):
         # transition /running
         _running_0 = Transition(self, self.states["/running"], [self.states["/running"]])
         _running_0.setAction(self._running_0_exec)
-        _running_0.setTrigger(Event("button_click", self.getInPortName("button_ui")))
+        _running_0.setTrigger(Event("clicked", self.getInPortName("button_ui")))
         _running_0.setGuard(self._running_0_guard)
         self.states["/running"].addTransition(_running_0)
     
     def _creating_enter(self):
-        self.big_step.outputEvent(Event("create_circle", self.getOutPortName("ui"), [self.canvas_id, CANVAS_DIMS[0] - 70, 45 + (30 * (FLOORS - self.number)) , 10, {'fill':'black', 'outline': 'black'}, self.inports['button_ui']]))
-        self.big_step.outputEvent(Event("create_text", self.getOutPortName("ui"), [self.canvas_id, CANVAS_DIMS[0] - 70, 45 + (30 * (FLOORS - self.number)) , str(self.number), self.inports['button_ui']]))
+        self.big_step.outputEvent(Event("create_circle", self.getOutPortName("ui"), [self.canvas_id, CANVAS_DIMS[0] - 70, 45 + (30 * (FLOORS - 1 - self.number)) , 10, {'fill':'black', 'outline': 'black'}, self.inports['button_ui']]))
+        self.big_step.outputEvent(Event("create_text", self.getOutPortName("ui"), [self.canvas_id, CANVAS_DIMS[0] - 70, 45 + (30 * (FLOORS - 1 - self.number)) , str(self.number), self.inports['button_ui']]))
     
     def _creating_0_exec(self, parameters):
         canvas_id = parameters[0]
         circle_id = parameters[1]
         self.button_id = circle_id
-        self.big_step.outputEvent(Event("bind_canvas_event", self.getOutPortName("ui"), [canvas_id, circle_id, ui.EVENTS.MOUSE_PRESS, 'button_click', self.inports['button_ui']]))
+        self.big_step.outputEvent(Event("bind_canvas_event", self.getOutPortName("ui"), [self.canvas_id, circle_id, ui.EVENTS.MOUSE_PRESS, 'clicked', self.inports['button_ui']]))
         self.big_step.outputEvent(Event("bind_canvas_event", self.getOutPortName("ui"), [self.canvas_id, circle_id, ui.EVENTS.MOUSE_MOVE, 'mouse_move', self.inports['button_ui']]))
     
     def _running_0_exec(self, parameters):
         x = parameters[0]
         y = parameters[1]
         button = parameters[2]
-        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("button_pressed", None, [self.number])]))
         self.big_step.outputEvent(Event("set_element_color", self.getOutPortName("ui"), [self.canvas_id, self.button_id, '#ff0']))
     
     def _running_0_guard(self, parameters):
@@ -591,8 +610,10 @@ class Elevator(RuntimeClassBase):
         # state /root/running
         self.states["/root/running"] = State(4, "/root/running", self)
         
-        # state /root/running/waiting
-        self.states["/root/running/waiting"] = State(5, "/root/running/waiting", self)
+        # state /root/running/idle
+        self.states["/root/running/idle"] = State(5, "/root/running/idle", self)
+        self.states["/root/running/idle"].setEnter(self._root_running_idle_enter)
+        self.states["/root/running/idle"].setExit(self._root_running_idle_exit)
         
         # state /root/running/move
         self.states["/root/running/move"] = State(6, "/root/running/move", self)
@@ -604,12 +625,12 @@ class Elevator(RuntimeClassBase):
         self.states["/root"].addChild(self.states["/root/waiting"])
         self.states["/root"].addChild(self.states["/root/creating_elevator"])
         self.states["/root"].addChild(self.states["/root/running"])
-        self.states["/root/running"].addChild(self.states["/root/running/waiting"])
+        self.states["/root/running"].addChild(self.states["/root/running/idle"])
         self.states["/root/running"].addChild(self.states["/root/running/move"])
         self.states[""].fixTree()
         self.states[""].default_state = self.states["/root"]
         self.states["/root"].default_state = self.states["/root/waiting"]
-        self.states["/root/running"].default_state = self.states["/root/running/waiting"]
+        self.states["/root/running"].default_state = self.states["/root/running/idle"]
         
         # transition /root/waiting
         _root_waiting_0 = Transition(self, self.states["/root/waiting"], [self.states["/root/creating_elevator"]])
@@ -623,17 +644,17 @@ class Elevator(RuntimeClassBase):
         _root_creating_elevator_0.setTrigger(Event("rectangle_created", None))
         self.states["/root/creating_elevator"].addTransition(_root_creating_elevator_0)
         
-        # transition /root/running/waiting
-        _root_running_waiting_0 = Transition(self, self.states["/root/running/waiting"], [self.states["/root/running/move"]])
-        _root_running_waiting_0.setTrigger(Event("move_elevator", None))
-        self.states["/root/running/waiting"].addTransition(_root_running_waiting_0)
+        # transition /root/running/idle
+        _root_running_idle_0 = Transition(self, self.states["/root/running/idle"], [self.states["/root/running/move"]])
+        _root_running_idle_0.setTrigger(Event("_0after"))
+        self.states["/root/running/idle"].addTransition(_root_running_idle_0)
         
         # transition /root/running/move
         _root_running_move_0 = Transition(self, self.states["/root/running/move"], [self.states["/root/running/move"]])
         _root_running_move_0.setAction(self._root_running_move_0_exec)
-        _root_running_move_0.setTrigger(Event("_0after"))
+        _root_running_move_0.setTrigger(Event("_1after"))
         self.states["/root/running/move"].addTransition(_root_running_move_0)
-        _root_running_move_1 = Transition(self, self.states["/root/running/move"], [self.states["/root/running/waiting"]])
+        _root_running_move_1 = Transition(self, self.states["/root/running/move"], [self.states["/root/running/idle"]])
         _root_running_move_1.setTrigger(None)
         _root_running_move_1.setGuard(self._root_running_move_1_guard)
         self.states["/root/running/move"].addTransition(_root_running_move_1)
@@ -641,11 +662,18 @@ class Elevator(RuntimeClassBase):
     def _root_creating_elevator_enter(self):
         self.big_step.outputEvent(Event("create_rectangle", self.getOutPortName("ui"), [self.canvas_id, self.pos['x'], self.pos['y'], self.dim['x'], self.dim['y'], {'fill':'white', 'outline': 'black'}, self.inports['elevator_ui']]))
     
+    def _root_running_idle_enter(self):
+        self.addTimer(0, 5)
+    
+    def _root_running_idle_exit(self):
+        self.removeTimer(0)
+    
     def _root_running_move_enter(self):
-        self.addTimer(0, 0.02)
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("update_bounds", None, [self.pos, self.dim, self.vel])]))
+        self.addTimer(1, 0.02)
     
     def _root_running_move_exit(self):
-        self.removeTimer(0)
+        self.removeTimer(1)
     
     def _root_waiting_0_exec(self, parameters):
         association_name = parameters[0]
@@ -696,7 +724,15 @@ class Ball(RuntimeClassBase):
     
     def user_defined_constructor(self, canvas_id, floor_num, x, y):
         self.canvas_id = canvas_id;
+        
+        
         self.floor_num = floor_num;
+        
+        self.elevator_floor = 0;
+        self.elevator_open = True;
+        self.rect_pos = None;
+        self.rect_dim = None;
+        
         self.r = 5.0;
         self.vel = {'x': random.uniform(-5.0, 5.0), 'y': random.uniform(-5.0, 5.0)};
         self.pos = {'x': x, 'y': y};
@@ -823,41 +859,44 @@ class Ball(RuntimeClassBase):
         canvas_id = parameters[0]
         circle_id = parameters[1]
         self.circle_id = circle_id
-        self.big_step.outputEvent(Event("bind_canvas_event", self.getOutPortName("ui"), [self.canvas_id, circle_id, ui.EVENTS.MOUSE_PRESS, 'mouse_press', self.inports['ball_ui']]))
-        self.big_step.outputEvent(Event("bind_canvas_event", self.getOutPortName("ui"), [self.canvas_id, circle_id, ui.EVENTS.MOUSE_MOVE, 'mouse_move', self.inports['ball_ui']]))
-        self.big_step.outputEvent(Event("bind_canvas_event", self.getOutPortName("ui"), [self.canvas_id, circle_id, ui.EVENTS.MOUSE_RELEASE, 'mouse_release', self.inports['ball_ui']]))
     
     def _main_behaviour_bouncing_0_exec(self, parameters):
         if self.floor_num == -1:
             if self.pos['x'] - self.r < self.rect_pos['x'] - (self.rect_dim['x'] / 2):
-                self.pos['x'] = self.rect_pos['x'] - (self.rect_dim['x'] / 2) + self.r  # Correct position
-                self.vel['x'] = -self.vel['x'] + self.rect_vel['x']
+                if self.elevator_open:
+                    self.floor_num = self.elevator_floor
+                else:
+                    self.pos['x'] = self.rect_pos['x'] - (self.rect_dim['x'] / 2) + self.r
+                    self.vel['x'] = -self.vel['x']
             elif self.pos['x'] + self.r > self.rect_pos['x'] + (self.rect_dim['x'] / 2):
-                self.pos['x'] = self.rect_pos['x'] + (self.rect_dim['x'] / 2) - self.r  # Correct position
-                self.vel['x'] = -self.vel['x'] + self.rect_vel['x']
+                self.pos['x'] = self.rect_pos['x'] + (self.rect_dim['x'] / 2) - self.r
+                self.vel['x'] = -self.vel['x']
         
             # Check collision with the top and bottom borders
             if self.pos['y'] - self.r < self.rect_pos['y'] - (self.rect_dim['y'] / 2):
-                self.pos['y'] = self.rect_pos['y'] - (self.rect_dim['y'] / 2) + self.r  # Correct position
-                self.vel['y'] = -self.vel['y'] + self.rect_vel['y']
+                self.pos['y'] = self.rect_pos['y'] - (self.rect_dim['y'] / 2) + self.r
+                self.vel['y'] = -self.vel['y'] + self.rect_vel
             elif self.pos['y'] + self.r > self.rect_pos['y'] + (self.rect_dim['y'] / 2):
-                self.pos['y'] = self.rect_pos['y'] + (self.rect_dim['y'] / 2) - self.r  # Correct position
-                self.vel['y'] = -self.vel['y'] + self.rect_vel['y']
+                self.pos['y'] = self.rect_pos['y'] + (self.rect_dim['y'] / 2) - self.r
+                self.vel['y'] = -self.vel['y'] + self.rect_vel
         else:
             floor_height = (CANVAS_DIMS[1] - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
             floor_dim = {'x': FLOOR_LENGTH, 'y': floor_height};
-            floor_pos = {'x': FLOOR_LENGTH / 2, 'y': (floor_height /2) + (self.floor_num * (floor_height + FLOOR_SPACE))};
+            floor_pos = {'x': FLOOR_LENGTH / 2, 'y': CANVAS_DIMS[1] - (floor_height /2) - ( self.floor_num * (floor_height + FLOOR_SPACE)  )};
         
             if self.pos['x'] - self.r < floor_pos['x'] - (floor_dim['x'] / 2):
-                self.pos['x'] = floor_pos['x'] - (floor_dim['x'] / 2) + self.r  # Correct position
+                self.pos['x'] = floor_pos['x'] - (floor_dim['x'] / 2) + self.r
                 self.vel['x'] = -self.vel['x']
             elif self.pos['x'] + self.r > floor_pos['x'] + (floor_dim['x'] / 2):
-                self.pos['x'] = floor_pos['x'] + (floor_dim['x'] / 2) - self.r  # Correct position
-                self.vel['x'] = -self.vel['x']
+                if self.elevator_open and (self.elevator_floor == self.floor_num):
+                    self.floor_num = -1
+                else:
+                    self.pos['x'] = floor_pos['x'] + (floor_dim['x'] / 2) - self.r
+                    self.vel['x'] = -self.vel['x']
         
             # Check collision with the top and bottom borders
             if self.pos['y'] - self.r < floor_pos['y'] - (floor_dim['y'] / 2):
-                self.pos['y'] = floor_pos['y'] - (floor_dim['y'] / 2) + self.r  # Correct position
+                self.pos['y'] = floor_pos['y'] - (floor_dim['y'] / 2) + self.r
                 self.vel['y'] = -self.vel['y']
             elif self.pos['y'] + self.r > floor_pos['y'] + (floor_dim['y'] / 2):
                 self.pos['y'] = floor_pos['y'] + (floor_dim['y'] / 2) - self.r  # Correct position
@@ -888,6 +927,7 @@ class Ball(RuntimeClassBase):
         self.rect_pos = pos
         self.rect_dim = dim
         self.rect_vel = vel
+        self.elevator_open = False
     
     def _main_behaviour_dragging_0_exec(self, parameters):
         x = parameters[0]
@@ -917,7 +957,7 @@ class Ball(RuntimeClassBase):
         x = parameters[0]
         y = parameters[1]
         button = parameters[2]
-        self.mouse_pos = {'x':x, 'y':y};
+        self.mouse_pos = {'x': x, 'y': y};
     
     def _main_behaviour_selected_0_guard(self, parameters):
         x = parameters[0]
@@ -926,7 +966,7 @@ class Ball(RuntimeClassBase):
         return button == ui.MOUSE_BUTTONS.LEFT
     
     def _main_behaviour_ball_delete_0_exec(self, parameters):
-        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("delete_ball", None, [self.association_name])]))
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'floor', Event("delete_ball", None, [self.association_name])]))
         self.big_step.outputEvent(Event("destroy_element", self.getOutPortName("ui"), [self.canvas_id, self.circle_id]))
     
     def initializeStatechart(self):
@@ -945,16 +985,15 @@ class ObjectManager(ObjectManagerBase):
             instance.associations["floor"] = Association("Floor", 2, -1)
             instance.associations["controls"] = Association("ElevatorControls", 1, 1)
             instance.associations["elevator"] = Association("Elevator", 1, 1)
+            instance.associations["ball"] = Association("Ball", 0, -1)
         elif class_name == "Floor":
             instance = Floor(self.controller, construct_params[0], construct_params[1])
             instance.associations = {}
-            instance.associations["balls"] = Association("Ball", 0, -1)
             instance.associations["parent"] = Association("MainApp", 1, 1)
         elif class_name == "ElevatorControls":
             instance = ElevatorControls(self.controller, construct_params[0])
             instance.associations = {}
             instance.associations["button"] = Association("ElevatorButton", 0, -1)
-            instance.associations["balls"] = Association("Ball", 0, -1)
             instance.associations["parent"] = Association("Elevator", 1, 1)
         elif class_name == "ElevatorButton":
             instance = ElevatorButton(self.controller, construct_params[0], construct_params[1])
@@ -963,7 +1002,7 @@ class ObjectManager(ObjectManagerBase):
         elif class_name == "Elevator":
             instance = Elevator(self.controller, construct_params[0])
             instance.associations = {}
-            instance.associations["balls"] = Association("Ball", 0, -1)
+            instance.associations["floors"] = Association("Floors", 1, 1)
             instance.associations["parent"] = Association("MainApp", 1, 1)
         elif class_name == "Ball":
             instance = Ball(self.controller, construct_params[0], construct_params[1], construct_params[2], construct_params[3])

+ 93 - 82
examples/ElevatorBalls/sccd.xml

@@ -17,6 +17,7 @@
             <association name="floor" class="Floor" min="2"/>
             <association name="controls" class="ElevatorControls" min="1" max="1"/>
             <association name="elevator" class="Elevator" min="1" max="1"/>
+            <association name="ball" class="Ball" />
         </relationships>
         <attribute name="window_id" />
         <attribute name="canvas_id" />
@@ -126,7 +127,7 @@
                 </transition>
             </state>
             <state id="creating">
-                <transition event="instance_created" target="../waiting">
+                <transition event="instance_created" target="../running">
                     <parameter name="association_name" type="string"/>
                     <raise scope="cd" event="start_instance">
                         <parameter expr="association_name" />
@@ -138,7 +139,39 @@
                     </raise>
                 </transition>
             </state>
-            <state id="waiting">
+            <state id="running">
+                <transition event="create_ball" target=".">
+                    <parameter name="floor_num" type="int"/>
+                    <parameter name="x" type="int"/>
+                    <parameter name="y" type="int"/>
+                    <raise scope="cd" event="create_instance">
+                        <parameter expr='"ball"' />
+                        <parameter expr='"Ball"' />
+                        <parameter expr="self.canvas_id" />
+                        <parameter expr="floor_num" />
+                        <parameter expr="x" />
+                        <parameter expr="y" />
+                    </raise>
+                </transition>
+                <transition event='instance_created' target='.'>
+                    <parameter name="association_name" type="string"/>
+                    <raise scope="cd" event="start_instance">
+                        <parameter expr="association_name" />
+                    </raise>
+                    <raise scope="narrow" event="set_association_name" target="association_name">
+                        <parameter expr="association_name" />
+                    </raise>
+                </transition>
+                <transition event='update_bounds' target='.'>
+                    <parameter name="pos" type="dict"/>
+                    <parameter name="dim" type="dict"/>
+                    <parameter name="vel" type="int"/>
+                    <raise scope="broad" event="update_bounds">
+                        <parameter expr="pos" />
+                        <parameter expr="dim" />
+                        <parameter expr="vel" />
+                    </raise>
+                </transition>
             </state>
         </scxml>
     </class>
@@ -150,7 +183,6 @@
         <atrribute name="pos" />
         <inport name="floor_ui"/>
         <relationships>
-            <association name="balls" class="Ball" />
             <association name="parent" class="MainApp" min="1" max="1" />
         </relationships>
         <constructor>
@@ -164,7 +196,12 @@
                 y_dim = (CANVAS_DIMS[1] - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
 
                 self.dim = {'x': FLOOR_LENGTH, 'y': y_dim};
-                self.pos = {'x': FLOOR_LENGTH / 2, 'y': (y_dim /2) + (self.floor_num * (y_dim + FLOOR_SPACE))};
+
+
+                # start position from the bottom instead of from the top
+                # self.pos = {'x': FLOOR_LENGTH / 2, 'y': (y_dim /2) + (self.floor_num * (y_dim + FLOOR_SPACE))};
+
+                self.pos = {'x': FLOOR_LENGTH / 2, 'y': CANVAS_DIMS[1] - (y_dim /2) - ( self.floor_num * (y_dim + FLOOR_SPACE)  )};
                 ]]>
             </body>
         </constructor>
@@ -186,28 +223,14 @@
             </state>
             <state id="running" initial="create_random_ball">
                 <state id="create_random_ball" >
-                    <transition after="random.randint(2, 10)" target="../wait">
-                        <raise scope="cd" event="create_instance">
-                            <parameter expr='"balls"' />
-                            <parameter expr='"Ball"' />
-                            <parameter expr="self.canvas_id" />
+                    <transition after="random.randint(2, 10)" target=".">
+                        <raise scope="narrow" event="create_ball" target="'parent'">
                             <parameter expr="self.floor_num" />
                             <parameter expr="10" />
                             <parameter expr="self.pos['y']" />
                         </raise>
                     </transition>
                 </state>
-                <state id="wait">
-                    <transition event="instance_created" target="../create_random_ball">
-                        <parameter name="association_name" type="string"/>
-                        <raise scope="cd" event="start_instance">
-                            <parameter expr="association_name" />
-                        </raise>
-                        <raise scope="narrow" event="set_association_name" target="association_name">
-                            <parameter expr="association_name" />
-                        </raise>
-                    </transition>
-                </state>
             </state>
         </scxml>
     </class>
@@ -216,15 +239,14 @@
         <inport name="control_ui"/>
         <relationships>
             <association name="button" class="ElevatorButton" />
-            <association name="balls" class="Ball" />
             <association name="parent" class="Elevator" min="1" max="1" />
         </relationships>
         <constructor>
             <parameter name="canvas_id" />
             <body>
                 self.canvas_id = canvas_id;
-                self.button_num = FLOORS;
-                self.dim = {'x': 120, 'y': (50 + (FLOORS * 30))}
+                self.button_num = (FLOORS - 1);
+                self.dim = {'x': 120, 'y': (50 + ((FLOORS - 1) * 30))}
                 self.pos = {'x': CANVAS_DIMS[0] - ((self.dim['x'] / 2) + 10), 'y': (self.dim['y'] / 2) + 10}
             </body>
         </constructor>
@@ -248,12 +270,6 @@
                             <parameter expr="'Elevator Controls'"/>
                             <parameter expr="self.inports['control_ui']"/><!-- inport for response -->
                         </raise>
-                        <raise port="ui" event="bind_event">
-                            <parameter expr="self.canvas_id"/>                   <!-- widget_id -->
-                            <parameter expr="ui.EVENTS.MOUSE_MOVE"/>        <!-- tk_event -->
-                            <parameter expr="'mouse_move'"/>                <!-- sccd_event_name -->
-                            <parameter expr="self.inports['control_ui']"/>    <!-- inport for response -->
-                        </raise>
                     </onentry>
                     <transition target="../create_buttons" />
                 </state>
@@ -322,7 +338,7 @@
                     <raise port="ui" event="create_circle">
                         <parameter expr="self.canvas_id" />
                         <parameter expr="CANVAS_DIMS[0] - 70"/>
-                        <parameter expr="45 + (30 * (FLOORS - self.number)) "/>
+                        <parameter expr="45 + (30 * (FLOORS - 1 - self.number)) "/>
                         <parameter expr="10" />
                         <parameter expr="{'fill':'black', 'outline': 'black'}"/><!-- style -->
                         <parameter expr="self.inports['button_ui']"/><!-- inport for response -->
@@ -330,7 +346,7 @@
                     <raise port="ui" event="create_text">
                         <parameter expr="self.canvas_id" />
                         <parameter expr="CANVAS_DIMS[0] - 70"/>
-                        <parameter expr="45 + (30 * (FLOORS - self.number)) "/>
+                        <parameter expr="45 + (30 * (FLOORS - 1 - self.number)) "/>
                         <parameter expr="str(self.number)"/>
                         <parameter expr="self.inports['button_ui']"/><!-- inport for response -->
                     </raise>
@@ -342,10 +358,10 @@
                         self.button_id = circle_id
                     </script>
                     <raise port="ui" event="bind_canvas_event">
-                        <parameter expr="canvas_id"/>
+                        <parameter expr="self.canvas_id"/>
                         <parameter expr="circle_id"/><!-- widget_id -->
                         <parameter expr="ui.EVENTS.MOUSE_PRESS"/><!-- tk_event -->
-                        <parameter expr="'button_click'"/><!-- sccd_event_name -->
+                        <parameter expr="'clicked'"/><!-- sccd_event_name -->
                         <parameter expr="self.inports['button_ui']"/><!-- inport for response -->
                     </raise>
                     <raise port="ui" event="bind_canvas_event">
@@ -358,13 +374,10 @@
                 </transition>
             </state>
             <state id="running">
-                <transition port='button_ui' event="button_click" target='.' cond="button == ui.MOUSE_BUTTONS.LEFT">
+                <transition port='button_ui' event="clicked" target='.' cond="button == ui.MOUSE_BUTTONS.LEFT">
                     <parameter name="x" />
                     <parameter name="y" />
                     <parameter name="button" />
-                    <raise event="button_pressed" scope="narrow" target="'parent'">
-                        <parameter expr="self.number" />
-                    </raise>
                     <raise port="ui" event="set_element_color">
                         <parameter expr="self.canvas_id"/>
                         <parameter expr="self.button_id"/>
@@ -382,7 +395,7 @@
         <atrribute name="pos" />
         <inport name="elevator_ui"/>
         <relationships>
-            <association name="balls" class="Ball" />
+            <association name="floors" class="Floors" min="1" max="1" />
             <association name="parent" class="MainApp" min="1" max="1" />
         </relationships>
         <constructor>
@@ -436,13 +449,19 @@
                         </script>
                     </transition>
                 </state>
-                <state id="running" initial="waiting">
-                    <state id="waiting">
-                        <transition event="move_elevator" target="../move">
-                            <parameter name="position" type="int"/>
+                <state id="running" initial="idle">
+                    <state id="idle">
+                        <transition after="5" target="../move">
                         </transition>
                     </state>
                     <state id="move">
+                        <onentry>
+                            <raise scope="narrow" event="update_bounds" target="'parent'">
+                                <parameter expr="self.pos" />
+                                <parameter expr="self.dim" />
+                                <parameter expr="self.vel" />
+                            </raise>
+                        </onentry>
                         <transition after="0.02" target=".">
                             <raise port="ui" event="set_element_pos">
                                 <parameter expr="self.canvas_id"/>
@@ -454,7 +473,7 @@
                                 self.pos['y'] += self.vel
                             </script>
                         </transition>
-                        <transition target="../waiting" cond="(self.pos['y'] - (self.dim['y']/2)) &lt; 0">
+                        <transition target="../idle" cond="(self.pos['y'] - (self.dim['y']/2)) &lt; 0">
                         </transition>
                     </state>
                 </state>
@@ -478,7 +497,15 @@
             <body>
                 <![CDATA[
                 self.canvas_id = canvas_id;
+
+
                 self.floor_num = floor_num;
+
+                self.elevator_floor = 0;
+                self.elevator_open = True;
+                self.rect_pos = None;
+                self.rect_dim = None;
+
                 self.r = 5.0;
                 self.vel = {'x': random.uniform(-5.0, 5.0), 'y': random.uniform(-5.0, 5.0)};
                 self.pos = {'x': x, 'y': y};
@@ -501,7 +528,6 @@
                 <state id="creating_circle">
                     <onentry>
                         <raise port="ui" event="create_circle">
-                            canvas_id, x, y, r, style, res_port
                             <parameter expr="self.canvas_id"/><!-- canvas_id -->
                             <parameter expr="self.pos['x']"/><!-- x -->
                             <parameter expr="self.pos['y']"/><!-- y -->
@@ -516,27 +542,6 @@
                         <script>
                             self.circle_id = circle_id
                         </script>
-                        <raise port="ui" event="bind_canvas_event">
-                            <parameter expr="self.canvas_id"/>
-                            <parameter expr="circle_id"/>
-                            <parameter expr="ui.EVENTS.MOUSE_PRESS"/>
-                            <parameter expr="'mouse_press'"/>
-                            <parameter expr="self.inports['ball_ui']"/>
-                        </raise>
-                        <raise port="ui" event="bind_canvas_event">
-                            <parameter expr="self.canvas_id"/>
-                            <parameter expr="circle_id"/>
-                            <parameter expr="ui.EVENTS.MOUSE_MOVE"/>
-                            <parameter expr="'mouse_move'"/>
-                            <parameter expr="self.inports['ball_ui']"/>
-                        </raise>
-                        <raise port="ui" event="bind_canvas_event">
-                            <parameter expr="self.canvas_id"/>
-                            <parameter expr="circle_id"/>
-                            <parameter expr="ui.EVENTS.MOUSE_RELEASE"/>
-                            <parameter expr="'mouse_release'"/>
-                            <parameter expr="self.inports['ball_ui']"/>
-                        </raise>
                     </transition>
                 </state>
                 <state id="bouncing">
@@ -545,34 +550,40 @@
                             <![CDATA[
                             if self.floor_num == -1:
                                 if self.pos['x'] - self.r < self.rect_pos['x'] - (self.rect_dim['x'] / 2):
-                                    self.pos['x'] = self.rect_pos['x'] - (self.rect_dim['x'] / 2) + self.r  # Correct position
-                                    self.vel['x'] = -self.vel['x'] + self.rect_vel['x']
+                                    if self.elevator_open:
+                                        self.floor_num = self.elevator_floor
+                                    else:
+                                        self.pos['x'] = self.rect_pos['x'] - (self.rect_dim['x'] / 2) + self.r
+                                        self.vel['x'] = -self.vel['x']
                                 elif self.pos['x'] + self.r > self.rect_pos['x'] + (self.rect_dim['x'] / 2):
-                                    self.pos['x'] = self.rect_pos['x'] + (self.rect_dim['x'] / 2) - self.r  # Correct position
-                                    self.vel['x'] = -self.vel['x'] + self.rect_vel['x']
+                                    self.pos['x'] = self.rect_pos['x'] + (self.rect_dim['x'] / 2) - self.r
+                                    self.vel['x'] = -self.vel['x']
 
                                 # Check collision with the top and bottom borders
                                 if self.pos['y'] - self.r < self.rect_pos['y'] - (self.rect_dim['y'] / 2):
-                                    self.pos['y'] = self.rect_pos['y'] - (self.rect_dim['y'] / 2) + self.r  # Correct position
-                                    self.vel['y'] = -self.vel['y'] + self.rect_vel['y']
+                                    self.pos['y'] = self.rect_pos['y'] - (self.rect_dim['y'] / 2) + self.r
+                                    self.vel['y'] = -self.vel['y'] + self.rect_vel
                                 elif self.pos['y'] + self.r > self.rect_pos['y'] + (self.rect_dim['y'] / 2):
-                                    self.pos['y'] = self.rect_pos['y'] + (self.rect_dim['y'] / 2) - self.r  # Correct position
-                                    self.vel['y'] = -self.vel['y'] + self.rect_vel['y']
+                                    self.pos['y'] = self.rect_pos['y'] + (self.rect_dim['y'] / 2) - self.r
+                                    self.vel['y'] = -self.vel['y'] + self.rect_vel
                             else:
                                 floor_height = (CANVAS_DIMS[1] - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
                                 floor_dim = {'x': FLOOR_LENGTH, 'y': floor_height};
-                                floor_pos = {'x': FLOOR_LENGTH / 2, 'y': (floor_height /2) + (self.floor_num * (floor_height + FLOOR_SPACE))};
+                                floor_pos = {'x': FLOOR_LENGTH / 2, 'y': CANVAS_DIMS[1] - (floor_height /2) - ( self.floor_num * (floor_height + FLOOR_SPACE)  )};
 
                                 if self.pos['x'] - self.r < floor_pos['x'] - (floor_dim['x'] / 2):
-                                    self.pos['x'] = floor_pos['x'] - (floor_dim['x'] / 2) + self.r  # Correct position
+                                    self.pos['x'] = floor_pos['x'] - (floor_dim['x'] / 2) + self.r
                                     self.vel['x'] = -self.vel['x']
                                 elif self.pos['x'] + self.r > floor_pos['x'] + (floor_dim['x'] / 2):
-                                    self.pos['x'] = floor_pos['x'] + (floor_dim['x'] / 2) - self.r  # Correct position
-                                    self.vel['x'] = -self.vel['x']
+                                    if self.elevator_open and (self.elevator_floor == self.floor_num):
+                                        self.floor_num = -1
+                                    else:
+                                        self.pos['x'] = floor_pos['x'] + (floor_dim['x'] / 2) - self.r
+                                        self.vel['x'] = -self.vel['x']
 
                                 # Check collision with the top and bottom borders
                                 if self.pos['y'] - self.r < floor_pos['y'] - (floor_dim['y'] / 2):
-                                    self.pos['y'] = floor_pos['y'] - (floor_dim['y'] / 2) + self.r  # Correct position
+                                    self.pos['y'] = floor_pos['y'] - (floor_dim['y'] / 2) + self.r
                                     self.vel['y'] = -self.vel['y']
                                 elif self.pos['y'] + self.r > floor_pos['y'] + (floor_dim['y'] / 2):
                                     self.pos['y'] = floor_pos['y'] + (floor_dim['y'] / 2) - self.r  # Correct position
@@ -605,11 +616,12 @@
                     <transition event="update_bounds" target=".">
                         <parameter name="pos" type="dict" />
                         <parameter name="dim" type="dict" />
-                        <parameter name="vel" type="dict" />
+                        <parameter name="vel" type="int" />
                         <script>
                             self.rect_pos = pos
                             self.rect_dim = dim
                             self.rect_vel = vel
+                            self.elevator_open = False
                         </script>
                     </transition>
                 </state>
@@ -659,14 +671,14 @@
                         <parameter name="button" />
                         <script>
                             <![CDATA[
-                            self.mouse_pos = {'x':x, 'y':y};
+                            self.mouse_pos = {'x': x, 'y': y};
                             ]]>
                         </script>
                     </transition>
                 </state>
                 <state id="ball_delete">
                     <transition event="delete_self" target='../../deleted'>                    
-                        <raise event="delete_ball" scope="narrow" target="'parent'">
+                        <raise event="delete_ball" scope="narrow" target="'floor'">
                             <parameter expr='self.association_name' />
                         </raise>
                         <raise port="ui" event="destroy_element">
@@ -679,5 +691,4 @@
             <state id='deleted' />
         </scxml>
     </class>
-
 </diagram>

+ 1 - 1
sccd/runtime/DEVS_loop.py

@@ -8,7 +8,7 @@ def get_port(text):
 		result = match.group(1)
 		return result
 	else:
-		return None
+		return text
 
 
 class DEVSSimulator(Simulator):

+ 0 - 12
tests/BrokenTest/runner.py

@@ -1,12 +0,0 @@
-import target as target
-import threading
-from sccd.runtime.statecharts_core import Event
-
-controller = target.Controller(False)
-def raw_inputter():
-    while 1:
-        controller.addInput(Event(raw_input(), "input", []))
-thread = threading.Thread(target=raw_inputter)
-thread.daemon = True
-thread.start()
-controller.start()

+ 0 - 65
tests/BrokenTest/sccd.xml

@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<diagram author="Yentl Van Tendeloo+Simon Van Mierlo" name="broken">
-    <description>
-        Broken!
-        Sam: The file was called external input
-    </description>
-    
-    <inport name="input" />
-
-    <class name="A" default="true">
-        <relationships>
-            <association name="child" class="B" min="0" max="1"/>
-        </relationships>
-
-        <scxml initial="x">
-            <state id="x">
-                <onentry>
-                    <raise scope="cd" event="create_instance">
-                        <parameter expr="'child'"/>
-                        <parameter expr="'B'"/>
-                    </raise>
-                </onentry>
-
-                <transition event="instance_created" target="../ready">
-                    <parameter name="instancename"/>
-                    <script>
-                        self.instancename = instancename
-                    </script>
-                    <raise scope="cd" event="start_instance">
-                        <parameter expr="self.instancename"/>
-                    </raise>
-                </transition>
-            </state>
-            <state id="ready">
-                <transition after="0.001" target=".">
-                    <script>
-                        for _ in range(100000):
-                            pass
-                    </script>
-                </transition>
-                <transition event="close" target="../done">
-                    <raise scope="cd" event="delete_instance">
-                        <parameter expr="self.instancename"/>
-                    </raise>
-                </transition>
-            </state>
-            <state id="done"/>
-        </scxml>
-    </class>
-
-    <class name="B">
-        <relationships>
-            <association name="parent" class="A" min="1" max="1"/>
-        </relationships>
-
-        <scxml initial="z">
-            <state id="z">
-                <transition event="stop" port="input" target=".">
-                    <raise event="close" target="'parent[0]'" />
-                </transition>
-            </state>
-        </scxml>
-    </class>
-
-</diagram>

+ 1 - 1
tests/Test1/PyDEVS/target.py

@@ -4,7 +4,7 @@ Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van M
 Model author: Sam Pieters
 Model name:   EndingTest
 Model description:
-Test 1: Check if the program ends on time.
+Test 1: Check if the model ends on time.
 """
 
 from sccd.runtime.DEVS_statecharts_core import *

+ 12 - 5
tests/Test1/Python/runner.py

@@ -1,9 +1,16 @@
-import tests.Test1.Python.target as target
+import target as target
+from sccd.runtime.statecharts_core import Event
+import threading
+
+class OutputListener:
+	def add(self, event):
+		if event.port == "ui":
+			print(event.name, ", received on:", event.parameters[0], "seconds, parameters:", event.parameters[1:])
+				
 
 if __name__ == '__main__':
 	controller = target.Controller()
 	controller.keep_running = False
-	controller.setVerbose(None)
-	controller.start()
-
-	
+	controller.addMyOwnOutputListener(OutputListener())
+	controller.setVerbose("check.txt")
+	controller.start()

+ 1 - 1
tests/Test1/Python/target.py

@@ -4,7 +4,7 @@ Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van M
 Model author: Sam Pieters
 Model name:   EndingTest
 Model description:
-Test 1: Check if the program ends on time.
+Test 1: Check if the model ends on time.
 """
 
 from sccd.runtime.statecharts_core import *

+ 2 - 2
tests/Test3/PyDEVS/target.py

@@ -2,14 +2,14 @@
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration) and Sam Pieters (DEVS)
 
 Model author: Sam Pieters
-Model name:   Output Test
+Model name:   Multiple Output Test
 Model description:
 Test 3: Check if the model outputs multiple events with an interval on the right time.
 """
 
 from sccd.runtime.DEVS_statecharts_core import *
 
-# package "Output Test"
+# package "Multiple Output Test"
 
 class MainAppInstance(RuntimeClassBase):
     def __init__(self, atomdevs):

+ 2 - 2
tests/Test3/Python/target.py

@@ -2,14 +2,14 @@
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 
 Model author: Sam Pieters
-Model name:   Output Test
+Model name:   Multiple Output Test
 Model description:
 Test 3: Check if the model outputs multiple events with an interval on the right time.
 """
 
 from sccd.runtime.statecharts_core import *
 
-# package "Output Test"
+# package "Multiple Output Test"
 
 class MainApp(RuntimeClassBase):
     def __init__(self, controller):

+ 10 - 7
tests/Test4/sccd.xml

@@ -1,22 +1,25 @@
 <?xml version="1.1" ?>
-<diagram author="Sam Pieters" name="Input Test">
+<diagram author="Sam Pieters" name="Global Input Test">
     <description>
-        Test 4: Check if the model receives input on the right rime and sends and output event after 0.5 seconds.
+        Test 4: Check if the model receives input on the right time.
     </description>
     <inport name="ui"/>
     <outport name="ui"/>
     <class name="MainApp" default="true">
         <scxml initial="state1">
             <state id="state1">
-                <transition event="input_test_event" target="../state2" />
-            </state>
-            <state id="state2">
                 <onentry>
-                    <raise port="ui" event="test_event">
-                        <parameter expr="str(self.amount)" />
+                    <raise port="ui" event="output_event">
                         <parameter expr="str('%.2f' % (self.getSimulatedTime() / 1000.0))" />
                     </raise>
                 </onentry>
+                <transition event="input_event" target="../state2">
+                    <raise port="ui" event="received">
+                        <parameter expr="str('%.2f' % (self.getSimulatedTime() / 1000.0))" />
+                    </raise>
+                </transition>
+            </state>
+            <state id="state2">
             </state>
         </scxml>
     </class>