Selaa lähdekoodia

halfly solved deletion

sampieters 1 vuosi sitten
vanhempi
commit
fd42fc367f

+ 0 - 11
examples/BouncingBalls/PyDEVS/output.txt

@@ -1,11 +0,0 @@
-0.242 (event name: create_window; port: ui; parameters: [800, 600, 'BouncingBalls', 'private_2_field_ui'])
-0.292 (event name: bind_event; port: ui; parameters: [0, 'WM_DELETE_WINDOW', 'window_close', 'private_2_field_ui'])
-0.292 (event name: bind_event; port: ui; parameters: [0, '<Key>', 'key_press', 'private_2_field_ui'])
-0.292 (event name: create_canvas; port: ui; parameters: [0, 800, 550, {'background': '#eee'}, 'private_2_field_ui'])
-0.306 (event name: bind_event; port: ui; parameters: [1, '<Button-2>', 'right_click', 'private_2_field_ui'])
-0.306 (event name: bind_event; port: ui; parameters: [1, '<Motion>', 'mouse_move', 'private_2_field_ui'])
-0.306 (event name: bind_event; port: ui; parameters: [1, '<ButtonRelease>', 'mouse_release', 'private_2_field_ui'])
-0.307 (event name: create_button; port: ui; parameters: [0, 'create_new_field', 'private_4_button_ui'])
-0.318 (event name: bind_event; port: ui; parameters: [2, '<Button>', 'mouse_click', 'private_4_button_ui'])
-2.452 (event name: destroy_window; port: ui; parameters: [0])
-2.505 (event name: destroy_all; port: ui)

+ 2 - 2
examples/BouncingBalls/PyDEVS/runner.py

@@ -1,5 +1,5 @@
 import tkinter as tk
-import examples.BouncingBalls.PyDEVS.target as target
+import target as target
 from sccd.runtime.libs.ui_v2 import UI
 from sccd.runtime.DEVS_loop import DEVSSimulator
 
@@ -21,7 +21,7 @@ if __name__ == '__main__':
 	tkroot.withdraw()
 	sim = DEVSSimulator(model, refs)
 
-	sim.setVerbose()
+	#sim.setVerbose()
 	sim.setRealTimePlatformTk(tkroot)
 
 	ui = UI(tkroot, sim)

+ 0 - 43
examples/BouncingBalls/PyDEVS/test_runner.py

@@ -1,43 +0,0 @@
-import tkinter as tk
-import examples.BouncingBalls.PyDEVS.target as target
-from sccd.runtime.libs.ui_v2 import UI
-from sccd.runtime.DEVS_loop import DEVSSimulator
-import time
-
-begin_time = time.time()
-
-class OutputListener:
-	def __init__(self, model, log_file):
-		self.model = model
-		self.log_file = log_file
-
-		# Clear the log file when the listener is initialized
-		with open(self.log_file, 'w') as file:
-			file.write('')  # This will create a new empty file or clear the existing file
-		
-	def add(self, events):
-		with open(self.log_file, 'a') as file:
-			for event in events:
-				elapsed_time = time.time() - begin_time
-				file.write(f'{elapsed_time:.3f} {event}\n')
-
-				# IMPORTANT: This is here because we add our own inputs but tkinter will not close properly because of this
-				#if event.name == "destroy_all":
-					#self.tk.destroy()
-
-if __name__ == '__main__':
-	model = target.Controller(name="controller")
-	refs = {"ui": model.in_ui, "field_ui": model.atomic1.field_ui, "button_ui": model.atomic2.button_ui, "ball_ui": model.atomic3.ball_ui}
-
-	tkroot = tk.Tk()
-	tkroot.withdraw()
-	sim = DEVSSimulator(model, refs)
-	sim.setRealTimeInputFile("./examples/BouncingBalls/input_trace.txt")
-	
-	sim.setRealTimePlatformTk(tkroot)
-
-	listener = OutputListener(model, "./examples/BouncingBalls/PyDEVS/output.txt")
-	sim.setListenPorts(model.out_ui, listener.add)
-
-	sim.simulate()
-	tkroot.mainloop()

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 2571
examples/BouncingBalls/PyDEVS/trace.txt


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 9847
examples/BouncingBalls/Python/trace.txt


+ 230 - 353
examples/ElevatorBalls/PyDEVS/target.py

@@ -23,8 +23,9 @@ 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["button"] = Association("ElevatorButton", 0, -1)
         self.associations["elevator"] = Association("Elevator", 1, 1)
+        self.associations["ball"] = Association("Ball", 0, -1)
         
         self.semantics.big_step_maximality = StatechartSemantics.TakeMany
         self.semantics.internal_event_lifeline = StatechartSemantics.Queue
@@ -52,6 +53,9 @@ class MainAppInstance(RuntimeClassBase):
     
     def user_defined_constructor(self):
         self.num_floors = 0
+        self.button_num = FLOORS
+        
+        self.next_elevator_pos = None
     
     def user_defined_destructor(self):
         pass
@@ -80,17 +84,27 @@ class MainAppInstance(RuntimeClassBase):
         # 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_controls/create_buttons
+        self.states["/create_controls/create_buttons"] = State(6, "/create_controls/create_buttons", self)
+        
+        # state /create_controls/create_buttons/create_a_button
+        self.states["/create_controls/create_buttons/create_a_button"] = State(7, "/create_controls/create_buttons/create_a_button", self)
+        self.states["/create_controls/create_buttons/create_a_button"].setEnter(self._create_controls_create_buttons_create_a_button_enter)
+        
+        # state /create_controls/create_buttons/start_a_button
+        self.states["/create_controls/create_buttons/start_a_button"] = State(8, "/create_controls/create_buttons/start_a_button", self)
+        
+        # state /create_controls/create_buttons/check_next
+        self.states["/create_controls/create_buttons/check_next"] = State(9, "/create_controls/create_buttons/check_next", self)
         
         # state /create_elevator
-        self.states["/create_elevator"] = State(7, "/create_elevator", self)
+        self.states["/create_elevator"] = State(10, "/create_elevator", self)
         
         # state /creating
-        self.states["/creating"] = State(8, "/creating", self)
+        self.states["/creating"] = State(11, "/creating", self)
         
-        # state /waiting
-        self.states["/waiting"] = State(9, "/waiting", self)
+        # state /running
+        self.states["/running"] = State(12, "/running", self)
         
         # add children
         self.states[""].addChild(self.states["/creating_window"])
@@ -98,12 +112,17 @@ class MainAppInstance(RuntimeClassBase):
         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"])
+        self.states[""].addChild(self.states["/running"])
+        self.states["/create_controls"].addChild(self.states["/create_controls/create_buttons"])
+        self.states["/create_controls/create_buttons"].addChild(self.states["/create_controls/create_buttons/create_a_button"])
+        self.states["/create_controls/create_buttons"].addChild(self.states["/create_controls/create_buttons/start_a_button"])
+        self.states["/create_controls/create_buttons"].addChild(self.states["/create_controls/create_buttons/check_next"])
         self.states[""].fixTree()
         self.states[""].default_state = self.states["/creating_window"]
+        self.states["/create_controls"].default_state = self.states["/create_controls/create_buttons"]
+        self.states["/create_controls/create_buttons"].default_state = self.states["/create_controls/create_buttons/create_a_button"]
         
         # transition /creating_window
         _creating_window_0 = Transition(self, self.states["/creating_window"], [self.states["/creating_canvas"]])
@@ -137,17 +156,27 @@ 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_controls/create_buttons/create_a_button
+        _create_controls_create_buttons_create_a_button_0 = Transition(self, self.states["/create_controls/create_buttons/create_a_button"], [self.states["/create_controls/create_buttons/start_a_button"]])
+        _create_controls_create_buttons_create_a_button_0.setAction(self._create_controls_create_buttons_create_a_button_0_exec)
+        _create_controls_create_buttons_create_a_button_0.setTrigger(Event("instance_created", None))
+        self.states["/create_controls/create_buttons/create_a_button"].addTransition(_create_controls_create_buttons_create_a_button_0)
+        
+        # transition /create_controls/create_buttons/start_a_button
+        _create_controls_create_buttons_start_a_button_0 = Transition(self, self.states["/create_controls/create_buttons/start_a_button"], [self.states["/create_controls/create_buttons/check_next"]])
+        _create_controls_create_buttons_start_a_button_0.setTrigger(Event("instance_started", None))
+        self.states["/create_controls/create_buttons/start_a_button"].addTransition(_create_controls_create_buttons_start_a_button_0)
+        
+        # transition /create_controls/create_buttons/check_next
+        _create_controls_create_buttons_check_next_0 = Transition(self, self.states["/create_controls/create_buttons/check_next"], [self.states["/create_controls/create_buttons/create_a_button"]])
+        _create_controls_create_buttons_check_next_0.setAction(self._create_controls_create_buttons_check_next_0_exec)
+        _create_controls_create_buttons_check_next_0.setTrigger(None)
+        _create_controls_create_buttons_check_next_0.setGuard(self._create_controls_create_buttons_check_next_0_guard)
+        self.states["/create_controls/create_buttons/check_next"].addTransition(_create_controls_create_buttons_check_next_0)
+        _create_controls_create_buttons_check_next_1 = Transition(self, self.states["/create_controls/create_buttons/check_next"], [self.states["/create_elevator"]])
+        _create_controls_create_buttons_check_next_1.setTrigger(None)
+        _create_controls_create_buttons_check_next_1.setGuard(self._create_controls_create_buttons_check_next_1_guard)
+        self.states["/create_controls/create_buttons/check_next"].addTransition(_create_controls_create_buttons_check_next_1)
         
         # transition /create_elevator
         _create_elevator_0 = Transition(self, self.states["/create_elevator"], [self.states["/creating"]])
@@ -156,16 +185,41 @@ class MainAppInstance(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)
+        _running_3 = Transition(self, self.states["/running"], [self.states["/running"]])
+        _running_3.setAction(self._running_3_exec)
+        _running_3.setTrigger(Event("button_pressed", None))
+        self.states["/running"].addTransition(_running_3)
+        _running_4 = Transition(self, self.states["/running"], [self.states["/running"]])
+        _running_4.setAction(self._running_4_exec)
+        _running_4.setTrigger(Event("open_elevator", None))
+        self.states["/running"].addTransition(_running_4)
     
     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']]))
     
     def _creating_canvas_enter(self):
-        self.big_step.outputEvent(Event("create_canvas", self.getOutPortName("ui"), [self.window_id, CANVAS_DIMS[0], CANVAS_DIMS[1] - 200, {'background':'#fff'}, self.inports['field_ui']]))
+        self.big_step.outputEvent(Event("create_canvas", self.getOutPortName("ui"), [self.window_id, CANVAS_DIMS[0], CANVAS_DIMS[1] - 150, {'background':'#fff'}, self.inports['field_ui']]))
+    
+    def _create_controls_create_buttons_create_a_button_enter(self):
+        self.big_step.outputEventOM(Event("create_instance", None, [self, "button", "ElevatorButton", self.window_id, self.canvas_id, self.button_num - 1]))
     
     def _creating_window_0_exec(self, parameters):
         window_id = parameters[0]
@@ -191,13 +245,19 @@ 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):
+    def _create_controls_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 _create_controls_create_buttons_check_next_0_exec(self, parameters):
+        self.button_num -= 1
+    
+    def _create_controls_create_buttons_check_next_0_guard(self, parameters):
+        return self.button_num != 1
+    
+    def _create_controls_create_buttons_check_next_1_guard(self, parameters):
+        return self.button_num == 1
+    
     def _create_elevator_0_exec(self, parameters):
         self.big_step.outputEventOM(Event("create_instance", None, [self, "elevator", "Elevator", self.canvas_id]))
     
@@ -206,6 +266,30 @@ class MainAppInstance(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 _running_3_exec(self, parameters):
+        floor_number = parameters[0]
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'elevator', Event("move_elevator", None, [floor_number])]))
+    
+    def _running_4_exec(self, parameters):
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'ball', Event("open_elevator", None, [])]))
+    
     def initializeStatechart(self):
         # enter default state
         self.default_targets = self.states["/creating_window"].getEffectiveTargetStates()
@@ -217,8 +301,9 @@ 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["button"] = self.addOutPort("button")
         self.outputs["elevator"] = self.addOutPort("elevator")
+        self.outputs["ball"] = self.addOutPort("ball")
         self.field_ui = self.addInPort("field_ui")
         self.instances[self.next_instance] = MainAppInstance(self)
         self.next_instance = self.next_instance + 1
@@ -231,7 +316,6 @@ class FloorInstance(RuntimeClassBase):
     def __init__(self, atomdevs, canvas_id, floor_num):
         RuntimeClassBase.__init__(self, atomdevs)
         self.associations = {}
-        self.associations["balls"] = Association("Ball", 0, -1)
         self.associations["parent"] = Association("MainApp", 1, 1)
         
         self.semantics.big_step_maximality = StatechartSemantics.TakeMany
@@ -261,10 +345,17 @@ class FloorInstance(RuntimeClassBase):
         self.canvas_id = canvas_id;
         self.floor_num = floor_num;
         
-        y_dim = (CANVAS_DIMS[1] - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
+        height = CANVAS_DIMS[1] - 150
+        
+        y_dim = (height - ((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': height - (y_dim /2) - ( self.floor_num * (y_dim + FLOOR_SPACE)  )};
     
     def user_defined_destructor(self):
         pass
@@ -288,14 +379,10 @@ class FloorInstance(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"]
@@ -306,16 +393,10 @@ class FloorInstance(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']]))
@@ -327,12 +408,7 @@ class FloorInstance(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
@@ -344,7 +420,6 @@ class Floor(ObjectManagerBase):
         ObjectManagerBase.__init__(self, name)
         self.input = self.addInPort("input")
         self.output = self.addOutPort("ui")
-        self.outputs["balls"] = self.addOutPort("balls")
         self.outputs["parent"] = self.addOutPort("parent")
         self.floor_ui = self.addInPort("floor_ui")
     
@@ -352,166 +427,11 @@ 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):
+    def __init__(self, atomdevs, window_id, canvas_id, number):
         RuntimeClassBase.__init__(self, atomdevs)
         self.associations = {}
-        self.associations["parent"] = Association("ElevatorControls", 1, 1)
+        self.associations["parent"] = Association("MainApp", 1, 1)
         
         self.semantics.big_step_maximality = StatechartSemantics.TakeMany
         self.semantics.internal_event_lifeline = StatechartSemantics.Queue
@@ -523,7 +443,7 @@ class ElevatorButtonInstance(RuntimeClassBase):
         self.build_statechart_structure()
         
         # call user defined constructor
-        ElevatorButtonInstance.user_defined_constructor(self, canvas_id, number)
+        ElevatorButtonInstance.user_defined_constructor(self, window_id, canvas_id, number)
         port_name = Ports.addInputPort("<narrow_cast>", self)
         atomdevs.addInPort(port_name)
         port_name = Ports.addInputPort("button_ui", self)
@@ -531,7 +451,8 @@ class ElevatorButtonInstance(RuntimeClassBase):
         atomdevs.port_mappings[port_name] = atomdevs.next_instance
         self.inports["button_ui"] = port_name
     
-    def user_defined_constructor(self, canvas_id, number):
+    def user_defined_constructor(self, window_id, canvas_id, number):
+        self.window_id = window_id;
         self.canvas_id = canvas_id;
         self.button_id = None;
         
@@ -566,33 +487,29 @@ class ElevatorButtonInstance(RuntimeClassBase):
         # 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))
+        _creating_0.setTrigger(Event("button_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.setTrigger(Event("mouse_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']]))
+        self.big_step.outputEvent(Event("create_button", self.getOutPortName("ui"), [self.window_id, 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']]))
+        button_id = parameters[0]
+        self.button_id = button_id
+        self.big_step.outputEvent(Event("bind_event", self.getOutPortName("ui"), [button_id, ui.EVENTS.MOUSE_CLICK, "mouse_click", 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]
@@ -614,14 +531,14 @@ class ElevatorButton(ObjectManagerBase):
         self.button_ui = self.addInPort("button_ui")
     
     def constructObject(self, parameters):
-        new_instance = ElevatorButtonInstance(self, parameters[2], parameters[3])
+        new_instance = ElevatorButtonInstance(self, parameters[2], parameters[3], parameters[4])
         return new_instance
 
 class ElevatorInstance(RuntimeClassBase):
     def __init__(self, atomdevs, canvas_id):
         RuntimeClassBase.__init__(self, atomdevs)
         self.associations = {}
-        self.associations["balls"] = Association("Ball", 0, -1)
+        self.associations["floors"] = Association("Floor", 1, 1)
         self.associations["parent"] = Association("MainApp", 1, 1)
         
         self.semantics.big_step_maximality = StatechartSemantics.TakeMany
@@ -650,13 +567,19 @@ class ElevatorInstance(RuntimeClassBase):
     def user_defined_constructor(self, canvas_id):
         self.canvas_id = canvas_id;
         
-        self.is_open = False;
+        height = CANVAS_DIMS[1] - 150
         
-        elevator_height = (CANVAS_DIMS[1] - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
+        elevator_height = (height - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
         
         self.dim = {'x': elevator_height, 'y': elevator_height};
         self.vel = -2;
-        self.pos = {'x': FLOOR_LENGTH + (elevator_height / 2), 'y': (CANVAS_DIMS[1] - (elevator_height / 2))};
+        
+        self.current_floor = 0;
+        
+        self.pos = {'x': FLOOR_LENGTH + (elevator_height / 2), 'y': (height - (elevator_height / 2))};
+        self.next_pos = {'x': FLOOR_LENGTH / 2, 'y': None};
+        
+        
         self.smooth = 0.6; # value between 0 and 1
     
     def user_defined_destructor(self):
@@ -682,8 +605,9 @@ class ElevatorInstance(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)
         
         # state /root/running/move
         self.states["/root/running/move"] = State(6, "/root/running/move", self)
@@ -695,12 +619,12 @@ class ElevatorInstance(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"]])
@@ -714,17 +638,19 @@ 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/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.setAction(self._root_running_idle_0_exec)
+        _root_running_idle_0.setTrigger(Event("move_elevator", None))
+        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"))
         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.setAction(self._root_running_move_1_exec)
         _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)
@@ -732,7 +658,11 @@ class ElevatorInstance(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.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("update_bounds", None, [self.pos, self.dim, self.vel])]))
+    
     def _root_running_move_enter(self):
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("update_bounds", None, [self.pos, self.dim, self.vel])]))
         self.addTimer(0, 0.02)
     
     def _root_running_move_exit(self):
@@ -751,12 +681,26 @@ class ElevatorInstance(RuntimeClassBase):
         rect_id = parameters[1]
         self.elevator_id = rect_id
     
+    def _root_running_idle_0_exec(self, parameters):
+        floor_number = parameters[0]
+        if self.current_floor < floor_number:
+            self.vel = -2
+        else:
+            self.vel = 2
+        
+        height = (CANVAS_DIMS[1] - 150)
+        y_dim = (height - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
+        self.next_pos['y'] = height - (y_dim /2) - (floor_number * (y_dim + FLOOR_SPACE));
+    
     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_move_1_exec(self, parameters):
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("open_elevator", None, [])]))
+    
     def _root_running_move_1_guard(self, parameters):
-        return (self.pos['y'] - (self.dim['y']/2)) < 0
+        return (self.pos['y']) < self.next_pos['y']
     
     def initializeStatechart(self):
         # enter default state
@@ -768,7 +712,7 @@ class Elevator(ObjectManagerBase):
         ObjectManagerBase.__init__(self, name)
         self.input = self.addInPort("input")
         self.output = self.addOutPort("ui")
-        self.outputs["balls"] = self.addOutPort("balls")
+        self.outputs["floors"] = self.addOutPort("floors")
         self.outputs["parent"] = self.addOutPort("parent")
         self.elevator_ui = self.addInPort("elevator_ui")
     
@@ -806,7 +750,15 @@ class BallInstance(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};
@@ -837,17 +789,11 @@ class BallInstance(RuntimeClassBase):
         self.states["/main_behaviour/bouncing"].setEnter(self._main_behaviour_bouncing_enter)
         self.states["/main_behaviour/bouncing"].setExit(self._main_behaviour_bouncing_exit)
         
-        # state /main_behaviour/dragging
-        self.states["/main_behaviour/dragging"] = State(5, "/main_behaviour/dragging", self)
-        
-        # 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)
+        self.states["/main_behaviour/ball_delete"] = State(5, "/main_behaviour/ball_delete", self)
         
         # state /deleted
-        self.states["/deleted"] = State(8, "/deleted", self)
+        self.states["/deleted"] = State(6, "/deleted", self)
         
         # add children
         self.states[""].addChild(self.states["/main_behaviour"])
@@ -855,8 +801,6 @@ class BallInstance(RuntimeClassBase):
         self.states["/main_behaviour"].addChild(self.states["/main_behaviour/initializing"])
         self.states["/main_behaviour"].addChild(self.states["/main_behaviour/creating_circle"])
         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"]
@@ -879,13 +823,12 @@ 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/ball_delete"]])
-        _main_behaviour_bouncing_1.setTrigger(None)
-        _main_behaviour_bouncing_1.setGuard(self._main_behaviour_bouncing_1_guard)
+        _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.setTrigger(Event("open_elevator", None))
         self.states["/main_behaviour/bouncing"].addTransition(_main_behaviour_bouncing_1)
-        _main_behaviour_bouncing_2 = Transition(self, self.states["/main_behaviour/bouncing"], [self.states["/main_behaviour/selected"]])
-        _main_behaviour_bouncing_2.setAction(self._main_behaviour_bouncing_2_exec)
-        _main_behaviour_bouncing_2.setTrigger(Event("mouse_press", self.getInPortName("ball_ui")))
+        _main_behaviour_bouncing_2 = Transition(self, self.states["/main_behaviour/bouncing"], [self.states["/main_behaviour/ball_delete"]])
+        _main_behaviour_bouncing_2.setTrigger(None)
         _main_behaviour_bouncing_2.setGuard(self._main_behaviour_bouncing_2_guard)
         self.states["/main_behaviour/bouncing"].addTransition(_main_behaviour_bouncing_2)
         _main_behaviour_bouncing_3 = Transition(self, self.states["/main_behaviour/bouncing"], [self.states["/main_behaviour/bouncing"]])
@@ -893,23 +836,6 @@ class BallInstance(RuntimeClassBase):
         _main_behaviour_bouncing_3.setTrigger(Event("update_bounds", None))
         self.states["/main_behaviour/bouncing"].addTransition(_main_behaviour_bouncing_3)
         
-        # transition /main_behaviour/dragging
-        _main_behaviour_dragging_0 = Transition(self, self.states["/main_behaviour/dragging"], [self.states["/main_behaviour/dragging"]])
-        _main_behaviour_dragging_0.setAction(self._main_behaviour_dragging_0_exec)
-        _main_behaviour_dragging_0.setTrigger(Event("mouse_move", self.getInPortName("ball_ui")))
-        self.states["/main_behaviour/dragging"].addTransition(_main_behaviour_dragging_0)
-        _main_behaviour_dragging_1 = Transition(self, self.states["/main_behaviour/dragging"], [self.states["/main_behaviour/bouncing"]])
-        _main_behaviour_dragging_1.setAction(self._main_behaviour_dragging_1_exec)
-        _main_behaviour_dragging_1.setTrigger(Event("mouse_release", self.getInPortName("ball_ui")))
-        self.states["/main_behaviour/dragging"].addTransition(_main_behaviour_dragging_1)
-        
-        # transition /main_behaviour/selected
-        _main_behaviour_selected_0 = Transition(self, self.states["/main_behaviour/selected"], [self.states["/main_behaviour/dragging"]])
-        _main_behaviour_selected_0.setAction(self._main_behaviour_selected_0_exec)
-        _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)
-        
         # 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)
@@ -933,41 +859,44 @@ class BallInstance(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_height = ((CANVAS_DIMS[1] - 150) - ((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] - 150) - (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
@@ -976,20 +905,11 @@ class BallInstance(RuntimeClassBase):
         self.pos['x'] += self.vel['x']
         self.pos['y'] += self.vel['y']
     
-    def _main_behaviour_bouncing_1_guard(self, parameters):
-        return self.pos['x'] - self.r < 2
-    
-    def _main_behaviour_bouncing_2_exec(self, parameters):
-        x = parameters[0]
-        y = parameters[1]
-        button = parameters[2]
-        self.big_step.outputEvent(Event("set_element_color", self.getOutPortName("ui"), [self.canvas_id, self.circle_id, '#ff0']))
+    def _main_behaviour_bouncing_1_exec(self, parameters):
+        self.elevator_open = True
     
     def _main_behaviour_bouncing_2_guard(self, parameters):
-        x = parameters[0]
-        y = parameters[1]
-        button = parameters[2]
-        return button == ui.MOUSE_BUTTONS.LEFT
+        return self.pos['x'] - self.r < 2
     
     def _main_behaviour_bouncing_3_exec(self, parameters):
         pos = parameters[0]
@@ -998,45 +918,10 @@ class BallInstance(RuntimeClassBase):
         self.rect_pos = pos
         self.rect_dim = dim
         self.rect_vel = vel
-    
-    def _main_behaviour_dragging_0_exec(self, parameters):
-        x = parameters[0]
-        y = parameters[1]
-        button = parameters[2]
-        # Always keep ball within canvas:
-        x = min(max(0+self.r, x), CANVAS_DIMS[0]-self.r)
-        y = min(max(0+self.r, y), CANVAS_DIMS[1]-self.r)
-        
-        dx = x - self.pos['x']
-        dy = y - self.pos['y']
-        
-        self.vel = {
-            'x': (1-self.smooth)*dx + self.smooth*self.vel['x'],
-            'y': (1-self.smooth)*dy + self.smooth*self.vel['y']
-        }
-        
-        self.pos = {'x': x, 'y': y}
-        self.big_step.outputEvent(Event("set_element_pos", self.getOutPortName("ui"), [self.canvas_id, self.circle_id, x-self.r, y-self.r]))
-    
-    def _main_behaviour_dragging_1_exec(self, parameters):
-        x = parameters[0]
-        y = parameters[1]
-        self.big_step.outputEvent(Event("set_element_color", self.getOutPortName("ui"), [self.canvas_id, self.circle_id, '#f00']))
-    
-    def _main_behaviour_selected_0_exec(self, parameters):
-        x = parameters[0]
-        y = parameters[1]
-        button = parameters[2]
-        self.mouse_pos = {'x':x, 'y':y};
-    
-    def _main_behaviour_selected_0_guard(self, parameters):
-        x = parameters[0]
-        y = parameters[1]
-        button = parameters[2]
-        return button == ui.MOUSE_BUTTONS.LEFT
+        self.elevator_open = False
     
     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):
@@ -1067,7 +952,6 @@ 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()
@@ -1082,37 +966,30 @@ 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(ElevatorControls("ElevatorControls"))
-        self.atomic3 = self.addSubModel(ElevatorButton("ElevatorButton"))
-        self.atomic4 = self.addSubModel(Elevator("Elevator"))
-        self.atomic5 = self.addSubModel(Ball("Ball"))
+        self.atomic2 = self.addSubModel(ElevatorButton("ElevatorButton"))
+        self.atomic3 = self.addSubModel(Elevator("Elevator"))
+        self.atomic4 = 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["controls"], self.atomic2.input)
-        self.connectPorts(self.atomic0.outputs["elevator"], self.atomic4.input)
+        self.connectPorts(self.atomic0.outputs["button"], self.atomic2.input)
+        self.connectPorts(self.atomic0.outputs["elevator"], self.atomic3.input)
+        self.connectPorts(self.atomic0.outputs["ball"], 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.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["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.objectmanager.output["ElevatorButton"], self.atomic2.obj_manager_in)
+        self.connectPorts(self.atomic2.outputs["parent"], self.atomic0.input)
         self.connectPorts(self.atomic3.obj_manager_out, self.objectmanager.input)
-        self.connectPorts(self.objectmanager.output["ElevatorButton"], self.atomic3.obj_manager_in)
-        self.connectPorts(self.atomic3.outputs["parent"], self.atomic2.input)
+        self.connectPorts(self.objectmanager.output["Elevator"], self.atomic3.obj_manager_in)
+        self.connectPorts(self.atomic3.outputs["floors"], self.atomic1.input)
+        self.connectPorts(self.atomic3.outputs["parent"], self.atomic0.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.objectmanager.output["Ball"], self.atomic4.obj_manager_in)
         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.atomic4.output, self.out_ui)
-        self.connectPorts(self.atomic5.output, self.out_ui)
+        self.connectPorts(self.atomic4.output, self.out_ui)

+ 136 - 274
examples/ElevatorBalls/Python/target.py

@@ -44,6 +44,9 @@ class MainApp(RuntimeClassBase):
     
     def user_defined_constructor(self):
         self.num_floors = 0
+        self.button_num = FLOORS
+        
+        self.next_elevator_pos = None
     
     def user_defined_destructor(self):
         pass
@@ -72,17 +75,27 @@ class MainApp(RuntimeClassBase):
         # 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_controls/create_buttons
+        self.states["/create_controls/create_buttons"] = State(6, "/create_controls/create_buttons", self)
+        
+        # state /create_controls/create_buttons/create_a_button
+        self.states["/create_controls/create_buttons/create_a_button"] = State(7, "/create_controls/create_buttons/create_a_button", self)
+        self.states["/create_controls/create_buttons/create_a_button"].setEnter(self._create_controls_create_buttons_create_a_button_enter)
+        
+        # state /create_controls/create_buttons/start_a_button
+        self.states["/create_controls/create_buttons/start_a_button"] = State(8, "/create_controls/create_buttons/start_a_button", self)
+        
+        # state /create_controls/create_buttons/check_next
+        self.states["/create_controls/create_buttons/check_next"] = State(9, "/create_controls/create_buttons/check_next", self)
         
         # state /create_elevator
-        self.states["/create_elevator"] = State(7, "/create_elevator", self)
+        self.states["/create_elevator"] = State(10, "/create_elevator", self)
         
         # state /creating
-        self.states["/creating"] = State(8, "/creating", self)
+        self.states["/creating"] = State(11, "/creating", self)
         
         # state /running
-        self.states["/running"] = State(9, "/running", self)
+        self.states["/running"] = State(12, "/running", self)
         
         # add children
         self.states[""].addChild(self.states["/creating_window"])
@@ -90,12 +103,17 @@ class MainApp(RuntimeClassBase):
         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["/running"])
+        self.states["/create_controls"].addChild(self.states["/create_controls/create_buttons"])
+        self.states["/create_controls/create_buttons"].addChild(self.states["/create_controls/create_buttons/create_a_button"])
+        self.states["/create_controls/create_buttons"].addChild(self.states["/create_controls/create_buttons/start_a_button"])
+        self.states["/create_controls/create_buttons"].addChild(self.states["/create_controls/create_buttons/check_next"])
         self.states[""].fixTree()
         self.states[""].default_state = self.states["/creating_window"]
+        self.states["/create_controls"].default_state = self.states["/create_controls/create_buttons"]
+        self.states["/create_controls/create_buttons"].default_state = self.states["/create_controls/create_buttons/create_a_button"]
         
         # transition /creating_window
         _creating_window_0 = Transition(self, self.states["/creating_window"], [self.states["/creating_canvas"]])
@@ -129,17 +147,27 @@ class MainApp(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_controls/create_buttons/create_a_button
+        _create_controls_create_buttons_create_a_button_0 = Transition(self, self.states["/create_controls/create_buttons/create_a_button"], [self.states["/create_controls/create_buttons/start_a_button"]])
+        _create_controls_create_buttons_create_a_button_0.setAction(self._create_controls_create_buttons_create_a_button_0_exec)
+        _create_controls_create_buttons_create_a_button_0.setTrigger(Event("instance_created", None))
+        self.states["/create_controls/create_buttons/create_a_button"].addTransition(_create_controls_create_buttons_create_a_button_0)
+        
+        # transition /create_controls/create_buttons/start_a_button
+        _create_controls_create_buttons_start_a_button_0 = Transition(self, self.states["/create_controls/create_buttons/start_a_button"], [self.states["/create_controls/create_buttons/check_next"]])
+        _create_controls_create_buttons_start_a_button_0.setTrigger(Event("instance_started", None))
+        self.states["/create_controls/create_buttons/start_a_button"].addTransition(_create_controls_create_buttons_start_a_button_0)
+        
+        # transition /create_controls/create_buttons/check_next
+        _create_controls_create_buttons_check_next_0 = Transition(self, self.states["/create_controls/create_buttons/check_next"], [self.states["/create_controls/create_buttons/create_a_button"]])
+        _create_controls_create_buttons_check_next_0.setAction(self._create_controls_create_buttons_check_next_0_exec)
+        _create_controls_create_buttons_check_next_0.setTrigger(None)
+        _create_controls_create_buttons_check_next_0.setGuard(self._create_controls_create_buttons_check_next_0_guard)
+        self.states["/create_controls/create_buttons/check_next"].addTransition(_create_controls_create_buttons_check_next_0)
+        _create_controls_create_buttons_check_next_1 = Transition(self, self.states["/create_controls/create_buttons/check_next"], [self.states["/create_elevator"]])
+        _create_controls_create_buttons_check_next_1.setTrigger(None)
+        _create_controls_create_buttons_check_next_1.setGuard(self._create_controls_create_buttons_check_next_1_guard)
+        self.states["/create_controls/create_buttons/check_next"].addTransition(_create_controls_create_buttons_check_next_1)
         
         # transition /create_elevator
         _create_elevator_0 = Transition(self, self.states["/create_elevator"], [self.states["/creating"]])
@@ -166,12 +194,23 @@ class MainApp(RuntimeClassBase):
         _running_2.setAction(self._running_2_exec)
         _running_2.setTrigger(Event("update_bounds", None))
         self.states["/running"].addTransition(_running_2)
+        _running_3 = Transition(self, self.states["/running"], [self.states["/running"]])
+        _running_3.setAction(self._running_3_exec)
+        _running_3.setTrigger(Event("button_pressed", None))
+        self.states["/running"].addTransition(_running_3)
+        _running_4 = Transition(self, self.states["/running"], [self.states["/running"]])
+        _running_4.setAction(self._running_4_exec)
+        _running_4.setTrigger(Event("open_elevator", None))
+        self.states["/running"].addTransition(_running_4)
     
     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']]))
     
     def _creating_canvas_enter(self):
-        self.big_step.outputEvent(Event("create_canvas", self.getOutPortName("ui"), [self.window_id, CANVAS_DIMS[0], CANVAS_DIMS[1] - 200, {'background':'#fff'}, self.inports['field_ui']]))
+        self.big_step.outputEvent(Event("create_canvas", self.getOutPortName("ui"), [self.window_id, CANVAS_DIMS[0], CANVAS_DIMS[1] - 150, {'background':'#fff'}, self.inports['field_ui']]))
+    
+    def _create_controls_create_buttons_create_a_button_enter(self):
+        self.big_step.outputEventOM(Event("create_instance", None, [self, "button", "ElevatorButton", self.window_id, self.canvas_id, self.button_num - 1]))
     
     def _creating_window_0_exec(self, parameters):
         window_id = parameters[0]
@@ -197,13 +236,19 @@ class MainApp(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):
+    def _create_controls_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 _create_controls_create_buttons_check_next_0_exec(self, parameters):
+        self.button_num -= 1
+    
+    def _create_controls_create_buttons_check_next_0_guard(self, parameters):
+        return self.button_num != 1
+    
+    def _create_controls_create_buttons_check_next_1_guard(self, parameters):
+        return self.button_num == 1
+    
     def _create_elevator_0_exec(self, parameters):
         self.big_step.outputEventOM(Event("create_instance", None, [self, "elevator", "Elevator", self.canvas_id]))
     
@@ -229,6 +274,13 @@ class MainApp(RuntimeClassBase):
         vel = parameters[2]
         self.big_step.outputEventOM(Event("broad_cast", None, [self, Event("update_bounds", None, [pos, dim, vel])]))
     
+    def _running_3_exec(self, parameters):
+        floor_number = parameters[0]
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'elevator', Event("move_elevator", None, [floor_number])]))
+    
+    def _running_4_exec(self, parameters):
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'ball', Event("open_elevator", None, [])]))
+    
     def initializeStatechart(self):
         # enter default state
         self.default_targets = self.states["/creating_window"].getEffectiveTargetStates()
@@ -261,7 +313,9 @@ class Floor(RuntimeClassBase):
         self.canvas_id = canvas_id;
         self.floor_num = floor_num;
         
-        y_dim = (CANVAS_DIMS[1] - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
+        height = CANVAS_DIMS[1] - 150
+        
+        y_dim = (height - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
         
         self.dim = {'x': FLOOR_LENGTH, 'y': y_dim};
         
@@ -269,7 +323,7 @@ class Floor(RuntimeClassBase):
         # 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)  )};
+        self.pos = {'x': FLOOR_LENGTH / 2, 'y': height - (y_dim /2) - ( self.floor_num * (y_dim + FLOOR_SPACE)  )};
     
     def user_defined_destructor(self):
         pass
@@ -329,140 +383,8 @@ class Floor(RuntimeClassBase):
         self.default_targets = self.states["/creating_floor"].getEffectiveTargetStates()
         RuntimeClassBase.initializeStatechart(self)
 
-class ElevatorControls(RuntimeClassBase):
-    def __init__(self, controller, canvas_id):
-        RuntimeClassBase.__init__(self, controller)
-        
-        self.inports["control_ui"] = controller.addInputPort("control_ui", self)
-        
-        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
-        ElevatorControls.user_defined_constructor(self, canvas_id)
-    
-    def user_defined_constructor(self, canvas_id):
-        self.canvas_id = canvas_id;
-        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):
-        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']]))
-    
-    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 ElevatorButton(RuntimeClassBase):
-    def __init__(self, controller, canvas_id, number):
+    def __init__(self, controller, window_id, canvas_id, number):
         RuntimeClassBase.__init__(self, controller)
         
         self.inports["button_ui"] = controller.addInputPort("button_ui", self)
@@ -477,9 +399,10 @@ class ElevatorButton(RuntimeClassBase):
         self.build_statechart_structure()
         
         # call user defined constructor
-        ElevatorButton.user_defined_constructor(self, canvas_id, number)
+        ElevatorButton.user_defined_constructor(self, window_id, canvas_id, number)
     
-    def user_defined_constructor(self, canvas_id, number):
+    def user_defined_constructor(self, window_id, canvas_id, number):
+        self.window_id = window_id;
         self.canvas_id = canvas_id;
         self.button_id = None;
         
@@ -514,32 +437,29 @@ class ElevatorButton(RuntimeClassBase):
         # 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))
+        _creating_0.setTrigger(Event("button_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("clicked", self.getInPortName("button_ui")))
+        _running_0.setTrigger(Event("mouse_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 - 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']]))
+        self.big_step.outputEvent(Event("create_button", self.getOutPortName("ui"), [self.window_id, 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"), [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']]))
+        button_id = parameters[0]
+        self.button_id = button_id
+        self.big_step.outputEvent(Event("bind_event", self.getOutPortName("ui"), [button_id, ui.EVENTS.MOUSE_CLICK, "mouse_click", self.inports['button_ui']]))
     
     def _running_0_exec(self, parameters):
         x = parameters[0]
         y = parameters[1]
         button = parameters[2]
-        self.big_step.outputEvent(Event("set_element_color", self.getOutPortName("ui"), [self.canvas_id, self.button_id, '#ff0']))
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("button_pressed", None, [self.number])]))
     
     def _running_0_guard(self, parameters):
         x = parameters[0]
@@ -578,13 +498,19 @@ class Elevator(RuntimeClassBase):
     def user_defined_constructor(self, canvas_id):
         self.canvas_id = canvas_id;
         
-        self.is_open = False;
+        height = CANVAS_DIMS[1] - 150
         
-        elevator_height = (CANVAS_DIMS[1] - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
+        elevator_height = (height - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
         
         self.dim = {'x': elevator_height, 'y': elevator_height};
         self.vel = -2;
-        self.pos = {'x': FLOOR_LENGTH + (elevator_height / 2), 'y': (CANVAS_DIMS[1] - (elevator_height / 2))};
+        
+        self.current_floor = 0;
+        
+        self.pos = {'x': FLOOR_LENGTH + (elevator_height / 2), 'y': (height - (elevator_height / 2))};
+        self.next_pos = {'x': FLOOR_LENGTH / 2, 'y': None};
+        
+        
         self.smooth = 0.6; # value between 0 and 1
     
     def user_defined_destructor(self):
@@ -613,7 +539,6 @@ class Elevator(RuntimeClassBase):
         # 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)
@@ -646,15 +571,17 @@ class Elevator(RuntimeClassBase):
         
         # 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"))
+        _root_running_idle_0.setAction(self._root_running_idle_0_exec)
+        _root_running_idle_0.setTrigger(Event("move_elevator", None))
         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("_1after"))
+        _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/idle"]])
+        _root_running_move_1.setAction(self._root_running_move_1_exec)
         _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)
@@ -663,17 +590,14 @@ class Elevator(RuntimeClassBase):
         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)
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("update_bounds", None, [self.pos, self.dim, self.vel])]))
     
     def _root_running_move_enter(self):
         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)
+        self.addTimer(0, 0.02)
     
     def _root_running_move_exit(self):
-        self.removeTimer(1)
+        self.removeTimer(0)
     
     def _root_waiting_0_exec(self, parameters):
         association_name = parameters[0]
@@ -688,12 +612,26 @@ class Elevator(RuntimeClassBase):
         rect_id = parameters[1]
         self.elevator_id = rect_id
     
+    def _root_running_idle_0_exec(self, parameters):
+        floor_number = parameters[0]
+        if self.current_floor < floor_number:
+            self.vel = -2
+        else:
+            self.vel = 2
+        
+        height = (CANVAS_DIMS[1] - 150)
+        y_dim = (height - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
+        self.next_pos['y'] = height - (y_dim /2) - (floor_number * (y_dim + FLOOR_SPACE));
+    
     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_move_1_exec(self, parameters):
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("open_elevator", None, [])]))
+    
     def _root_running_move_1_guard(self, parameters):
-        return (self.pos['y'] - (self.dim['y']/2)) < 0
+        return (self.pos['y']) < self.next_pos['y']
     
     def initializeStatechart(self):
         # enter default state
@@ -763,17 +701,11 @@ class Ball(RuntimeClassBase):
         self.states["/main_behaviour/bouncing"].setEnter(self._main_behaviour_bouncing_enter)
         self.states["/main_behaviour/bouncing"].setExit(self._main_behaviour_bouncing_exit)
         
-        # state /main_behaviour/dragging
-        self.states["/main_behaviour/dragging"] = State(5, "/main_behaviour/dragging", self)
-        
-        # 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)
+        self.states["/main_behaviour/ball_delete"] = State(5, "/main_behaviour/ball_delete", self)
         
         # state /deleted
-        self.states["/deleted"] = State(8, "/deleted", self)
+        self.states["/deleted"] = State(6, "/deleted", self)
         
         # add children
         self.states[""].addChild(self.states["/main_behaviour"])
@@ -781,8 +713,6 @@ class Ball(RuntimeClassBase):
         self.states["/main_behaviour"].addChild(self.states["/main_behaviour/initializing"])
         self.states["/main_behaviour"].addChild(self.states["/main_behaviour/creating_circle"])
         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"]
@@ -805,13 +735,12 @@ class Ball(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/ball_delete"]])
-        _main_behaviour_bouncing_1.setTrigger(None)
-        _main_behaviour_bouncing_1.setGuard(self._main_behaviour_bouncing_1_guard)
+        _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.setTrigger(Event("open_elevator", None))
         self.states["/main_behaviour/bouncing"].addTransition(_main_behaviour_bouncing_1)
-        _main_behaviour_bouncing_2 = Transition(self, self.states["/main_behaviour/bouncing"], [self.states["/main_behaviour/selected"]])
-        _main_behaviour_bouncing_2.setAction(self._main_behaviour_bouncing_2_exec)
-        _main_behaviour_bouncing_2.setTrigger(Event("mouse_press", self.getInPortName("ball_ui")))
+        _main_behaviour_bouncing_2 = Transition(self, self.states["/main_behaviour/bouncing"], [self.states["/main_behaviour/ball_delete"]])
+        _main_behaviour_bouncing_2.setTrigger(None)
         _main_behaviour_bouncing_2.setGuard(self._main_behaviour_bouncing_2_guard)
         self.states["/main_behaviour/bouncing"].addTransition(_main_behaviour_bouncing_2)
         _main_behaviour_bouncing_3 = Transition(self, self.states["/main_behaviour/bouncing"], [self.states["/main_behaviour/bouncing"]])
@@ -819,23 +748,6 @@ class Ball(RuntimeClassBase):
         _main_behaviour_bouncing_3.setTrigger(Event("update_bounds", None))
         self.states["/main_behaviour/bouncing"].addTransition(_main_behaviour_bouncing_3)
         
-        # transition /main_behaviour/dragging
-        _main_behaviour_dragging_0 = Transition(self, self.states["/main_behaviour/dragging"], [self.states["/main_behaviour/dragging"]])
-        _main_behaviour_dragging_0.setAction(self._main_behaviour_dragging_0_exec)
-        _main_behaviour_dragging_0.setTrigger(Event("mouse_move", self.getInPortName("ball_ui")))
-        self.states["/main_behaviour/dragging"].addTransition(_main_behaviour_dragging_0)
-        _main_behaviour_dragging_1 = Transition(self, self.states["/main_behaviour/dragging"], [self.states["/main_behaviour/bouncing"]])
-        _main_behaviour_dragging_1.setAction(self._main_behaviour_dragging_1_exec)
-        _main_behaviour_dragging_1.setTrigger(Event("mouse_release", self.getInPortName("ball_ui")))
-        self.states["/main_behaviour/dragging"].addTransition(_main_behaviour_dragging_1)
-        
-        # transition /main_behaviour/selected
-        _main_behaviour_selected_0 = Transition(self, self.states["/main_behaviour/selected"], [self.states["/main_behaviour/dragging"]])
-        _main_behaviour_selected_0.setAction(self._main_behaviour_selected_0_exec)
-        _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)
-        
         # 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)
@@ -880,9 +792,9 @@ class Ball(RuntimeClassBase):
                 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_height = ((CANVAS_DIMS[1] - 150) - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
             floor_dim = {'x': FLOOR_LENGTH, 'y': floor_height};
-            floor_pos = {'x': FLOOR_LENGTH / 2, 'y': CANVAS_DIMS[1] - (floor_height /2) - ( self.floor_num * (floor_height + FLOOR_SPACE)  )};
+            floor_pos = {'x': FLOOR_LENGTH / 2, 'y': (CANVAS_DIMS[1] - 150) - (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
@@ -905,20 +817,11 @@ class Ball(RuntimeClassBase):
         self.pos['x'] += self.vel['x']
         self.pos['y'] += self.vel['y']
     
-    def _main_behaviour_bouncing_1_guard(self, parameters):
-        return self.pos['x'] - self.r < 2
-    
-    def _main_behaviour_bouncing_2_exec(self, parameters):
-        x = parameters[0]
-        y = parameters[1]
-        button = parameters[2]
-        self.big_step.outputEvent(Event("set_element_color", self.getOutPortName("ui"), [self.canvas_id, self.circle_id, '#ff0']))
+    def _main_behaviour_bouncing_1_exec(self, parameters):
+        self.elevator_open = True
     
     def _main_behaviour_bouncing_2_guard(self, parameters):
-        x = parameters[0]
-        y = parameters[1]
-        button = parameters[2]
-        return button == ui.MOUSE_BUTTONS.LEFT
+        return self.pos['x'] - self.r < 2
     
     def _main_behaviour_bouncing_3_exec(self, parameters):
         pos = parameters[0]
@@ -929,42 +832,6 @@ class Ball(RuntimeClassBase):
         self.rect_vel = vel
         self.elevator_open = False
     
-    def _main_behaviour_dragging_0_exec(self, parameters):
-        x = parameters[0]
-        y = parameters[1]
-        button = parameters[2]
-        # Always keep ball within canvas:
-        x = min(max(0+self.r, x), CANVAS_DIMS[0]-self.r)
-        y = min(max(0+self.r, y), CANVAS_DIMS[1]-self.r)
-        
-        dx = x - self.pos['x']
-        dy = y - self.pos['y']
-        
-        self.vel = {
-            'x': (1-self.smooth)*dx + self.smooth*self.vel['x'],
-            'y': (1-self.smooth)*dy + self.smooth*self.vel['y']
-        }
-        
-        self.pos = {'x': x, 'y': y}
-        self.big_step.outputEvent(Event("set_element_pos", self.getOutPortName("ui"), [self.canvas_id, self.circle_id, x-self.r, y-self.r]))
-    
-    def _main_behaviour_dragging_1_exec(self, parameters):
-        x = parameters[0]
-        y = parameters[1]
-        self.big_step.outputEvent(Event("set_element_color", self.getOutPortName("ui"), [self.canvas_id, self.circle_id, '#f00']))
-    
-    def _main_behaviour_selected_0_exec(self, parameters):
-        x = parameters[0]
-        y = parameters[1]
-        button = parameters[2]
-        self.mouse_pos = {'x': x, 'y': y};
-    
-    def _main_behaviour_selected_0_guard(self, parameters):
-        x = parameters[0]
-        y = parameters[1]
-        button = parameters[2]
-        return button == ui.MOUSE_BUTTONS.LEFT
-    
     def _main_behaviour_ball_delete_0_exec(self, parameters):
         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]))
@@ -983,26 +850,21 @@ class ObjectManager(ObjectManagerBase):
             instance = MainApp(self.controller)
             instance.associations = {}
             instance.associations["floor"] = Association("Floor", 2, -1)
-            instance.associations["controls"] = Association("ElevatorControls", 1, 1)
+            instance.associations["button"] = Association("ElevatorButton", 0, -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["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["parent"] = Association("Elevator", 1, 1)
         elif class_name == "ElevatorButton":
-            instance = ElevatorButton(self.controller, construct_params[0], construct_params[1])
+            instance = ElevatorButton(self.controller, construct_params[0], construct_params[1], construct_params[2])
             instance.associations = {}
-            instance.associations["parent"] = Association("ElevatorControls", 1, 1)
+            instance.associations["parent"] = Association("MainApp", 1, 1)
         elif class_name == "Elevator":
             instance = Elevator(self.controller, construct_params[0])
             instance.associations = {}
-            instance.associations["floors"] = Association("Floors", 1, 1)
+            instance.associations["floors"] = Association("Floor", 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])

+ 694 - 0
examples/ElevatorBalls/nice_sccd.xml

@@ -0,0 +1,694 @@
+<?xml version="1.0" ?>
+<diagram author="Sam Pieters" name="Elevator Balls">
+    <top>
+        import sccd.runtime.libs.ui_v2 as ui
+        import random
+        import time
+
+        CANVAS_DIMS = (800, 550)
+        FLOOR_LENGTH = 350
+        FLOOR_SPACE = 50
+        FLOORS = 3
+    </top>
+    <inport name="ui" />
+    <outport name="ui" />
+    <class name="MainApp" default="true">
+        <relationships>
+            <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" />
+        <attribute name="num_floors" />
+        <attribute name="floor_dimensions" />
+        <atrribute name="floor_height" />
+        <inport name="field_ui"/>
+        <constructor>
+            <body>
+                self.num_floors = 0
+            </body>
+        </constructor>
+        <scxml initial="creating_window">
+            <state id="creating_window">
+                <onentry>
+                    <raise port="ui" event="create_window">
+                        <parameter expr="CANVAS_DIMS[0]"/><!-- width -->
+                        <parameter expr="CANVAS_DIMS[1]"/><!-- height -->
+                        <parameter expr='"Bouncing Balls Elevator"'/><!-- title -->
+                        <parameter expr="self.inports['field_ui']"/><!-- inport for response -->
+                    </raise>
+                </onentry>
+                <transition event="window_created" target="../creating_canvas">
+                    <parameter name="window_id" type="int" />
+                    <script>
+                        self.window_id = window_id
+                    </script>
+                    <raise port="ui" event="bind_event">
+                        <parameter expr="window_id"/><!-- widget_id -->
+                        <parameter expr="ui.EVENTS.WINDOW_CLOSE"/><!-- tk_event -->
+                        <parameter expr="'window_close'"/><!-- sccd_event_name -->
+                        <parameter expr="self.inports['field_ui']"/><!-- inport for response -->
+                    </raise>
+                    <raise port="ui" event="bind_event">
+                        <parameter expr="window_id"/><!-- widget_id -->
+                        <parameter expr="ui.EVENTS.KEY_PRESS"/><!-- tk_event -->
+                        <parameter expr="'key_press'"/><!-- sccd_event_name -->
+                        <parameter expr="self.inports['field_ui']"/><!-- inport for response -->
+                    </raise>
+                </transition>
+            </state>
+            <state id="creating_canvas">
+                <onentry>
+                    <raise port="ui" event="create_canvas">
+                        <parameter expr="self.window_id"/><!-- window_id -->
+                        <parameter expr="CANVAS_DIMS[0]"/><!-- width -->
+                        <parameter expr="CANVAS_DIMS[1] - 200"/><!-- height -->
+                        <parameter expr="{'background':'#fff'}"/><!-- style -->
+                        <parameter expr="self.inports['field_ui']"/><!-- inport for response -->
+                    </raise>
+                </onentry>
+                <transition event="canvas_created" target="../create_floors">
+                    <parameter name="canvas_id" type="int"/>
+                    <script>
+                        self.canvas_id = canvas_id
+                    </script>
+                </transition>
+            </state>
+            <state id="create_floors">
+                <transition target="../create_controls" cond="self.num_floors == FLOORS">
+                </transition>
+                <transition target="../wait" cond="self.num_floors != FLOORS">
+                    <raise scope="cd" event="create_instance">
+                        <parameter expr='"floor"' />
+                        <parameter expr='"Floor"' />
+                        <parameter expr="self.canvas_id" />
+                        <parameter expr="self.num_floors" />
+                    </raise>
+                    <script>
+                        self.num_floors += 1
+                    </script>
+                </transition>
+            </state>
+            <state id="wait">
+                <transition event='instance_created' target='.'>
+                    <parameter name="association_name" type="string"/>
+                    <raise scope="cd" event="start_instance">
+                        <parameter expr="association_name" />
+                    </raise>
+                </transition>
+                <transition event="instance_started" target="../create_floors" />
+            </state>
+            <state id="create_controls">
+                <transition target="../creating_controls">
+                    <raise scope="cd" event="create_instance">
+                        <parameter expr='"controls"' />
+                        <parameter expr='"ElevatorControls"' />
+                        <parameter expr="self.canvas_id" />
+                    </raise>
+                </transition>
+            </state>
+            <state id="creating_controls">
+                <transition event="instance_created" target="../create_elevator">
+                    <parameter name="association_name" type="string"/>
+                    <raise scope="cd" event="start_instance">
+                        <parameter expr="association_name" />
+                    </raise>
+                </transition>
+            </state>
+            <state id="create_elevator">
+                <transition target="../creating">
+                    <raise scope="cd" event="create_instance">
+                        <parameter expr='"elevator"' />
+                        <parameter expr='"Elevator"' />
+                        <parameter expr="self.canvas_id" />
+                    </raise>
+                </transition>
+            </state>
+            <state id="creating">
+                <transition event="instance_created" target="../running">
+                    <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" />
+                        <parameter expr="self.canvas_id" />
+                        <parameter expr="self.window_id" />
+                    </raise>
+                </transition>
+            </state>
+            <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>
+
+    <class name="Floor">
+        <attribute name="window_id" />
+        <attribute name="canvas_id" />
+        <attribute name="elevator_id" />
+        <atrribute name="pos" />
+        <inport name="floor_ui"/>
+        <relationships>
+            <association name="parent" class="MainApp" min="1" max="1" />
+        </relationships>
+        <constructor>
+            <parameter name="canvas_id" />
+            <parameter name="floor_num" />
+            <body>
+                <![CDATA[
+                self.canvas_id = canvas_id;
+                self.floor_num = floor_num;
+
+                y_dim = (CANVAS_DIMS[1] - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
+
+                self.dim = {'x': FLOOR_LENGTH, 'y': y_dim};
+
+
+                # 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>
+        <scxml initial="creating_floor">
+            <state id="creating_floor">
+                <onentry>
+                    <raise port="ui" event="create_rectangle">
+                        <parameter expr="self.canvas_id" />
+                        <parameter expr="self.pos['x']"/>
+                        <parameter expr="self.pos['y']"/>
+                        <parameter expr="self.dim['x']" />
+                        <parameter expr="self.dim['y']"/>
+                        <parameter expr="{'fill':'white', 'outline': 'black'}"/><!-- style -->
+                        <parameter expr="self.inports['floor_ui']"/><!-- inport for response -->
+                    </raise>
+                </onentry>
+                <transition event="rectangle_created" target="../running">
+                </transition>
+            </state>
+            <state id="running" initial="create_random_ball">
+                <state id="create_random_ball" >
+                    <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>
+        </scxml>
+    </class>
+
+    <class name="ElevatorControls">
+        <inport name="control_ui"/>
+        <relationships>
+            <association name="button" class="ElevatorButton" />
+            <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 - 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>
+        <scxml initial="creating">
+            <state id="creating" initial="create_rect">
+                <state id="create_rect">
+                    <onentry>
+                        <raise port="ui" event="create_rectangle">
+                            <parameter expr="self.canvas_id" />
+                            <parameter expr="self.pos['x']"/>
+                            <parameter expr="self.pos['y']"/>
+                            <parameter expr="self.dim['x']" />
+                            <parameter expr="self.dim['y']"/>
+                            <parameter expr="{'fill':'grey', 'outline': 'black'}"/><!-- style -->
+                            <parameter expr="self.inports['control_ui']"/><!-- inport for response -->
+                        </raise>
+                        <raise port="ui" event="create_text">
+                            <parameter expr="self.canvas_id" />
+                            <parameter expr="self.pos['x']"/>
+                            <parameter expr="20"/>
+                            <parameter expr="'Elevator Controls'"/>
+                            <parameter expr="self.inports['control_ui']"/><!-- inport for response -->
+                        </raise>
+                    </onentry>
+                    <transition target="../create_buttons" />
+                </state>
+                <state id="create_buttons" initial="create_a_button">
+                    <state id="create_a_button">
+                        <onentry>
+                            <raise scope="cd" event="create_instance">
+                                <parameter expr='"button"' />
+                                <parameter expr='"ElevatorButton"' />
+                                <parameter expr="self.canvas_id" />
+                                <parameter expr="self.button_num" />
+                            </raise>
+                        </onentry>
+                        <transition event='instance_created' target='../start_a_button'>
+                            <parameter name="association_name" type="string"/>
+                            <raise scope="cd" event="start_instance">
+                                <parameter expr="association_name" />
+                            </raise>
+                        </transition>
+                    </state>
+                    <state id="start_a_button">
+                        <transition event="instance_started" target="../check_next" />
+                    </state>
+                    <state id="check_next">
+                        <transition target="../create_a_button" cond="self.button_num != 0">
+                            <script>
+                                self.button_num -= 1
+                            </script>
+                        </transition>
+                        <transition target="../../../running" cond="self.button_num == 0" />
+                    </state>
+                </state>
+            </state>
+            <state id="running">
+                <transition event="button_pressed" target='.'>
+                    <parameter name="floor" type="int" />
+                    <raise event="move_elevator" scope="narrow" target="'parent'">
+                        <parameter expr='0' />
+                    </raise>
+                </transition>
+            </state>
+        </scxml>
+    </class>
+
+    <class name="ElevatorButton">
+        <inport name="button_ui"/>
+        <relationships>
+            <association name="parent" class="ElevatorControls" min="1" max="1" />
+        </relationships>
+        <constructor>
+            <parameter name="canvas_id" />
+            <parameter name="number" />
+            <body>
+                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;
+            </body>
+        </constructor>
+        <scxml initial="creating">
+            <state id="creating">
+                <onentry>
+                    <raise port="ui" event="create_circle">
+                        <parameter expr="self.canvas_id" />
+                        <parameter expr="CANVAS_DIMS[0] - 70"/>
+                        <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 -->
+                    </raise>
+                    <raise port="ui" event="create_text">
+                        <parameter expr="self.canvas_id" />
+                        <parameter expr="CANVAS_DIMS[0] - 70"/>
+                        <parameter expr="45 + (30 * (FLOORS - 1 - self.number)) "/>
+                        <parameter expr="str(self.number)"/>
+                        <parameter expr="self.inports['button_ui']"/><!-- inport for response -->
+                    </raise>
+                </onentry>
+                <transition event="circle_created" target="../running">
+                    <parameter name="canvas_id"/>
+                    <parameter name="circle_id"/>
+                    <script>
+                        self.button_id = circle_id
+                    </script>
+                    <raise port="ui" event="bind_canvas_event">
+                        <parameter expr="self.canvas_id"/>
+                        <parameter expr="circle_id"/><!-- widget_id -->
+                        <parameter expr="ui.EVENTS.MOUSE_PRESS"/><!-- tk_event -->
+                        <parameter expr="'clicked'"/><!-- sccd_event_name -->
+                        <parameter expr="self.inports['button_ui']"/><!-- inport for response -->
+                    </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['button_ui']"/>
+                    </raise>
+                </transition>
+            </state>
+            <state id="running">
+                <transition port='button_ui' event="clicked" target='.' cond="button == ui.MOUSE_BUTTONS.LEFT">
+                    <parameter name="x" />
+                    <parameter name="y" />
+                    <parameter name="button" />
+                    <raise port="ui" event="set_element_color">
+                        <parameter expr="self.canvas_id"/>
+                        <parameter expr="self.button_id"/>
+                        <parameter expr="'#ff0'"/>
+                    </raise>
+                </transition>
+            </state>
+        </scxml>
+    </class>
+
+    <class name="Elevator">
+        <attribute name="window_id" />
+        <attribute name="canvas_id" />
+        <attribute name="elevator_id" />
+        <atrribute name="pos" />
+        <inport name="elevator_ui"/>
+        <relationships>
+            <association name="floors" class="Floor" min="1" max="1" />
+            <association name="parent" class="MainApp" min="1" max="1" />
+        </relationships>
+        <constructor>
+            <parameter name="canvas_id" />
+            <body>
+                <![CDATA[
+                self.canvas_id = canvas_id;
+
+                self.is_open = False;
+
+                elevator_height = (CANVAS_DIMS[1] - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
+
+                self.dim = {'x': elevator_height, 'y': elevator_height};
+                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
+                ]]>
+            </body>
+        </constructor>
+        <scxml initial="root">
+            <state id="root" initial="waiting">
+                <state id="waiting">
+                    <transition event="set_association_name" target="../creating_elevator">
+                        <parameter name="association_name" type="str" />
+                        <parameter name="canvas_id" type="int" />
+                        <parameter name="window_id" type="int" />
+                        <script>
+                            self.association_name = association_name
+                            self.canvas_id = canvas_id
+                            self.window_id = window_id
+                        </script>
+                    </transition>
+                </state>
+                <state id="creating_elevator">
+                    <onentry>
+                        <raise port="ui" event="create_rectangle">
+                            <parameter expr="self.canvas_id" />
+                            <parameter expr="self.pos['x']"/>
+                            <parameter expr="self.pos['y']"/>
+                            <parameter expr="self.dim['x']" />
+                            <parameter expr="self.dim['y']"/>
+                            <parameter expr="{'fill':'white', 'outline': 'black'}"/><!-- style -->
+                            <parameter expr="self.inports['elevator_ui']"/><!-- inport for response -->
+                        </raise>
+                    </onentry>
+                    <transition event="rectangle_created" target="../running">
+                        <parameter name="canvas_id" type="int" />
+                        <parameter name="rect_id" type="int" />
+                        <script>
+                            self.elevator_id = rect_id
+                        </script>
+                    </transition>
+                </state>
+                <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"/>
+                                <parameter expr="self.elevator_id"/>
+                                <parameter expr="self.pos['x']"/>
+                                <parameter expr="self.pos['y']"/>
+                            </raise>
+                            <script>
+                                self.pos['y'] += self.vel
+                            </script>
+                        </transition>
+                        <transition target="../idle" cond="(self.pos['y'] - (self.dim['y']/2)) &lt; 0">
+                        </transition>
+                    </state>
+                </state>
+            </state>
+        </scxml>
+    </class>
+
+    <class name="Ball">
+        <attribute name="canvas_id" />
+        <atrribute name="circle_id" />
+        <attribute name="pos" />
+        <inport name="ball_ui" />
+        <relationships>
+            <association name="parent" class="MainApp" min="1" max="1" />
+        </relationships>
+        <constructor>
+            <parameter name="canvas_id" />
+            <parameter name="floor_num" />
+            <parameter name="x" />
+            <parameter name="y" />
+            <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};
+                self.smooth = 0.6; # value between 0 and 1
+                ]]>
+            </body>
+        </constructor>
+        <destructor>
+        </destructor>
+        <scxml initial="main_behaviour">
+            <state id="main_behaviour" initial="initializing">
+                <state id="initializing">
+                    <transition event="set_association_name" target="../creating_circle">
+                        <parameter name="association_name" type="str" />
+                        <script>
+                            self.association_name = association_name
+                        </script>
+                    </transition>
+                </state>
+                <state id="creating_circle">
+                    <onentry>
+                        <raise port="ui" event="create_circle">
+                            <parameter expr="self.canvas_id"/><!-- canvas_id -->
+                            <parameter expr="self.pos['x']"/><!-- x -->
+                            <parameter expr="self.pos['y']"/><!-- y -->
+                            <parameter expr="self.r"/><!-- r -->
+                            <parameter expr="{'fill':'#000'}"/><!-- style -->
+                            <parameter expr="self.inports['ball_ui']"/><!-- inport for response -->
+                        </raise>
+                    </onentry>
+                    <transition event="circle_created" target="../bouncing">
+                        <parameter name="canvas_id"/>
+                        <parameter name="circle_id"/>
+                        <script>
+                            self.circle_id = circle_id
+                        </script>
+                    </transition>
+                </state>
+                <state id="bouncing">
+                    <transition after="0.02" target=".">
+                        <script>
+                            <![CDATA[
+                            if self.floor_num == -1:
+                                if self.pos['x'] - self.r < self.rect_pos['x'] - (self.rect_dim['x'] / 2):
+                                    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
+                                    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
+                                    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
+                                    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': 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
+                                    self.vel['x'] = -self.vel['x']
+                                elif self.pos['x'] + self.r > floor_pos['x'] + (floor_dim['x'] / 2):
+                                    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
+                                    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
+                                    self.vel['y'] = -self.vel['y']
+
+                            ]]>
+                        </script>
+                        <raise port="ui" event="move_element">
+                            <parameter expr="self.canvas_id"/>
+                            <parameter expr="self.circle_id"/>
+                            <parameter expr="self.vel['x']"/>
+                            <parameter expr="self.vel['y']"/>
+                        </raise>
+                        <script>
+                            self.pos['x'] += self.vel['x']
+                            self.pos['y'] += self.vel['y']
+                        </script>
+                    </transition>
+                    <transition target="../ball_delete" cond="self.pos['x'] - self.r &lt; 2" />
+                    <transition port="ball_ui" event="mouse_press" target="../selected" cond="button == ui.MOUSE_BUTTONS.LEFT">
+                        <parameter name="x" />
+                        <parameter name="y" />
+                        <parameter name="button" />
+                        <raise port="ui" event="set_element_color">
+                            <parameter expr="self.canvas_id"/>
+                            <parameter expr="self.circle_id"/>
+                            <parameter expr="'#ff0'"/>
+                        </raise>
+                    </transition>
+                    <transition event="update_bounds" target=".">
+                        <parameter name="pos" type="dict" />
+                        <parameter name="dim" 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>
+                <state id="dragging">
+                    <transition port="ball_ui" event="mouse_move" target=".">
+                        <parameter name="x" />
+                        <parameter name="y" />
+                        <parameter name="button" />
+                        <script>
+                            <![CDATA[
+                            # Always keep ball within canvas:
+                            x = min(max(0+self.r, x), CANVAS_DIMS[0]-self.r)
+                            y = min(max(0+self.r, y), CANVAS_DIMS[1]-self.r)
+
+                            dx = x - self.pos['x']
+                            dy = y - self.pos['y']
+
+                            self.vel = {
+                                'x': (1-self.smooth)*dx + self.smooth*self.vel['x'],
+                                'y': (1-self.smooth)*dy + self.smooth*self.vel['y']
+                            }
+
+                            self.pos = {'x': x, 'y': y}
+                            ]]>
+                        </script>
+                        <raise port="ui" event="set_element_pos">
+                            <parameter expr="self.canvas_id"/>
+                            <parameter expr="self.circle_id"/>
+                            <parameter expr="x-self.r"/>
+                            <parameter expr="y-self.r"/>
+                        </raise>
+                    </transition>
+                    <transition port="ball_ui" event="mouse_release" target="../bouncing">
+                        <parameter name="x" />
+                        <parameter name="y" />
+                        <raise port="ui" event="set_element_color">
+                            <parameter expr="self.canvas_id"/>
+                            <parameter expr="self.circle_id"/>
+                            <parameter expr="'#f00'"/>
+                        </raise>
+                    </transition>
+                </state>
+                <state id='selected'>
+                    <transition port="ball_ui" event="mouse_press" target="../dragging" cond="button == ui.MOUSE_BUTTONS.LEFT">
+                        <parameter name="x" />
+                        <parameter name="y" />
+                        <parameter name="button" />
+                        <script>
+                            <![CDATA[
+                            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="'floor'">
+                            <parameter expr='self.association_name' />
+                        </raise>
+                        <raise port="ui" event="destroy_element">
+                            <parameter expr="self.canvas_id" />
+                            <parameter expr="self.circle_id" />
+                        </raise>
+                    </transition>
+                </state>
+            </state>
+            <state id='deleted' />
+        </scxml>
+    </class>
+</diagram>

+ 104 - 205
examples/ElevatorBalls/sccd.xml

@@ -15,7 +15,7 @@
     <class name="MainApp" default="true">
         <relationships>
             <association name="floor" class="Floor" min="2"/>
-            <association name="controls" class="ElevatorControls" min="1" max="1"/>
+            <association name="button" class="ElevatorButton" />
             <association name="elevator" class="Elevator" min="1" max="1"/>
             <association name="ball" class="Ball" />
         </relationships>
@@ -28,6 +28,9 @@
         <constructor>
             <body>
                 self.num_floors = 0
+                self.button_num = FLOORS
+
+                self.next_elevator_pos = None
             </body>
         </constructor>
         <scxml initial="creating_window">
@@ -64,7 +67,7 @@
                     <raise port="ui" event="create_canvas">
                         <parameter expr="self.window_id"/><!-- window_id -->
                         <parameter expr="CANVAS_DIMS[0]"/><!-- width -->
-                        <parameter expr="CANVAS_DIMS[1] - 200"/><!-- height -->
+                        <parameter expr="CANVAS_DIMS[1] - 150"/><!-- height -->
                         <parameter expr="{'background':'#fff'}"/><!-- style -->
                         <parameter expr="self.inports['field_ui']"/><!-- inport for response -->
                     </raise>
@@ -77,8 +80,7 @@
                 </transition>
             </state>
             <state id="create_floors">
-                <transition target="../create_controls" cond="self.num_floors == FLOORS">
-                </transition>
+                <transition target="../create_controls" cond="self.num_floors == FLOORS" />
                 <transition target="../wait" cond="self.num_floors != FLOORS">
                     <raise scope="cd" event="create_instance">
                         <parameter expr='"floor"' />
@@ -100,22 +102,37 @@
                 </transition>
                 <transition event="instance_started" target="../create_floors" />
             </state>
-            <state id="create_controls">
-                <transition target="../creating_controls">
-                    <raise scope="cd" event="create_instance">
-                        <parameter expr='"controls"' />
-                        <parameter expr='"ElevatorControls"' />
-                        <parameter expr="self.canvas_id" />
-                    </raise>
-                </transition>
-            </state>
-            <state id="creating_controls">
-                <transition event="instance_created" target="../create_elevator">
-                    <parameter name="association_name" type="string"/>
-                    <raise scope="cd" event="start_instance">
-                        <parameter expr="association_name" />
-                    </raise>
-                </transition>
+            <state id="create_controls" initial="create_buttons">
+                <state id="create_buttons" initial="create_a_button">
+                    <state id="create_a_button">
+                        <onentry>
+                            <raise scope="cd" event="create_instance">
+                                <parameter expr='"button"' />
+                                <parameter expr='"ElevatorButton"' />
+                                <parameter expr="self.window_id" />
+                                <parameter expr="self.canvas_id" />
+                                <parameter expr="self.button_num - 1" />
+                            </raise>
+                        </onentry>
+                        <transition event='instance_created' target='../start_a_button'>
+                            <parameter name="association_name" type="string"/>
+                            <raise scope="cd" event="start_instance">
+                                <parameter expr="association_name" />
+                            </raise>
+                        </transition>
+                    </state>
+                    <state id="start_a_button">
+                        <transition event="instance_started" target="../check_next" />
+                    </state>
+                    <state id="check_next">
+                        <transition target="../create_a_button" cond="self.button_num != 1">
+                            <script>
+                                self.button_num -= 1
+                            </script>
+                        </transition>
+                        <transition target="../../../create_elevator" cond="self.button_num == 1" />
+                    </state>
+                </state>
             </state>
             <state id="create_elevator">
                 <transition target="../creating">
@@ -172,6 +189,15 @@
                         <parameter expr="vel" />
                     </raise>
                 </transition>
+                <transition event='button_pressed' target='.'>
+                    <parameter name="floor_number" type="int"/>
+                    <raise scope="narrow" event="move_elevator" target="'elevator'">
+                        <parameter expr="floor_number" />
+                    </raise>
+                </transition>
+                <transition event='open_elevator' target='.'>
+                    <raise scope="narrow" event="open_elevator" target="'ball'" />
+                </transition>
             </state>
         </scxml>
     </class>
@@ -193,7 +219,9 @@
                 self.canvas_id = canvas_id;
                 self.floor_num = floor_num;
 
-                y_dim = (CANVAS_DIMS[1] - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
+                height = CANVAS_DIMS[1] - 150
+
+                y_dim = (height - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
 
                 self.dim = {'x': FLOOR_LENGTH, 'y': y_dim};
 
@@ -201,7 +229,7 @@
                 # 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)  )};
+                self.pos = {'x': FLOOR_LENGTH / 2, 'y': height - (y_dim /2) - ( self.floor_num * (y_dim + FLOOR_SPACE)  )};
                 ]]>
             </body>
         </constructor>
@@ -235,94 +263,17 @@
         </scxml>
     </class>
 
-    <class name="ElevatorControls">
-        <inport name="control_ui"/>
-        <relationships>
-            <association name="button" class="ElevatorButton" />
-            <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 - 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>
-        <scxml initial="creating">
-            <state id="creating" initial="create_rect">
-                <state id="create_rect">
-                    <onentry>
-                        <raise port="ui" event="create_rectangle">
-                            <parameter expr="self.canvas_id" />
-                            <parameter expr="self.pos['x']"/>
-                            <parameter expr="self.pos['y']"/>
-                            <parameter expr="self.dim['x']" />
-                            <parameter expr="self.dim['y']"/>
-                            <parameter expr="{'fill':'grey', 'outline': 'black'}"/><!-- style -->
-                            <parameter expr="self.inports['control_ui']"/><!-- inport for response -->
-                        </raise>
-                        <raise port="ui" event="create_text">
-                            <parameter expr="self.canvas_id" />
-                            <parameter expr="self.pos['x']"/>
-                            <parameter expr="20"/>
-                            <parameter expr="'Elevator Controls'"/>
-                            <parameter expr="self.inports['control_ui']"/><!-- inport for response -->
-                        </raise>
-                    </onentry>
-                    <transition target="../create_buttons" />
-                </state>
-                <state id="create_buttons" initial="create_a_button">
-                    <state id="create_a_button">
-                        <onentry>
-                            <raise scope="cd" event="create_instance">
-                                <parameter expr='"button"' />
-                                <parameter expr='"ElevatorButton"' />
-                                <parameter expr="self.canvas_id" />
-                                <parameter expr="self.button_num" />
-                            </raise>
-                        </onentry>
-                        <transition event='instance_created' target='../start_a_button'>
-                            <parameter name="association_name" type="string"/>
-                            <raise scope="cd" event="start_instance">
-                                <parameter expr="association_name" />
-                            </raise>
-                        </transition>
-                    </state>
-                    <state id="start_a_button">
-                        <transition event="instance_started" target="../check_next" />
-                    </state>
-                    <state id="check_next">
-                        <transition target="../create_a_button" cond="self.button_num != 0">
-                            <script>
-                                self.button_num -= 1
-                            </script>
-                        </transition>
-                        <transition target="../../../running" cond="self.button_num == 0" />
-                    </state>
-                </state>
-            </state>
-            <state id="running">
-                <transition event="button_pressed" target='.'>
-                    <parameter name="floor" type="int" />
-                    <raise event="move_elevator" scope="narrow" target="'parent'">
-                        <parameter expr='0' />
-                    </raise>
-                </transition>
-            </state>
-        </scxml>
-    </class>
-
     <class name="ElevatorButton">
         <inport name="button_ui"/>
         <relationships>
-            <association name="parent" class="ElevatorControls" min="1" max="1" />
+            <association name="parent" class="MainApp" min="1" max="1" />
         </relationships>
         <constructor>
+            <parameter name="window_id" />
             <parameter name="canvas_id" />
             <parameter name="number" />
             <body>
+                self.window_id = window_id;
                 self.canvas_id = canvas_id;
                 self.button_id = None;
                 
@@ -335,53 +286,32 @@
         <scxml initial="creating">
             <state id="creating">
                 <onentry>
-                    <raise port="ui" event="create_circle">
-                        <parameter expr="self.canvas_id" />
-                        <parameter expr="CANVAS_DIMS[0] - 70"/>
-                        <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 -->
-                    </raise>
-                    <raise port="ui" event="create_text">
-                        <parameter expr="self.canvas_id" />
-                        <parameter expr="CANVAS_DIMS[0] - 70"/>
-                        <parameter expr="45 + (30 * (FLOORS - 1 - self.number)) "/>
-                        <parameter expr="str(self.number)"/>
+                    <raise port="ui" event="create_button">
+                        <parameter expr="self.window_id" />
+                        <parameter expr="self.number"/>
                         <parameter expr="self.inports['button_ui']"/><!-- inport for response -->
                     </raise>
                 </onentry>
-                <transition event="circle_created" target="../running">
-                    <parameter name="canvas_id"/>
-                    <parameter name="circle_id"/>
+                <transition event="button_created" target="../running">
+                    <parameter name="button_id"/>
                     <script>
-                        self.button_id = circle_id
+                        self.button_id = button_id
                     </script>
-                    <raise port="ui" event="bind_canvas_event">
-                        <parameter expr="self.canvas_id"/>
-                        <parameter expr="circle_id"/><!-- widget_id -->
-                        <parameter expr="ui.EVENTS.MOUSE_PRESS"/><!-- tk_event -->
-                        <parameter expr="'clicked'"/><!-- sccd_event_name -->
+                    <raise port="ui" event="bind_event">
+                        <parameter expr="button_id"/><!-- widget_id -->
+                        <parameter expr="ui.EVENTS.MOUSE_CLICK"/><!-- tk_event -->
+                        <parameter expr='"mouse_click"'/><!-- sccd_event_name -->
                         <parameter expr="self.inports['button_ui']"/><!-- inport for response -->
                     </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['button_ui']"/>
-                    </raise>
                 </transition>
             </state>
             <state id="running">
-                <transition port='button_ui' event="clicked" target='.' cond="button == ui.MOUSE_BUTTONS.LEFT">
+                <transition port='button_ui' event="mouse_click" target='.' cond="button == ui.MOUSE_BUTTONS.LEFT">
                     <parameter name="x" />
                     <parameter name="y" />
                     <parameter name="button" />
-                    <raise port="ui" event="set_element_color">
-                        <parameter expr="self.canvas_id"/>
-                        <parameter expr="self.button_id"/>
-                        <parameter expr="'#ff0'"/>
+                    <raise event="button_pressed" scope="narrow" target="'parent'">
+                        <parameter expr="self.number" />
                     </raise>
                 </transition>
             </state>
@@ -395,7 +325,7 @@
         <atrribute name="pos" />
         <inport name="elevator_ui"/>
         <relationships>
-            <association name="floors" class="Floors" min="1" max="1" />
+            <association name="floors" class="Floor" min="1" max="1" />
             <association name="parent" class="MainApp" min="1" max="1" />
         </relationships>
         <constructor>
@@ -404,13 +334,19 @@
                 <![CDATA[
                 self.canvas_id = canvas_id;
 
-                self.is_open = False;
+                height = CANVAS_DIMS[1] - 150
 
-                elevator_height = (CANVAS_DIMS[1] - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
+                elevator_height = (height - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
 
                 self.dim = {'x': elevator_height, 'y': elevator_height};
                 self.vel = -2;
-                self.pos = {'x': FLOOR_LENGTH + (elevator_height / 2), 'y': (CANVAS_DIMS[1] - (elevator_height / 2))};
+
+                self.current_floor = 0;
+
+                self.pos = {'x': FLOOR_LENGTH + (elevator_height / 2), 'y': (height - (elevator_height / 2))};
+                self.next_pos = {'x': FLOOR_LENGTH / 2, 'y': None};
+
+
                 self.smooth = 0.6; # value between 0 and 1
                 ]]>
             </body>
@@ -451,7 +387,25 @@
                 </state>
                 <state id="running" initial="idle">
                     <state id="idle">
-                        <transition after="5" target="../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 event="move_elevator" target="../move">
+                            <parameter name="floor_number" type="int"/>
+                            <script>
+                                if self.current_floor &lt; floor_number:
+                                    self.vel = -2
+                                else:
+                                    self.vel = 2
+                                
+                                height = (CANVAS_DIMS[1] - 150)
+                                y_dim = (height - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
+                                self.next_pos['y'] = height - (y_dim /2) - (floor_number * (y_dim + FLOOR_SPACE));
+                            </script>
                         </transition>
                     </state>
                     <state id="move">
@@ -473,7 +427,8 @@
                                 self.pos['y'] += self.vel
                             </script>
                         </transition>
-                        <transition target="../idle" cond="(self.pos['y'] - (self.dim['y']/2)) &lt; 0">
+                        <transition target="../idle" cond="(self.pos['y']) &lt; self.next_pos['y']">
+                            <raise scope="narrow" event="open_elevator" target="'parent'" />
                         </transition>
                     </state>
                 </state>
@@ -567,9 +522,9 @@
                                     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_height = ((CANVAS_DIMS[1] - 150) - ((FLOORS - 1) * FLOOR_SPACE)) / FLOORS
                                 floor_dim = {'x': FLOOR_LENGTH, 'y': floor_height};
-                                floor_pos = {'x': FLOOR_LENGTH / 2, 'y': CANVAS_DIMS[1] - (floor_height /2) - ( self.floor_num * (floor_height + FLOOR_SPACE)  )};
+                                floor_pos = {'x': FLOOR_LENGTH / 2, 'y': (CANVAS_DIMS[1] - 150) - (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
@@ -602,17 +557,12 @@
                             self.pos['y'] += self.vel['y']
                         </script>
                     </transition>
-                    <transition target="../ball_delete" cond="self.pos['x'] - self.r &lt; 2" />
-                    <transition port="ball_ui" event="mouse_press" target="../selected" cond="button == ui.MOUSE_BUTTONS.LEFT">
-                        <parameter name="x" />
-                        <parameter name="y" />
-                        <parameter name="button" />
-                        <raise port="ui" event="set_element_color">
-                            <parameter expr="self.canvas_id"/>
-                            <parameter expr="self.circle_id"/>
-                            <parameter expr="'#ff0'"/>
-                        </raise>
+                    <transition event="open_elevator" target=".">
+                        <script>
+                            self.elevator_open = True
+                        </script>
                     </transition>
+                    <transition target="../ball_delete" cond="self.pos['x'] - self.r &lt; 2" />
                     <transition event="update_bounds" target=".">
                         <parameter name="pos" type="dict" />
                         <parameter name="dim" type="dict" />
@@ -625,57 +575,6 @@
                         </script>
                     </transition>
                 </state>
-                <state id="dragging">
-                    <transition port="ball_ui" event="mouse_move" target=".">
-                        <parameter name="x" />
-                        <parameter name="y" />
-                        <parameter name="button" />
-                        <script>
-                            <![CDATA[
-                            # Always keep ball within canvas:
-                            x = min(max(0+self.r, x), CANVAS_DIMS[0]-self.r)
-                            y = min(max(0+self.r, y), CANVAS_DIMS[1]-self.r)
-
-                            dx = x - self.pos['x']
-                            dy = y - self.pos['y']
-
-                            self.vel = {
-                                'x': (1-self.smooth)*dx + self.smooth*self.vel['x'],
-                                'y': (1-self.smooth)*dy + self.smooth*self.vel['y']
-                            }
-
-                            self.pos = {'x': x, 'y': y}
-                            ]]>
-                        </script>
-                        <raise port="ui" event="set_element_pos">
-                            <parameter expr="self.canvas_id"/>
-                            <parameter expr="self.circle_id"/>
-                            <parameter expr="x-self.r"/>
-                            <parameter expr="y-self.r"/>
-                        </raise>
-                    </transition>
-                    <transition port="ball_ui" event="mouse_release" target="../bouncing">
-                        <parameter name="x" />
-                        <parameter name="y" />
-                        <raise port="ui" event="set_element_color">
-                            <parameter expr="self.canvas_id"/>
-                            <parameter expr="self.circle_id"/>
-                            <parameter expr="'#f00'"/>
-                        </raise>
-                    </transition>
-                </state>
-                <state id='selected'>
-                    <transition port="ball_ui" event="mouse_press" target="../dragging" cond="button == ui.MOUSE_BUTTONS.LEFT">
-                        <parameter name="x" />
-                        <parameter name="y" />
-                        <parameter name="button" />
-                        <script>
-                            <![CDATA[
-                            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="'floor'">

+ 59 - 22
sccd/runtime/DEVS_statecharts_core.py

@@ -730,8 +730,8 @@ class ObjectManagerBase(AtomicDEVS):
     # broadcast an event to all instances
     def broadcast(self, source, new_event, time_offset = 0):
         for i in self.instances:
-            if i != source:
-                i.addEvent(new_event, time_offset)
+            if self.instances[i] != source:
+                self.instances[i].addEvent(new_event, time_offset)
         
     def stepAll(self):
         self.step()
@@ -809,13 +809,6 @@ class ObjectManagerBase(AtomicDEVS):
 
     def outputEvent(self, event):
         self.to_send.append(event)
-        #self.to_send.append((self.name, None, event))
-
-
-
-        #for listener in self.output_listeners:
-        #    self.to_send.append((self.name, None, event))
-        #   listener.add(event)
 
     def processAssociationReference(self, input_string):
         if len(input_string) == 0:
@@ -994,7 +987,8 @@ class ObjectManagerBase(AtomicDEVS):
                 association = current["instance"].associations[name]
                 if (index >= 0 ):
                     try:
-                        check = association.instances[index]
+                        # TODO: check if this check works
+                        check = association.instances_to_ids[index]
                         nexts.append({
                             "to_class": association.to_class,
                             "instance": index,
@@ -1072,17 +1066,22 @@ class ObjectManagerBase(AtomicDEVS):
                         if not (assoc_name == "parent"):
                             traversal_list = self.processAssociationReference(assoc_name)
                             #instances = self.getInstances(i["instance"], traversal_list)
-                            #if len(instances) > 0:
-                            #    pass
+                            instances = self.getInstances(i, traversal_list)
+                            if len(instances) > 0:
+                                raise RuntimeException("Error removing instance from association %s, still %i children left connected with association %s" % (association_name, len(instances), assoc_name))
                     i.user_defined_destructor()
                     i.stop()
-                self.instances = {key: value for key, value in self.instances.items() if key not in input[2].parameters[1]}
 
                 #if not isinstance(input[2].parameters[1], list):
-                    
 
-                ev = Event("instance_deleted", None, [input[2].parameters[0]], input[2].instance)
+                self.instances = {key: value for key, value in self.instances.items() if key not in input[2].parameters[1]}
+                
+                    
+                ev = Event("instance_deleted", None, [input[2].parameters[0], input[2].parameters[1]], input[2].instance)
+                    #ev = Event("instance_deleted", None, input[2].parameters[1], input[2].instance)
+                #ev = Event("instance_deleted", None, [input[2].parameters[0]], input[2].instance)
                 self.to_send.append((input[1], input[0], ev))
+                
             elif input[2].name == "instance_created":
                 instance = self.instances[input[2].instance]
                 
@@ -1103,13 +1102,51 @@ class ObjectManagerBase(AtomicDEVS):
                 instance = self.instances[input[2].instance]
                 instance.addEvent(input[2])
             elif input[2].name == "instance_deleted":
-                instance = self.instances[input[2].instance]
-                for association in instance.associations.items():
-                    if association[1].to_class == input[0]:
-                        for assoc in input[2].parameters:
-                            index = self.processAssociationReference(assoc)[0][1]
-                            association[1].removeInstance(index)
-                instance.addEvent(input[2])
+                source = self.instances[input[2].instance]
+                association_name = input[2].parameters[0]
+
+                traversal_list = self.processAssociationReference(association_name)
+                instances = self.getInstances(source, traversal_list)
+                association = source.associations[traversal_list[0][0]]
+
+                for index, instance in enumerate(instances):
+                    try:
+                        #for assoc_name in i["instance"].associations:
+                        #    if assoc_name != 'parent':
+                        #        traversal_list = self.processAssociationReference(assoc_name)
+                        #        instances = self.getInstances(i["instance"], traversal_list)
+                        #        if len(instances) > 0:
+                        #            raise RuntimeException("Error removing instance from association %s, still %i children left connected with association %s" % (association_name, len(instances), assoc_name))
+                        #del i["instance"].controller.input_ports[i["instance"].narrow_cast_port]
+                        association.removeInstance(instance["instance"])
+                        #self.instances.discard(i["instance"])
+                        #self.eventless.discard(i["instance"])
+                        #instances.pop(index, None)
+                        #self.eventless.discard(i)
+                    except AssociationException as exception:
+                        raise RuntimeException("Error removing instance from association '" + association_name + "': " + str(exception))
+                
+                #instances = []
+                
+                source.addEvent(Event("instance_deleted", parameters = [input[2].parameters[1]]))
+
+
+
+                #instance = self.instances[input[2].instance]
+
+                #assoc_link = input[2].parameters[0]
+                #assoc_name, assoc_index = self.processAssociationReference(assoc_link)[0]
+
+                #associations = instance.associations[assoc_link]
+
+                #for association in instance.associations.items():
+                #    if association[1].to_class == input[0]:
+                #for index in input[2].parameters[1]:
+                #    associations.removeInstance(index)
+                            #index = self.processAssociationReference(assoc)[0][1]
+                    #association[1].removeInstance(index)
+                            #association[1].removeInstance(input[2].instance)
+                #instance.addEvent(input[2])
             else:
                 ev = input[2]
                 self.addInput(ev)

+ 29 - 9
tests/Test23/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:   Dissasociate an instance
+Model name:   Dissasociate multiple instances
 Model description:
-Test 12: Dissasociate an instance
+Test 23: Dissasociate multiple instances
 """
 
 from sccd.runtime.DEVS_statecharts_core import *
 
-# package "Dissasociate an instance"
+# package "Dissasociate multiple instances"
 
 class MainAppInstance(RuntimeClassBase):
     def __init__(self, atomdevs):
@@ -50,20 +50,25 @@ class MainAppInstance(RuntimeClassBase):
         
         # state /state2
         self.states["/state2"] = State(2, "/state2", self)
+        self.states["/state2"].setEnter(self._state2_enter)
         
         # state /state3
         self.states["/state3"] = State(3, "/state3", self)
-        self.states["/state3"].setEnter(self._state3_enter)
         
         # state /state4
         self.states["/state4"] = State(4, "/state4", self)
         self.states["/state4"].setEnter(self._state4_enter)
         
+        # state /state5
+        self.states["/state5"] = State(5, "/state5", self)
+        self.states["/state5"].setEnter(self._state5_enter)
+        
         # add children
         self.states[""].addChild(self.states["/state1"])
         self.states[""].addChild(self.states["/state2"])
         self.states[""].addChild(self.states["/state3"])
         self.states[""].addChild(self.states["/state4"])
+        self.states[""].addChild(self.states["/state5"])
         self.states[""].fixTree()
         self.states[""].default_state = self.states["/state1"]
         
@@ -76,22 +81,31 @@ class MainAppInstance(RuntimeClassBase):
         # transition /state2
         _state2_0 = Transition(self, self.states["/state2"], [self.states["/state3"]])
         _state2_0.setAction(self._state2_0_exec)
-        _state2_0.setTrigger(Event("instance_started", None))
+        _state2_0.setTrigger(Event("instance_created", None))
         self.states["/state2"].addTransition(_state2_0)
         
         # transition /state3
         _state3_0 = Transition(self, self.states["/state3"], [self.states["/state4"]])
         _state3_0.setAction(self._state3_0_exec)
-        _state3_0.setTrigger(Event("instance_disassociated", None))
+        _state3_0.setTrigger(Event("instance_started", None))
         self.states["/state3"].addTransition(_state3_0)
+        
+        # transition /state4
+        _state4_0 = Transition(self, self.states["/state4"], [self.states["/state5"]])
+        _state4_0.setAction(self._state4_0_exec)
+        _state4_0.setTrigger(Event("instance_disassociated", None))
+        self.states["/state4"].addTransition(_state4_0)
     
     def _state1_enter(self):
         self.big_step.outputEventOM(Event("create_instance", None, [self, "linkA", "A"]))
     
-    def _state3_enter(self):
-        self.big_step.outputEventOM(Event("disassociate_instance", None, [self, "linkA"]))
+    def _state2_enter(self):
+        self.big_step.outputEventOM(Event("create_instance", None, [self, "linkA", "A"]))
     
     def _state4_enter(self):
+        self.big_step.outputEventOM(Event("disassociate_instance", None, [self, "linkA"]))
+    
+    def _state5_enter(self):
         self.big_step.outputEventOM(Event("narrow_cast", None, [self, self.association_name, Event("sanity_check", None, [])]))
     
     def _state1_0_exec(self, parameters):
@@ -101,11 +115,17 @@ class MainAppInstance(RuntimeClassBase):
         self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
     
     def _state2_0_exec(self, parameters):
+        association_name = parameters[0]
+        self.association_name = association_name
+        self.big_step.outputEvent(Event("instance_created_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0)), association_name]))
+        self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
+    
+    def _state3_0_exec(self, parameters):
         association_name = parameters[0]
         self.big_step.outputEvent(Event("instance_started_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0)), association_name]))
         self.big_step.outputEventOM(Event("narrow_cast", None, [self, association_name, Event("link_check", None, [association_name])]))
     
-    def _state3_0_exec(self, parameters):
+    def _state4_0_exec(self, parameters):
         deleted_links = parameters[0]
         self.big_step.outputEvent(Event("instance_disassociated_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0)), deleted_links]))
     

+ 20 - 23
tests/Test23/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:   Dissasociate and associate an instance
+Model name:   Dissasociate multiple instances
 Model description:
-Test 13: Dissasociate an instance and then associate an instance again
+Test 23: Dissasociate multiple instances
 """
 
 from sccd.runtime.statecharts_core import *
 
-# package "Dissasociate and associate an instance"
+# package "Dissasociate multiple instances"
 
 class MainApp(RuntimeClassBase):
     def __init__(self, controller):
@@ -47,10 +47,10 @@ class MainApp(RuntimeClassBase):
         
         # state /state2
         self.states["/state2"] = State(2, "/state2", self)
+        self.states["/state2"].setEnter(self._state2_enter)
         
         # state /state3
         self.states["/state3"] = State(3, "/state3", self)
-        self.states["/state3"].setEnter(self._state3_enter)
         
         # state /state4
         self.states["/state4"] = State(4, "/state4", self)
@@ -58,6 +58,7 @@ class MainApp(RuntimeClassBase):
         
         # state /state5
         self.states["/state5"] = State(5, "/state5", self)
+        self.states["/state5"].setEnter(self._state5_enter)
         
         # add children
         self.states[""].addChild(self.states["/state1"])
@@ -77,34 +78,31 @@ class MainApp(RuntimeClassBase):
         # transition /state2
         _state2_0 = Transition(self, self.states["/state2"], [self.states["/state3"]])
         _state2_0.setAction(self._state2_0_exec)
-        _state2_0.setTrigger(Event("instance_started", None))
+        _state2_0.setTrigger(Event("instance_created", None))
         self.states["/state2"].addTransition(_state2_0)
         
         # transition /state3
         _state3_0 = Transition(self, self.states["/state3"], [self.states["/state4"]])
         _state3_0.setAction(self._state3_0_exec)
-        _state3_0.setTrigger(Event("instance_disassociated", None))
+        _state3_0.setTrigger(Event("instance_started", None))
         self.states["/state3"].addTransition(_state3_0)
         
         # transition /state4
         _state4_0 = Transition(self, self.states["/state4"], [self.states["/state5"]])
         _state4_0.setAction(self._state4_0_exec)
-        _state4_0.setTrigger(None)
+        _state4_0.setTrigger(Event("instance_disassociated", None))
         self.states["/state4"].addTransition(_state4_0)
-        
-        # transition /state5
-        _state5_0 = Transition(self, self.states["/state5"], [self.states["/state5"]])
-        _state5_0.setAction(self._state5_0_exec)
-        _state5_0.setTrigger(Event("instance_associated", None))
-        self.states["/state5"].addTransition(_state5_0)
     
     def _state1_enter(self):
         self.big_step.outputEventOM(Event("create_instance", None, [self, "linkA", "A"]))
     
-    def _state3_enter(self):
-        self.big_step.outputEventOM(Event("disassociate_instance", None, [self, "linkA"]))
+    def _state2_enter(self):
+        self.big_step.outputEventOM(Event("create_instance", None, [self, "linkA", "A"]))
     
     def _state4_enter(self):
+        self.big_step.outputEventOM(Event("disassociate_instance", None, [self, "linkA"]))
+    
+    def _state5_enter(self):
         self.big_step.outputEventOM(Event("narrow_cast", None, [self, self.association_name, Event("sanity_check", None, [])]))
     
     def _state1_0_exec(self, parameters):
@@ -114,21 +112,20 @@ class MainApp(RuntimeClassBase):
         self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
     
     def _state2_0_exec(self, parameters):
+        association_name = parameters[0]
+        self.association_name = association_name
+        self.big_step.outputEvent(Event("instance_created_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0)), association_name]))
+        self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
+    
+    def _state3_0_exec(self, parameters):
         association_name = parameters[0]
         self.big_step.outputEvent(Event("instance_started_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0)), association_name]))
         self.big_step.outputEventOM(Event("narrow_cast", None, [self, association_name, Event("link_check", None, [association_name])]))
     
-    def _state3_0_exec(self, parameters):
+    def _state4_0_exec(self, parameters):
         deleted_links = parameters[0]
         self.big_step.outputEvent(Event("instance_disassociated_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0)), deleted_links]))
     
-    def _state4_0_exec(self, parameters):
-        self.big_step.outputEventOM(Event("associate_instance", None, [self, self.association_name, "linkA"]))
-    
-    def _state5_0_exec(self, parameters):
-        created_links = parameters[0]
-        self.big_step.outputEventOM(Event("narrow_cast", None, [self, created_links, Event("sanity_check", None, [])]))
-    
     def initializeStatechart(self):
         # enter default state
         self.default_targets = self.states["/state1"].getEffectiveTargetStates()

+ 27 - 20
tests/Test23/sccd.xml

@@ -1,8 +1,7 @@
 <?xml version="1.1" ?>
-<diagram author="Sam Pieters" name="Dissasociate and associate an instance">
+<diagram author="Sam Pieters" name="Dissasociate multiple instances">
     <description>
-        TODO: Does not work as I think it does
-        Test 13: Dissasociate an instance and then associate an instance again
+        Test 23: Dissasociate multiple instances
     </description>
     <inport name="ui"/>
     <outport name="ui"/>
@@ -38,7 +37,28 @@
                 </transition>
             </state>
             <state id="state2">
-                <transition event='instance_started' target='../state3'>
+                <onentry>
+                    <raise scope="cd" event="create_instance">
+                        <parameter expr='"linkA"' />
+                        <parameter expr='"A"' />
+                    </raise>
+                </onentry>
+                <transition event='instance_created' target='../state3'>
+                    <parameter name="association_name" type="string"/>
+                    <script>
+                        self.association_name = association_name
+                    </script>
+                    <raise port="ui" event="instance_created_succesfully">
+                        <parameter expr="str('%.2f' % (self.getSimulatedTime() / 1000.0))" />
+                        <parameter expr="association_name" />
+                    </raise>
+                    <raise scope="cd" event="start_instance">
+                        <parameter expr="association_name" />
+                    </raise>
+                </transition>
+            </state>
+            <state id="state3">
+                <transition event='instance_started' target='../state4'>
                     <parameter name="association_name" type="string"/>
                     <raise port="ui" event="instance_started_succesfully">
                         <parameter expr="str('%.2f' % (self.getSimulatedTime() / 1000.0))" />
@@ -49,13 +69,13 @@
                     </raise>
                 </transition>
             </state>
-            <state id="state3">
+            <state id="state4">
                 <onentry>
                     <raise scope="cd" event='disassociate_instance'>
                         <parameter expr='"linkA"' />
                     </raise>
                 </onentry>
-                <transition event='instance_disassociated' target='../state4'>
+                <transition event='instance_disassociated' target='../state5'>
                     <parameter name='deleted_links' />
                     <raise port="ui" event="instance_disassociated_succesfully">
                         <parameter expr="str('%.2f' % (self.getSimulatedTime() / 1000.0))" />
@@ -63,23 +83,10 @@
                     </raise>
                 </transition>
             </state>
-            <state id="state4">
+            <state id="state5">
                 <onentry>
                     <raise scope="narrow" event="sanity_check" target="self.association_name" />
                 </onentry>
-                <transition target='../state5'>
-                    <raise scope="cd" event='associate_instance'>
-                        <parameter expr='self.association_name' />
-                        <parameter expr='"linkA"' />
-                    </raise>
-                </transition>
-            </state>
-            <state id="state5">
-                <transition event='instance_associated' target='.'>
-                    <parameter name='created_links' />
-                    <raise scope="narrow" event="sanity_check" target="created_links" />
-                </transition>
-
             </state>
         </scxml>
     </class>

+ 4 - 0
tests/Test29/PyDEVS/log.txt

@@ -0,0 +1,4 @@
+0.00s - Debugger warning: It seems that frozen modules are being used, which may
+0.00s - make the debugger miss breakpoints. Please pass -Xfrozen_modules=off
+0.00s - to python to disable frozen modules.
+0.00s - Note: Debugging will proceed. Set PYDEVD_DISABLE_FILE_VALIDATION=1 to disable this validation.

+ 20 - 0
tests/Test29/PyDEVS/runner.py

@@ -0,0 +1,20 @@
+import target as target
+from sccd.runtime.DEVS_loop import DEVSSimulator
+from sccd.runtime.statecharts_core import Event
+
+class OutputListener:
+	def add(self, events):
+		for event in events:
+			if event.port == "ui":
+				print(event.name, ", received on:", event.parameters[0], "seconds, parameters:", event.parameters[1:])
+				
+
+if __name__ == '__main__':
+	controller = target.Controller(name="controller")
+	refs = {"ui": controller.in_ui}
+	sim = DEVSSimulator(controller, refs)
+
+	listener = OutputListener()
+	sim.setListenPorts(controller.out_ui, listener.add)
+	sim.simulate()
+

+ 243 - 0
tests/Test29/PyDEVS/target.py

@@ -0,0 +1,243 @@
+"""
+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:   Dissasociate an instance
+Model description:
+Test 12: Dissasociate an instance
+"""
+
+from sccd.runtime.DEVS_statecharts_core import *
+
+# package "Dissasociate an instance"
+
+class MainAppInstance(RuntimeClassBase):
+    def __init__(self, atomdevs):
+        RuntimeClassBase.__init__(self, atomdevs)
+        self.associations = {}
+        self.associations["linkA"] = Association("A", 0, -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
+        MainAppInstance.user_defined_constructor(self)
+        port_name = Ports.addInputPort("<narrow_cast>", self)
+        atomdevs.addInPort(port_name)
+    
+    def user_defined_constructor(self):
+        self.association_name = None
+    
+    def user_defined_destructor(self):
+        pass
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, "", self)
+        
+        # state /state1
+        self.states["/state1"] = State(1, "/state1", self)
+        self.states["/state1"].setEnter(self._state1_enter)
+        
+        # state /state2
+        self.states["/state2"] = State(2, "/state2", self)
+        
+        # state /state3
+        self.states["/state3"] = State(3, "/state3", self)
+        self.states["/state3"].setEnter(self._state3_enter)
+        
+        # state /state4
+        self.states["/state4"] = State(4, "/state4", self)
+        self.states["/state4"].setEnter(self._state4_enter)
+        
+        # add children
+        self.states[""].addChild(self.states["/state1"])
+        self.states[""].addChild(self.states["/state2"])
+        self.states[""].addChild(self.states["/state3"])
+        self.states[""].addChild(self.states["/state4"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/state1"]
+        
+        # transition /state1
+        _state1_0 = Transition(self, self.states["/state1"], [self.states["/state2"]])
+        _state1_0.setAction(self._state1_0_exec)
+        _state1_0.setTrigger(Event("instance_created", None))
+        self.states["/state1"].addTransition(_state1_0)
+        
+        # transition /state2
+        _state2_0 = Transition(self, self.states["/state2"], [self.states["/state3"]])
+        _state2_0.setAction(self._state2_0_exec)
+        _state2_0.setTrigger(Event("instance_started", None))
+        self.states["/state2"].addTransition(_state2_0)
+        
+        # transition /state3
+        _state3_0 = Transition(self, self.states["/state3"], [self.states["/state4"]])
+        _state3_0.setAction(self._state3_0_exec)
+        _state3_0.setTrigger(Event("instance_disassociated", None))
+        self.states["/state3"].addTransition(_state3_0)
+    
+    def _state1_enter(self):
+        self.big_step.outputEventOM(Event("create_instance", None, [self, "linkA", "A"]))
+    
+    def _state3_enter(self):
+        self.big_step.outputEventOM(Event("disassociate_instance", None, [self, "linkA"]))
+    
+    def _state4_enter(self):
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, self.association_name, Event("sanity_check", None, [])]))
+    
+    def _state1_0_exec(self, parameters):
+        association_name = parameters[0]
+        self.association_name = association_name
+        self.big_step.outputEvent(Event("instance_created_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0)), association_name]))
+        self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
+    
+    def _state2_0_exec(self, parameters):
+        association_name = parameters[0]
+        self.big_step.outputEvent(Event("instance_started_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0)), association_name]))
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, association_name, Event("link_check", None, [association_name])]))
+    
+    def _state3_0_exec(self, parameters):
+        deleted_links = parameters[0]
+        self.big_step.outputEvent(Event("instance_disassociated_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0)), deleted_links]))
+    
+    def initializeStatechart(self):
+        # enter default state
+        self.default_targets = self.states["/state1"].getEffectiveTargetStates()
+        RuntimeClassBase.initializeStatechart(self)
+
+class MainApp(ObjectManagerBase):
+    def __init__(self, name):
+        ObjectManagerBase.__init__(self, name)
+        self.input = self.addInPort("input")
+        self.output = self.addOutPort("ui")
+        self.outputs["linkA"] = self.addOutPort("linkA")
+        self.instances[self.next_instance] = MainAppInstance(self)
+        self.next_instance = self.next_instance + 1
+    
+    def constructObject(self, parameters):
+        new_instance = MainAppInstance(self)
+        return new_instance
+
+class AInstance(RuntimeClassBase):
+    def __init__(self, atomdevs):
+        RuntimeClassBase.__init__(self, atomdevs)
+        self.associations = {}
+        
+        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
+        AInstance.user_defined_constructor(self)
+        port_name = Ports.addInputPort("<narrow_cast>", self)
+        atomdevs.addInPort(port_name)
+    
+    def user_defined_constructor(self):
+        pass
+    
+    def user_defined_destructor(self):
+        pass
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, "", self)
+        
+        # state /state1
+        self.states["/state1"] = State(1, "/state1", self)
+        self.states["/state1"].setEnter(self._state1_enter)
+        
+        # state /state2
+        self.states["/state2"] = State(2, "/state2", self)
+        
+        # add children
+        self.states[""].addChild(self.states["/state1"])
+        self.states[""].addChild(self.states["/state2"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/state1"]
+        
+        # transition /state1
+        _state1_0 = Transition(self, self.states["/state1"], [self.states["/state2"]])
+        _state1_0.setTrigger(None)
+        self.states["/state1"].addTransition(_state1_0)
+        
+        # transition /state2
+        _state2_0 = Transition(self, self.states["/state2"], [self.states["/state2"]])
+        _state2_0.setAction(self._state2_0_exec)
+        _state2_0.setTrigger(Event("link_check", None))
+        self.states["/state2"].addTransition(_state2_0)
+        _state2_1 = Transition(self, self.states["/state2"], [self.states["/state2"]])
+        _state2_1.setAction(self._state2_1_exec)
+        _state2_1.setTrigger(Event("sanity_check", None))
+        self.states["/state2"].addTransition(_state2_1)
+    
+    def _state1_enter(self):
+        self.big_step.outputEvent(Event("statechart_started_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0))]))
+    
+    def _state2_0_exec(self, parameters):
+        link_name = parameters[0]
+        self.big_step.outputEvent(Event("instance_linked_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0)), link_name]))
+    
+    def _state2_1_exec(self, parameters):
+        self.big_step.outputEvent(Event("not_possible", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0))]))
+    
+    def initializeStatechart(self):
+        # enter default state
+        self.default_targets = self.states["/state1"].getEffectiveTargetStates()
+        RuntimeClassBase.initializeStatechart(self)
+
+class A(ObjectManagerBase):
+    def __init__(self, name):
+        ObjectManagerBase.__init__(self, name)
+        self.input = self.addInPort("input")
+        self.output = self.addOutPort("ui")
+    
+    def constructObject(self, parameters):
+        new_instance = AInstance(self)
+        return new_instance
+
+class ObjectManagerState:
+    def __init__(self):
+        self.to_send = [("MainApp", "MainApp", Event("start_instance", None, ["MainApp[0]"], 0))]
+
+class ObjectManager(TheObjectManager):
+    def __init__(self, name):
+        TheObjectManager.__init__(self, name)
+        self.State = ObjectManagerState()
+        self.input = self.addInPort("input")
+        self.output["MainApp"] = self.addOutPort()
+        self.output["A"] = self.addOutPort()
+
+class Controller(CoupledDEVS):
+    def __init__(self, name):
+        CoupledDEVS.__init__(self, name)
+        self.in_ui = self.addInPort("ui")
+        Ports.addInputPort("ui")
+        self.out_ui = self.addOutPort("ui")
+        Ports.addOutputPort("ui")
+        self.objectmanager = self.addSubModel(ObjectManager("ObjectManager"))
+        self.atomic0 = self.addSubModel(MainApp("MainApp"))
+        self.atomic1 = self.addSubModel(A("A"))
+        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["linkA"], self.atomic1.input)
+        self.connectPorts(self.atomic1.obj_manager_out, self.objectmanager.input)
+        self.connectPorts(self.objectmanager.output["A"], self.atomic1.obj_manager_in)
+        self.connectPorts(self.atomic0.output, self.out_ui)
+        self.connectPorts(self.atomic1.output, self.out_ui)

+ 8 - 0
tests/Test29/Python/log.txt

@@ -0,0 +1,8 @@
+instance_created_succesfully , received on: 0.00 seconds, parameters: ['linkA[0]']
+statechart_started_succesfully , received on: 0.00 seconds, parameters: []
+constructor_initialized_succesfully , received on: 0.00 seconds, parameters: []
+instance_started_succesfully , received on: 0.00 seconds, parameters: ['linkA[0]']
+0.00s - Debugger warning: It seems that frozen modules are being used, which may
+0.00s - make the debugger miss breakpoints. Please pass -Xfrozen_modules=off
+0.00s - to python to disable frozen modules.
+0.00s - Note: Debugging will proceed. Set PYDEVD_DISABLE_FILE_VALIDATION=1 to disable this validation.

+ 16 - 0
tests/Test29/Python/runner.py

@@ -0,0 +1,16 @@
+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.addMyOwnOutputListener(OutputListener())
+	controller.setVerbose(None)
+	controller.start()

+ 233 - 0
tests/Test29/Python/target.py

@@ -0,0 +1,233 @@
+"""
+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:   Dissasociate and associate an instance
+Model description:
+Test 13: Dissasociate an instance and then associate an instance again
+"""
+
+from sccd.runtime.statecharts_core import *
+
+# package "Dissasociate and associate an instance"
+
+class MainApp(RuntimeClassBase):
+    def __init__(self, controller):
+        RuntimeClassBase.__init__(self, controller)
+        
+        
+        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
+        MainApp.user_defined_constructor(self)
+    
+    def user_defined_constructor(self):
+        self.association_name = None
+    
+    def user_defined_destructor(self):
+        pass
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, "", self)
+        
+        # state /state1
+        self.states["/state1"] = State(1, "/state1", self)
+        self.states["/state1"].setEnter(self._state1_enter)
+        
+        # state /state2
+        self.states["/state2"] = State(2, "/state2", self)
+        
+        # state /state3
+        self.states["/state3"] = State(3, "/state3", self)
+        self.states["/state3"].setEnter(self._state3_enter)
+        
+        # state /state4
+        self.states["/state4"] = State(4, "/state4", self)
+        self.states["/state4"].setEnter(self._state4_enter)
+        
+        # state /state5
+        self.states["/state5"] = State(5, "/state5", self)
+        
+        # add children
+        self.states[""].addChild(self.states["/state1"])
+        self.states[""].addChild(self.states["/state2"])
+        self.states[""].addChild(self.states["/state3"])
+        self.states[""].addChild(self.states["/state4"])
+        self.states[""].addChild(self.states["/state5"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/state1"]
+        
+        # transition /state1
+        _state1_0 = Transition(self, self.states["/state1"], [self.states["/state2"]])
+        _state1_0.setAction(self._state1_0_exec)
+        _state1_0.setTrigger(Event("instance_created", None))
+        self.states["/state1"].addTransition(_state1_0)
+        
+        # transition /state2
+        _state2_0 = Transition(self, self.states["/state2"], [self.states["/state3"]])
+        _state2_0.setAction(self._state2_0_exec)
+        _state2_0.setTrigger(Event("instance_started", None))
+        self.states["/state2"].addTransition(_state2_0)
+        
+        # transition /state3
+        _state3_0 = Transition(self, self.states["/state3"], [self.states["/state4"]])
+        _state3_0.setAction(self._state3_0_exec)
+        _state3_0.setTrigger(Event("instance_disassociated", None))
+        self.states["/state3"].addTransition(_state3_0)
+        
+        # transition /state4
+        _state4_0 = Transition(self, self.states["/state4"], [self.states["/state5"]])
+        _state4_0.setAction(self._state4_0_exec)
+        _state4_0.setTrigger(None)
+        self.states["/state4"].addTransition(_state4_0)
+        
+        # transition /state5
+        _state5_0 = Transition(self, self.states["/state5"], [self.states["/state5"]])
+        _state5_0.setAction(self._state5_0_exec)
+        _state5_0.setTrigger(Event("instance_associated", None))
+        self.states["/state5"].addTransition(_state5_0)
+    
+    def _state1_enter(self):
+        self.big_step.outputEventOM(Event("create_instance", None, [self, "linkA", "A"]))
+    
+    def _state3_enter(self):
+        self.big_step.outputEventOM(Event("disassociate_instance", None, [self, "linkA"]))
+    
+    def _state4_enter(self):
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, self.association_name, Event("sanity_check", None, [])]))
+    
+    def _state1_0_exec(self, parameters):
+        association_name = parameters[0]
+        self.association_name = association_name
+        self.big_step.outputEvent(Event("instance_created_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0)), association_name]))
+        self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
+    
+    def _state2_0_exec(self, parameters):
+        association_name = parameters[0]
+        self.big_step.outputEvent(Event("instance_started_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0)), association_name]))
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, association_name, Event("link_check", None, [association_name])]))
+    
+    def _state3_0_exec(self, parameters):
+        deleted_links = parameters[0]
+        self.big_step.outputEvent(Event("instance_disassociated_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0)), deleted_links]))
+    
+    def _state4_0_exec(self, parameters):
+        self.big_step.outputEventOM(Event("associate_instance", None, [self, self.association_name, "linkA"]))
+    
+    def _state5_0_exec(self, parameters):
+        created_links = parameters[0]
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, created_links, Event("sanity_check", None, [])]))
+    
+    def initializeStatechart(self):
+        # enter default state
+        self.default_targets = self.states["/state1"].getEffectiveTargetStates()
+        RuntimeClassBase.initializeStatechart(self)
+
+class A(RuntimeClassBase):
+    def __init__(self, controller):
+        RuntimeClassBase.__init__(self, controller)
+        
+        
+        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
+        A.user_defined_constructor(self)
+    
+    def user_defined_constructor(self):
+        pass
+    
+    def user_defined_destructor(self):
+        pass
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, "", self)
+        
+        # state /state1
+        self.states["/state1"] = State(1, "/state1", self)
+        self.states["/state1"].setEnter(self._state1_enter)
+        
+        # state /state2
+        self.states["/state2"] = State(2, "/state2", self)
+        
+        # add children
+        self.states[""].addChild(self.states["/state1"])
+        self.states[""].addChild(self.states["/state2"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/state1"]
+        
+        # transition /state1
+        _state1_0 = Transition(self, self.states["/state1"], [self.states["/state2"]])
+        _state1_0.setTrigger(None)
+        self.states["/state1"].addTransition(_state1_0)
+        
+        # transition /state2
+        _state2_0 = Transition(self, self.states["/state2"], [self.states["/state2"]])
+        _state2_0.setAction(self._state2_0_exec)
+        _state2_0.setTrigger(Event("link_check", None))
+        self.states["/state2"].addTransition(_state2_0)
+        _state2_1 = Transition(self, self.states["/state2"], [self.states["/state2"]])
+        _state2_1.setAction(self._state2_1_exec)
+        _state2_1.setTrigger(Event("sanity_check", None))
+        self.states["/state2"].addTransition(_state2_1)
+    
+    def _state1_enter(self):
+        self.big_step.outputEvent(Event("statechart_started_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0))]))
+    
+    def _state2_0_exec(self, parameters):
+        link_name = parameters[0]
+        self.big_step.outputEvent(Event("instance_linked_succesfully", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0)), link_name]))
+    
+    def _state2_1_exec(self, parameters):
+        self.big_step.outputEvent(Event("not_possible", self.getOutPortName("ui"), [str('%.2f' % (self.getSimulatedTime() / 1000.0))]))
+    
+    def initializeStatechart(self):
+        # enter default state
+        self.default_targets = self.states["/state1"].getEffectiveTargetStates()
+        RuntimeClassBase.initializeStatechart(self)
+
+class ObjectManager(ObjectManagerBase):
+    def __init__(self, controller):
+        ObjectManagerBase.__init__(self, controller)
+    
+    def instantiate(self, class_name, construct_params):
+        if class_name == "MainApp":
+            instance = MainApp(self.controller)
+            instance.associations = {}
+            instance.associations["linkA"] = Association("A", 0, -1)
+        elif class_name == "A":
+            instance = A(self.controller)
+            instance.associations = {}
+        else:
+            raise Exception("Cannot instantiate class " + class_name)
+        return instance
+
+class Controller(ThreadsControllerBase):
+    def __init__(self, keep_running = None, behind_schedule_callback = None):
+        if keep_running == None: keep_running = True
+        if behind_schedule_callback == None: behind_schedule_callback = None
+        ThreadsControllerBase.__init__(self, ObjectManager(self), keep_running, behind_schedule_callback)
+        self.addInputPort("ui")
+        self.addOutputPort("ui")
+        self.object_manager.createInstance("MainApp", [])

+ 113 - 0
tests/Test29/sccd.xml

@@ -0,0 +1,113 @@
+<?xml version="1.1" ?>
+<diagram author="Sam Pieters" name="Dissasociate and associate an instance">
+    <description>
+        TODO: Does not work as I think it does
+        Test 13: Dissasociate an instance and then associate an instance again
+    </description>
+    <inport name="ui"/>
+    <outport name="ui"/>
+    <class name="MainApp" default="true">
+        <relationships>
+            <association name="linkA" class="A" />
+        </relationships>
+        <constructor>
+            <body>
+                self.association_name = None
+            </body>
+        </constructor>
+        <scxml initial="state1">
+            <state id="state1">
+                <onentry>
+                    <raise scope="cd" event="create_instance">
+                        <parameter expr='"linkA"' />
+                        <parameter expr='"A"' />
+                    </raise>
+                </onentry>
+                <transition event='instance_created' target='../state2'>
+                    <parameter name="association_name" type="string"/>
+                    <script>
+                        self.association_name = association_name
+                    </script>
+                    <raise port="ui" event="instance_created_succesfully">
+                        <parameter expr="str('%.2f' % (self.getSimulatedTime() / 1000.0))" />
+                        <parameter expr="association_name" />
+                    </raise>
+                    <raise scope="cd" event="start_instance">
+                        <parameter expr="association_name" />
+                    </raise>
+                </transition>
+            </state>
+            <state id="state2">
+                <transition event='instance_started' target='../state3'>
+                    <parameter name="association_name" type="string"/>
+                    <raise port="ui" event="instance_started_succesfully">
+                        <parameter expr="str('%.2f' % (self.getSimulatedTime() / 1000.0))" />
+                        <parameter expr="association_name" />
+                    </raise>
+                    <raise scope="narrow" event="link_check" target="association_name">
+                        <parameter expr="association_name" />
+                    </raise>
+                </transition>
+            </state>
+            <state id="state3">
+                <onentry>
+                    <raise scope="cd" event='disassociate_instance'>
+                        <parameter expr='"linkA"' />
+                    </raise>
+                </onentry>
+                <transition event='instance_disassociated' target='../state4'>
+                    <parameter name='deleted_links' />
+                    <raise port="ui" event="instance_disassociated_succesfully">
+                        <parameter expr="str('%.2f' % (self.getSimulatedTime() / 1000.0))" />
+                        <parameter expr="deleted_links" />
+                    </raise>
+                </transition>
+            </state>
+            <state id="state4">
+                <onentry>
+                    <raise scope="narrow" event="sanity_check" target="self.association_name" />
+                </onentry>
+                <transition target='../state5'>
+                    <raise scope="cd" event='associate_instance'>
+                        <parameter expr='self.association_name' />
+                        <parameter expr='"linkA"' />
+                    </raise>
+                </transition>
+            </state>
+            <state id="state5">
+                <transition event='instance_associated' target='.'>
+                    <parameter name='created_links' />
+                    <raise scope="narrow" event="sanity_check" target="created_links" />
+                </transition>
+
+            </state>
+        </scxml>
+    </class>
+
+    <class name="A">
+        <scxml initial="state1">
+            <state id="state1">
+                <onentry>
+                    <raise port="ui" event="statechart_started_succesfully">
+                        <parameter expr="str('%.2f' % (self.getSimulatedTime() / 1000.0))" />
+                    </raise>
+                </onentry>
+                <transition target="../state2" />
+            </state>
+            <state id="state2">
+                <transition event="link_check" target=".">
+                    <parameter name='link_name' />
+                    <raise port="ui" event="instance_linked_succesfully">
+                        <parameter expr="str('%.2f' % (self.getSimulatedTime() / 1000.0))" />
+                        <parameter expr="link_name" />
+                    </raise>
+                </transition>
+                <transition event="sanity_check" target=".">
+                    <raise port="ui" event="not_possible">
+                        <parameter expr="str('%.2f' % (self.getSimulatedTime() / 1000.0))" />
+                    </raise>
+                </transition>
+            </state>
+        </scxml>
+    </class>
+</diagram>