Sfoglia il codice sorgente

Added more to the paper + fixed one of the last issues of deleting an instance + the new fixed timer works without buttons

sampieters 1 anno fa
parent
commit
5b7505c3ca

+ 28 - 71
examples/BouncingBalls/PyDEVS/bestbest_target.py

@@ -610,7 +610,11 @@ class Field(AtomicDEVS, ObjectManagerBase):
                 instance.addEvent(input[2])
             elif input[2].name == "instance_deleted":
                 instance = self.instances[input[2].instance]
-                instance.addEvent(input[2])
+                for assoc in instance.associations.items():
+                    if assoc[1].to_class == input[0]:
+                        for index in input[2].parameters:
+                            assoc[1].removeInstance(index)
+                        break
             elif input[2].name == "instance_associated":
                 pass
             elif input[2].name == "instance_disassociated":
@@ -783,64 +787,13 @@ class Button(AtomicDEVS, ObjectManagerBase):
                     p.addInstance(input[2].instance)
                 ev = Event("instance_created", None, [f"{input[2].parameters[0]}[{len(self.instances)-1}]"], input[2].instance)
                 self.to_send.append((input[1], input[0], ev))
-
             elif input[2].name == "start_instance":
                 instance = self.instances[input[2].instance]
                 instance.start()
                 ev = Event("instance_started", None, [f"{input[0]}[{len(self.instances)-1}]"], input[2].instance)
                 self.to_send.append((input[0], input[1], ev))
             elif input[2].name == "delete_instance":
-                instances = self.instances
-                for i in instances:
-                    try:
-                        for assoc_name in i.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(i["instance"])
-                                self.instances.discard(i["instance"])
-                                self.eventless.discard(i["instance"])
-                    except AssociationException as exception:
-                        raise RuntimeException("Error removing instance from association '" + association_name + "': " + str(exception))
-                    i.user_defined_destructor()
-                    i.stop()
-                
-                ev = Event("instance_deleted", None, [input[0]])
-                self.to_send.append((input[1], input[0], ev))
-            #source.addEvent(Event("instance_deleted", parameters = [parameters[1]]))
-
-
-
-
-
-
-
-
-
-
-                #instance = self.instances[input[2].instance]
-                #try:
-                #    for assoc_name in 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" % (assoc_name, len(instances), assoc_name))
-                    #del i["instance"].controller.input_ports[i["instance"].narrow_cast_port]
-                    #association.removeInstance(instance)
-                #    self.instances.remove(instance)
-                #    self.eventless.discard(instance)
-                #except AssociationException as exception:
-                #    raise RuntimeException("Error removing instance from association '" + assoc_name + "': " + str(exception))
-                #instance.user_defined_destructor()
-                #instance.stop()
-
-                #ev = Event("instance_deleted", None, [input[0]])
-                #self.to_send.append((input[1], input[0], ev))
-
+                pass
             elif input[2].name == "associate_instance":
                 pass
             elif input[2].name == "disassociate_instance":
@@ -1158,24 +1111,28 @@ class Ball(AtomicDEVS, ObjectManagerBase):
                 ev = Event("instance_started", None, [f"{input[0]}[{len(self.instances)-1}]"], input[2].instance)
                 self.to_send.append((input[0], input[1], ev))
             elif input[2].name == "delete_instance":
-                instance = self.instances[input[2].instance]
-                try:
-                    for assoc_name in 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" % (assoc_name, len(instances), assoc_name))
-                    #del i["instance"].controller.input_ports[i["instance"].narrow_cast_port]
-                    #association.removeInstance(instance)
-                    self.instances.remove(instance)
-                    self.eventless.discard(instance)
-                except AssociationException as exception:
-                    raise RuntimeException("Error removing instance from association '" + assoc_name + "': " + str(exception))
-                instance.user_defined_destructor()
-                instance.stop()
-                ev = Event("instance_deleted", None, parameters = [input[0]])
-                self.to_send.append((input[0], input[1], ev))
+                for index in input[2].parameters[1]:
+                    i = self.instances[index]
+                    try:
+                        for assoc_name in i.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))
+                        # TODO: These still do need to be implemented
+                        #association.removeInstance(i["instance"])
+                        #self.eventless.discard(i["instance"])
+                    except AssociationException as exception:
+                        raise RuntimeException("Error removing instance from association '" + association_name + "': " + str(exception))
+                    i.user_defined_destructor()
+                    i.stop()
+                self.instances = [self.instances[i] for i in range(len(self.instances)) if i not in input[2].parameters[1]]
+                #source.addEvent(Event("instance_deleted", parameters = [parameters[1]]))
+
+                ev = Event("instance_deleted", None, input[2].parameters[1], input[2].instance)
+                self.to_send.append((input[1], input[0], ev))
+
             elif input[2].name == "associate_instance":
                 pass
             elif input[2].name == "disassociate_instance":

+ 67 - 52
examples/BouncingBalls/PyDEVS/target.py

@@ -238,11 +238,19 @@ class MainApp(AtomicDEVS, ObjectManagerBase):
                 ev = Event("instance_started", None, [f"{input[0]}[{len(self.instances)-1}]"], input[2].instance)
                 self.to_send.append((input[0], input[1], ev))
             elif input[2].name == "delete_instance":
-                pass
-            elif input[2].name == "associate_instance":
-                pass
-            elif input[2].name == "disassociate_instance":
-                pass
+                for index in input[2].parameters[1]:
+                    i = self.instances[index]
+                    for assoc_name in i.associations:
+                        if not (assoc_name == "parent"):
+                            traversal_list = self.processAssociationReference(assoc_name)
+                            instances = self.getInstances(i["instance"], traversal_list)
+                            if len(instances) > 0:
+                                pass
+                    i.user_defined_destructor()
+                    i.stop()
+                self.instances = [self.instances[i] for i in range(len(self.instances)) if i not in input[2].parameters[1]]
+                ev = Event("instance_deleted", None, input[2].parameters[1], input[2].instance)
+                self.to_send.append((input[1], input[0], ev))
             elif input[2].name == "instance_created":
                 instance = self.instances[input[2].instance]
                 instance.addEvent(input[2])
@@ -250,11 +258,11 @@ class MainApp(AtomicDEVS, ObjectManagerBase):
                 instance = self.instances[input[2].instance]
                 instance.addEvent(input[2])
             elif input[2].name == "instance_deleted":
-                pass
-            elif input[2].name == "instance_associated":
-                pass
-            elif input[2].name == "instance_disassociated":
-                pass
+                instance = self.instances[input[2].instance]
+                for association in instance.associations.items():
+                    if association[1].to_class == input[0]:
+                        for index in input[2].parameters:
+                            association[1].removeInstance(index)
             else:
                 ev = input[2]
                 self.addInput(ev)
@@ -597,11 +605,19 @@ class Field(AtomicDEVS, ObjectManagerBase):
                 ev = Event("instance_started", None, [f"{input[0]}[{len(self.instances)-1}]"], input[2].instance)
                 self.to_send.append((input[0], input[1], ev))
             elif input[2].name == "delete_instance":
-                pass
-            elif input[2].name == "associate_instance":
-                pass
-            elif input[2].name == "disassociate_instance":
-                pass
+                for index in input[2].parameters[1]:
+                    i = self.instances[index]
+                    for assoc_name in i.associations:
+                        if not (assoc_name == "parent"):
+                            traversal_list = self.processAssociationReference(assoc_name)
+                            instances = self.getInstances(i["instance"], traversal_list)
+                            if len(instances) > 0:
+                                pass
+                    i.user_defined_destructor()
+                    i.stop()
+                self.instances = [self.instances[i] for i in range(len(self.instances)) if i not in input[2].parameters[1]]
+                ev = Event("instance_deleted", None, input[2].parameters[1], input[2].instance)
+                self.to_send.append((input[1], input[0], ev))
             elif input[2].name == "instance_created":
                 instance = self.instances[input[2].instance]
                 instance.addEvent(input[2])
@@ -609,11 +625,11 @@ class Field(AtomicDEVS, ObjectManagerBase):
                 instance = self.instances[input[2].instance]
                 instance.addEvent(input[2])
             elif input[2].name == "instance_deleted":
-                pass
-            elif input[2].name == "instance_associated":
-                pass
-            elif input[2].name == "instance_disassociated":
-                pass
+                instance = self.instances[input[2].instance]
+                for association in instance.associations.items():
+                    if association[1].to_class == input[0]:
+                        for index in input[2].parameters:
+                            association[1].removeInstance(index)
             else:
                 ev = input[2]
                 self.addInput(ev)
@@ -788,11 +804,19 @@ class Button(AtomicDEVS, ObjectManagerBase):
                 ev = Event("instance_started", None, [f"{input[0]}[{len(self.instances)-1}]"], input[2].instance)
                 self.to_send.append((input[0], input[1], ev))
             elif input[2].name == "delete_instance":
-                pass
-            elif input[2].name == "associate_instance":
-                pass
-            elif input[2].name == "disassociate_instance":
-                pass
+                for index in input[2].parameters[1]:
+                    i = self.instances[index]
+                    for assoc_name in i.associations:
+                        if not (assoc_name == "parent"):
+                            traversal_list = self.processAssociationReference(assoc_name)
+                            instances = self.getInstances(i["instance"], traversal_list)
+                            if len(instances) > 0:
+                                pass
+                    i.user_defined_destructor()
+                    i.stop()
+                self.instances = [self.instances[i] for i in range(len(self.instances)) if i not in input[2].parameters[1]]
+                ev = Event("instance_deleted", None, input[2].parameters[1], input[2].instance)
+                self.to_send.append((input[1], input[0], ev))
             elif input[2].name == "instance_created":
                 instance = self.instances[input[2].instance]
                 instance.addEvent(input[2])
@@ -800,11 +824,11 @@ class Button(AtomicDEVS, ObjectManagerBase):
                 instance = self.instances[input[2].instance]
                 instance.addEvent(input[2])
             elif input[2].name == "instance_deleted":
-                pass
-            elif input[2].name == "instance_associated":
-                pass
-            elif input[2].name == "instance_disassociated":
-                pass
+                instance = self.instances[input[2].instance]
+                for association in instance.associations.items():
+                    if association[1].to_class == input[0]:
+                        for index in input[2].parameters:
+                            association[1].removeInstance(index)
             else:
                 ev = input[2]
                 self.addInput(ev)
@@ -1108,26 +1132,17 @@ class Ball(AtomicDEVS, ObjectManagerBase):
             elif input[2].name == "delete_instance":
                 for index in input[2].parameters[1]:
                     i = self.instances[index]
-                    try:
-                        for assoc_name in i.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))
-                        # TODO: These still do need to be implemented
-                        #association.removeInstance(i["instance"])
-                        #self.eventless.discard(i["instance"])
-                    except AssociationException as exception:
-                        raise RuntimeException("Error removing instance from association '" + association_name + "': " + str(exception))
+                    for assoc_name in i.associations:
+                        if not (assoc_name == "parent"):
+                            traversal_list = self.processAssociationReference(assoc_name)
+                            instances = self.getInstances(i["instance"], traversal_list)
+                            if len(instances) > 0:
+                                pass
                     i.user_defined_destructor()
                     i.stop()
                 self.instances = [self.instances[i] for i in range(len(self.instances)) if i not in input[2].parameters[1]]
-                #source.addEvent(Event("instance_deleted", parameters = [parameters[1]]))
-            elif input[2].name == "associate_instance":
-                pass
-            elif input[2].name == "disassociate_instance":
-                pass
+                ev = Event("instance_deleted", None, input[2].parameters[1], input[2].instance)
+                self.to_send.append((input[1], input[0], ev))
             elif input[2].name == "instance_created":
                 instance = self.instances[input[2].instance]
                 instance.addEvent(input[2])
@@ -1135,11 +1150,11 @@ class Ball(AtomicDEVS, ObjectManagerBase):
                 instance = self.instances[input[2].instance]
                 instance.addEvent(input[2])
             elif input[2].name == "instance_deleted":
-                pass
-            elif input[2].name == "instance_associated":
-                pass
-            elif input[2].name == "instance_disassociated":
-                pass
+                instance = self.instances[input[2].instance]
+                for association in instance.associations.items():
+                    if association[1].to_class == input[0]:
+                        for index in input[2].parameters:
+                            association[1].removeInstance(index)
             else:
                 ev = input[2]
                 self.addInput(ev)

+ 405 - 0
examples/BouncingBalls/old_sccd.xml

@@ -0,0 +1,405 @@
+<?xml version="1.1" ?>
+<diagram author="Simon Van Mierlo+Raphael Mannadiar" name="Bouncing_Balls_Python_Version">
+    <description>
+        Tkinter frame with bouncing balls in it.
+    </description>
+    <top>
+        from sccd.runtime.libs.ui import ui
+        from sccd.runtime.libs.utils import utils
+        import random
+    </top>
+    <inport name="ui"/>
+    <class name="MainApp" default="true">
+        <relationships>
+            <association name="fields" class="Field" />
+        </relationships>
+        <constructor>
+            <body>
+                <![CDATA[
+                self.nr_of_fields = 0
+                ]]>
+            </body>
+        </constructor>
+        <scxml initial="running">
+            <state id="running" initial="root">
+                <parallel id="root">
+                    <state id="main_behaviour" initial="initializing">
+                        <state id="initializing">
+                            <transition target="../running">
+                                <raise event="create_field" />        
+                            </transition>
+                        </state>
+                        <state id="running">
+                            <transition target='.' event='button_pressed' cond='event_name == "create_new_field"'>
+                                <parameter name="event_name" type="str" />
+                                <raise event="create_field" />
+                            </transition>
+                        </state>
+                    </state>
+                    <state id="cd_behaviour" initial="waiting">
+                        <state id="waiting">
+                            <transition event="create_field" target="../creating">
+                                <raise scope="cd" event="create_instance">
+                                    <parameter expr='"fields"' />
+                                </raise>
+                            </transition>
+                            <transition event="delete_field" target='../check_nr_of_fields'>
+                                <parameter name="association_name" type="str"/>
+                                <raise scope="cd" event="delete_instance">
+                                    <parameter expr='association_name' />
+                                </raise>
+                                <script>
+                                    <![CDATA[
+                                    self.nr_of_fields -= 1
+                                    ]]>
+                                </script>
+                            </transition>
+                        </state>
+                        <state id="creating">
+                            <transition event="instance_created" target="../waiting">
+                                <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>
+                                <script>
+                                    <![CDATA[
+                                    self.nr_of_fields += 1
+                                    ]]>
+                                </script>
+                            </transition>
+                        </state>
+                        <state id="check_nr_of_fields">
+                            <transition target="../stopped" cond="self.nr_of_fields == 0" after="0.05">
+                                <raise event="stop" />
+                            </transition>
+                            <transition target="../waiting" cond="self.nr_of_fields != 0"/>
+                        </state>
+                        <state id="stopped" />
+                    </state>
+                    <transition target="../stopped" event="stop">
+                        <script>
+                            <![CDATA[
+                            ui.close_window(ui.window)
+                            ]]>
+                        </script>
+                    </transition>
+                </parallel>
+                <state id="stopped" />
+            </state>
+        </scxml>
+    </class>
+
+    <class name="Field">
+        <attribute name="canvas" />
+        <attribute name="field_window" />
+        <inport name="field_ui"/>
+        <relationships>
+            <association name="balls" class="Ball" />
+            <association name="buttons" class="Button" />
+            <association name="parent" class="MainApp" min="1" max="1" />
+        </relationships>
+        <constructor>
+            <body>
+                <![CDATA[
+                self.field_window = ui.new_window(800,600,"BouncingBalls");
+                self.canvas = ui.append_canvas(self.field_window,800,550,{'background':'#eee'});
+                ui.bind_event(self.field_window, ui.EVENTS.WINDOW_CLOSE, self.controller, 'window_close', self.inports['field_ui']);
+                ui.bind_event(self.field_window, ui.EVENTS.KEY_PRESS, self.controller, 'key_press', self.inports['field_ui']);
+                ui.bind_event(self.canvas.element, ui.EVENTS.MOUSE_RIGHT_CLICK,    self.controller, 'right_click', self.inports['field_ui']);
+                ui.bind_event(self.canvas.element, ui.EVENTS.MOUSE_MOVE, self.controller, 'mouse_move', self.inports['field_ui']);
+                ui.bind_event(self.canvas.element, ui.EVENTS.MOUSE_RELEASE, self.controller, 'mouse_release', self.inports['field_ui']);
+                ]]>
+            </body>
+        </constructor>
+        <destructor>
+            <body>
+                <![CDATA[
+                ui.close_window(self.field_window);
+                ]]>
+            </body>
+        </destructor>
+        <scxml initial="root">
+            <state id="root" initial="waiting">
+                <state id="waiting">
+                    <transition event="set_association_name" target="../initializing">
+                        <parameter name="association_name" type="str" />
+                        <script>
+                            <![CDATA[
+                            self.association_name = association_name
+                            ]]>
+                        </script>
+                    </transition>
+                </state>
+                <state id="initializing">
+                    <transition target="../creating">
+                        <raise scope="cd" event="create_instance">
+                            <parameter expr='"buttons"' />
+                            <parameter expr='"Button"' />
+                            <parameter expr="self.field_window" />
+                            <parameter expr="'create_new_field'" />
+                            <parameter expr="'Spawn New Window'" />
+                        </raise>
+                    </transition>
+                </state>
+                <state id="creating">
+                    <transition event='instance_created' target='../packing'>
+                        <parameter name="association_name" type="string"/>
+                        <raise scope="cd" event="start_instance">
+                            <parameter expr="association_name" />
+                        </raise>
+                    </transition>
+                </state>
+                <state id="packing">
+                    <transition event="button_created" target='../running'>
+                    </transition>
+                </state>
+                <parallel id="running">
+                    <transition port="field_ui" event="window_close" target="../deleting">
+                        <raise event="delete_instance" scope="cd">
+                            <parameter expr='"buttons"' />
+                        </raise>
+                        <raise event="delete_instance" scope="cd">
+                            <parameter expr='"balls"' />
+                        </raise>
+                    </transition>
+                    <state id="main_behaviour" initial="running">
+                        <state id="running">
+                            <transition port="field_ui" event="right_click" target="../creating">
+                                <parameter name="x" />
+                                <parameter name="y" />
+                                <parameter name="button" />
+                                <raise scope="cd" event="create_instance">
+                                    <parameter expr='"balls"' />
+                                    <parameter expr='"Ball"' />
+                                    <parameter expr="self.canvas" />
+                                    <parameter expr="x" />
+                                    <parameter expr="y" />
+                                </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" />
+                                </raise>
+                            </transition>
+                        </state>
+                    </state>
+                    <state id="deleting_behaviour" initial="running">
+                        <state id="running">
+                            <transition event="delete_ball" target='.'>
+                                <parameter name="association_name" type="str"/>
+                                <raise scope="cd" event="delete_instance">
+                                    <parameter expr='association_name' />
+                                </raise>
+                            </transition>
+                        </state>
+                    </state>
+                    <state id="child_behaviour" initial="listening">
+                        <state id="listening">
+                            <transition event="button_pressed" target='.'>
+                                <parameter name="event_name" type="str" />
+                                <raise event="button_pressed" scope="narrow" target="'parent'">
+                                    <parameter expr='event_name' />
+                                </raise>
+                            </transition>
+                        </state>
+                    </state>
+                    <state id="deleting_balls_behaviour" initial="listening">
+                        <state id="listening">
+                            <transition port="field_ui" event="key_press" target="." cond="key == ui.KEYCODES.DELETE">
+                                <parameter name="key" />
+                                <raise event="delete_self" scope="narrow" target="'balls'" />
+                            </transition>
+                        </state>
+                    </state>
+                </parallel>
+                <state id="deleting">
+                    <transition target="../deleted">
+                        <raise event="delete_field" scope="narrow" target="'parent'">
+                            <parameter expr='self.association_name' />
+                        </raise>
+                    </transition>
+                </state>
+                <state id="deleted" />
+            </state>
+        </scxml>
+    </class>
+    
+    <class name="Button">
+        <relationships>
+            <association name="parent" class="Field" min="1" max="1" />
+        </relationships>
+        <inport name="button_ui"/>
+        <constructor>
+            <parameter name="tkparent" type="object" />
+            <parameter name="event_name" type="str" />
+            <parameter name="button_text" type="str" />
+            <body>
+                <![CDATA[
+                self.event_name = event_name;
+                button = ui.append_button(tkparent, event_name);
+                ui.bind_event(button.element, ui.EVENTS.MOUSE_CLICK, self.controller, 'mouse_click', self.inports['button_ui']);
+                ]]>
+            </body>
+        </constructor>
+        <scxml initial="initializing">
+            <state id="initializing">
+                <transition target="../running">
+                    <raise event="button_created" scope="narrow" target="'parent'">
+                    </raise>
+                </transition>
+            </state>
+            <state id="running">
+                <transition port='button_ui' event="mouse_click" target='.' cond="button == ui.MOUSE_BUTTONS.LEFT">
+                    <parameter name="x" />
+                    <parameter name="y" />
+                    <parameter name="button" />
+                    <raise event="button_pressed" scope="narrow" target="'parent'">
+                        <parameter expr="self.event_name" />
+                    </raise>
+                </transition>
+            </state>
+        </scxml>
+    </class>
+    
+    <class name="Ball">
+        <atrribute name="element" />
+        <attribute name="canvas" />
+        <inport name="ball_ui" />
+        <relationships>
+            <association name="parent" class="Field" min="1" max="1" />
+        </relationships>
+        <constructor>
+            <parameter name="canvas" />
+            <parameter name="x" />
+            <parameter name="y" />
+            <body>
+                <![CDATA[
+                self.canvas = canvas;
+                self.r = 20.0;
+                self.vel = {'x': random.uniform(-5.0, 5.0), 'y': random.uniform(-5.0, 5.0)};
+                self.mouse_pos = {};
+                self.smooth = 0.4; # value between 0 and 1
+
+                circle = self.canvas.add_circle(x, y, self.r, {'fill':'#000'});
+                ui.bind_event(circle, ui.EVENTS.MOUSE_PRESS, self.controller, 'mouse_press', self.inports["ball_ui"]);
+                ui.bind_event(circle, ui.EVENTS.MOUSE_MOVE, self.controller, 'mouse_move', self.inports['ball_ui']);
+                ui.bind_event(circle, ui.EVENTS.MOUSE_RELEASE, self.controller, 'mouse_release', self.inports['ball_ui']);
+                self.element = circle;
+                ]]>
+            </body>
+        </constructor>
+        <destructor>
+            <body>
+                <![CDATA[
+                self.canvas.remove_element(self.element);
+                ]]>
+            </body>
+        </destructor>
+        <scxml initial="main_behaviour">
+            <state id="main_behaviour" initial="initializing">
+                <state id="initializing">
+                    <transition event="set_association_name" target="../bouncing">
+                        <parameter name="association_name" type="str" />
+                        <script>
+                            <![CDATA[
+                            self.association_name = association_name
+                            ]]>                            
+                        </script>
+                    </transition>
+                </state>
+                <state id="bouncing">
+                    <transition after="(20 - self.getSimulatedTime() % 20) / 1000.0" target=".">
+                        <script>
+                            <![CDATA[
+                            pos = self.element.get_position();    
+                            if pos.x-self.r <= 0 or pos.x+self.r >= self.canvas.get_width():
+                                self.vel['x'] = -self.vel['x'];
+                            if pos.y-self.r <= 0 or pos.y+self.r >= self.canvas.get_height():
+                                self.vel['y'] = -self.vel['y'];
+                            self.element.move(self.vel['x'], self.vel['y']);
+                            ]]>                            
+                        </script>
+                    </transition>
+                    <transition port="ball_ui" event="mouse_press" target="../selected" cond="button == ui.MOUSE_BUTTONS.LEFT">
+                        <parameter name="x" />
+                        <parameter name="y" />
+                        <parameter name="button" />
+                        <script>
+                            <![CDATA[
+                            self.element.set_color("#ff0");
+                            ]]>                            
+                        </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[
+                            dx = x - self.mouse_pos['x'];
+                            dy = y - self.mouse_pos['y'];
+
+                            self.element.move(dx, dy);
+
+                            # keep ball within boundaries
+                            pos = self.element.get_position();
+                            if pos.x-self.r <= 0 :
+                                pos.x = self.r + 1;
+                            elif pos.x+self.r >= self.canvas.width :
+                                pos.x = self.canvas.width-self.r-1;
+                            if pos.y-self.r <= 0 :
+                                pos.y = self.r + 1;
+                            elif pos.y+self.r >= self.canvas.height :
+                                pos.y = self.canvas.height-self.r-1;
+                            self.element.set_position(pos.x, pos.y);
+                            self.mouse_pos = {'x':x, 'y':y};
+                            self.vel = {
+                                'x': (1-self.smooth)*dx + self.smooth*self.vel['x'],
+                                'y': (1-self.smooth)*dy + self.smooth*self.vel['y']
+                            };
+                            ]]>
+                        </script>
+                    </transition>
+                    <transition port="ball_ui" event="mouse_release" target="../bouncing">
+                        <parameter name="x" />
+                        <parameter name="y" />
+                        <script>
+                            <![CDATA[
+                            self.element.set_color("#f00");
+                            ]]>                            
+                        </script>
+                    </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>
+                    <transition event="delete_self" target='../../deleted'>                    
+                        <raise event="delete_ball" scope="narrow" target="'parent'">
+                            <parameter expr='self.association_name' />
+                        </raise>
+                    </transition>
+                </state>
+            </state>
+            <state id='deleted' />
+        </scxml>
+    </class>
+</diagram>

+ 18 - 7
examples/FixedTimer/Python/runner.py

@@ -1,12 +1,23 @@
 import tkinter as tk
 import target as target
-from sccd.runtime.libs.ui import ui
-from sccd.runtime.statecharts_core import Event
-from sccd.runtime.tkinter_eventloop import *
+from sccd.runtime.libs.ui_v2 import UI
+from sccd.runtime.tkinter_eventloop import TkEventLoop
 
-if __name__ == '__main__':
-	ui.window = tk.Tk()
+class OutputListener:
+	def __init__(self, ui):
+		self.ui = ui
+
+	def add(self, event):
+		if event.port == "ui":
+			method = getattr(self.ui, event.name)
+			method(*event.parameters)
 
-	controller = target.Controller(TkEventLoop(ui.window))
+if __name__ == '__main__':
+	tkroot = tk.Tk()
+	tkroot.withdraw()
+	controller = target.Controller(TkEventLoop(tkroot))
+	ui = UI(tkroot, controller)
+	controller.addMyOwnOutputListener(OutputListener(ui))
 	controller.start()
-	ui.window.mainloop()
+	tkroot.mainloop()
+	

+ 99 - 33
examples/FixedTimer/Python/target.py

@@ -10,9 +10,8 @@ from sccd.runtime.statecharts_core import *
 from sccd.runtime.libs.ui import ui
 from time import time
 
-CANVAS_WIDTH = 500
-CANVAS_HEIGHT = 500
-FONT_SIZE = 50
+CANVAS_WIDTH = 800
+CANVAS_HEIGHT = 550
 
 # package "Timer (Eventloop Version)"
 
@@ -20,6 +19,7 @@ class MainApp(RuntimeClassBase):
     def __init__(self, controller):
         RuntimeClassBase.__init__(self, controller)
         
+        self.inports["field_ui"] = controller.addInputPort("field_ui", self)
         
         self.semantics.big_step_maximality = StatechartSemantics.TakeMany
         self.semantics.internal_event_lifeline = StatechartSemantics.Queue
@@ -30,59 +30,93 @@ class MainApp(RuntimeClassBase):
         # build Statechart structure
         self.build_statechart_structure()
         
+        # user defined attributes
+        self.window_id = None
+        self.canvas_id = None
+        self.text_id = None
+        
         # call user defined constructor
         MainApp.user_defined_constructor(self)
     
     def user_defined_constructor(self):
-        self.canvas = ui.append_canvas(ui.window,500,500,{'background':'#222222'})
-        self.clock_text = self.canvas.element.create_text(
-            CANVAS_WIDTH / 2,
-            CANVAS_HEIGHT / 2,
-            text='0.0', 
-            anchor='center',
-            font=("TkDefaultFont", FONT_SIZE)
-            )
-        self.actual_clock_text = self.canvas.element.create_text(
-            CANVAS_WIDTH / 2, 
-            (CANVAS_HEIGHT / 2) + FONT_SIZE, 
-            text='0.0', 
-            anchor='center',
-            font=("TkDefaultFont", FONT_SIZE)
-        )
-        interrupt_button = ui.append_button(ui.window, 'INTERRUPT');
-        continue_button = ui.append_button(ui.window, 'CONTINUE');
-        ui.bind_event(interrupt_button.element, ui.EVENTS.MOUSE_CLICK, self.controller, 'interrupt_clicked');
-        ui.bind_event(continue_button.element, ui.EVENTS.MOUSE_CLICK, self.controller, 'continue_clicked');
+        pass
     
     def user_defined_destructor(self):
         pass
     
     
-    # user defined method
-    def update_timers(self):
-        self.canvas.element.itemconfigure(self.clock_text, text=str('%.2f' % (self.getSimulatedTime() / 1000.0)))
-        self.canvas.element.itemconfigure(self.actual_clock_text, text='%.2f' % (time() / 1000.0))
-    
-    
     # builds Statechart structure
     def build_statechart_structure(self):
         
         # state <root>
         self.states[""] = State(0, "", self)
         
+        # state /creating_window
+        self.states["/creating_window"] = State(1, "/creating_window", self)
+        self.states["/creating_window"].setEnter(self._creating_window_enter)
+        
+        # state /creating_canvas
+        self.states["/creating_canvas"] = State(2, "/creating_canvas", self)
+        self.states["/creating_canvas"].setEnter(self._creating_canvas_enter)
+        
+        # state /creating_clock_text
+        self.states["/creating_clock_text"] = State(3, "/creating_clock_text", self)
+        self.states["/creating_clock_text"].setEnter(self._creating_clock_text_enter)
+        
+        # state /creating_interrupt_button
+        self.states["/creating_interrupt_button"] = State(4, "/creating_interrupt_button", self)
+        self.states["/creating_interrupt_button"].setEnter(self._creating_interrupt_button_enter)
+        
+        # state /creating_resume_button
+        self.states["/creating_resume_button"] = State(5, "/creating_resume_button", self)
+        self.states["/creating_resume_button"].setEnter(self._creating_resume_button_enter)
+        
         # state /running
-        self.states["/running"] = State(1, "/running", self)
+        self.states["/running"] = State(6, "/running", self)
         self.states["/running"].setEnter(self._running_enter)
         self.states["/running"].setExit(self._running_exit)
         
         # state /interrupted
-        self.states["/interrupted"] = State(2, "/interrupted", self)
+        self.states["/interrupted"] = State(7, "/interrupted", self)
         
         # add children
+        self.states[""].addChild(self.states["/creating_window"])
+        self.states[""].addChild(self.states["/creating_canvas"])
+        self.states[""].addChild(self.states["/creating_clock_text"])
+        self.states[""].addChild(self.states["/creating_interrupt_button"])
+        self.states[""].addChild(self.states["/creating_resume_button"])
         self.states[""].addChild(self.states["/running"])
         self.states[""].addChild(self.states["/interrupted"])
         self.states[""].fixTree()
-        self.states[""].default_state = self.states["/running"]
+        self.states[""].default_state = self.states["/creating_window"]
+        
+        # transition /creating_window
+        _creating_window_0 = Transition(self, self.states["/creating_window"], [self.states["/creating_canvas"]])
+        _creating_window_0.setAction(self._creating_window_0_exec)
+        _creating_window_0.setTrigger(Event("window_created", None))
+        self.states["/creating_window"].addTransition(_creating_window_0)
+        
+        # transition /creating_canvas
+        _creating_canvas_0 = Transition(self, self.states["/creating_canvas"], [self.states["/creating_clock_text"]])
+        _creating_canvas_0.setAction(self._creating_canvas_0_exec)
+        _creating_canvas_0.setTrigger(Event("canvas_created", None))
+        self.states["/creating_canvas"].addTransition(_creating_canvas_0)
+        
+        # transition /creating_clock_text
+        _creating_clock_text_0 = Transition(self, self.states["/creating_clock_text"], [self.states["/creating_interrupt_button"]])
+        _creating_clock_text_0.setAction(self._creating_clock_text_0_exec)
+        _creating_clock_text_0.setTrigger(Event("text_created", None))
+        self.states["/creating_clock_text"].addTransition(_creating_clock_text_0)
+        
+        # transition /creating_interrupt_button
+        _creating_interrupt_button_0 = Transition(self, self.states["/creating_interrupt_button"], [self.states["/creating_resume_button"]])
+        _creating_interrupt_button_0.setTrigger(Event("button_created", None))
+        self.states["/creating_interrupt_button"].addTransition(_creating_interrupt_button_0)
+        
+        # transition /creating_resume_button
+        _creating_resume_button_0 = Transition(self, self.states["/creating_resume_button"], [self.states["/running"]])
+        _creating_resume_button_0.setTrigger(Event("button_created", None))
+        self.states["/creating_resume_button"].addTransition(_creating_resume_button_0)
         
         # transition /running
         _running_0 = Transition(self, self.states["/running"], [self.states["/running"]])
@@ -104,14 +138,46 @@ class MainApp(RuntimeClassBase):
         _interrupted_1.setTrigger(Event("continue_clicked", self.getInPortName("ui")))
         self.states["/interrupted"].addTransition(_interrupted_1)
     
+    def _creating_window_enter(self):
+        self.big_step.outputEvent(Event("create_window", self.getOutPortName("ui"), [800, 600, "Fixed Timer", self.inports['field_ui']]))
+    
+    def _creating_canvas_enter(self):
+        self.big_step.outputEvent(Event("create_canvas", self.getOutPortName("ui"), [self.window_id, CANVAS_WIDTH, CANVAS_HEIGHT, {'background':'#222222'}, self.inports['field_ui']]))
+    
+    def _creating_clock_text_enter(self):
+        self.big_step.outputEvent(Event("create_text", self.getOutPortName("ui"), [self.canvas_id, 50, 50, '00:00', self.inports['field_ui']]))
+    
+    def _creating_interrupt_button_enter(self):
+        self.big_step.outputEvent(Event("create_button", self.getOutPortName("ui"), [self.window_id, 'INTERRUPT', self.inports['field_ui']]))
+    
+    def _creating_resume_button_enter(self):
+        self.big_step.outputEvent(Event("create_button", self.getOutPortName("ui"), [self.window_id, 'RESUME', self.inports['field_ui']]))
+    
     def _running_enter(self):
         self.addTimer(0, 0.05)
     
     def _running_exit(self):
         self.removeTimer(0)
     
+    def _creating_window_0_exec(self, parameters):
+        window_id = parameters[0]
+        self.window_id = window_id
+        self.big_step.outputEvent(Event("bind_event", self.getOutPortName("ui"), [window_id, ui.EVENTS.WINDOW_CLOSE, 'window_close', self.inports['field_ui']]))
+        self.big_step.outputEvent(Event("bind_event", self.getOutPortName("ui"), [window_id, ui.EVENTS.KEY_PRESS, 'key_press', self.inports['field_ui']]))
+    
+    def _creating_canvas_0_exec(self, parameters):
+        canvas_id = parameters[0]
+        self.canvas_id = canvas_id
+        self.big_step.outputEvent(Event("bind_event", self.getOutPortName("ui"), [canvas_id, ui.EVENTS.MOUSE_RIGHT_CLICK, 'right_click', self.inports['field_ui']]))
+        self.big_step.outputEvent(Event("bind_event", self.getOutPortName("ui"), [canvas_id, ui.EVENTS.MOUSE_MOVE, 'mouse_move', self.inports['field_ui']]))
+        self.big_step.outputEvent(Event("bind_event", self.getOutPortName("ui"), [canvas_id, ui.EVENTS.MOUSE_RELEASE, 'mouse_release', self.inports['field_ui']]))
+    
+    def _creating_clock_text_0_exec(self, parameters):
+        text_id = parameters[0]
+        self.text_id = text_id
+    
     def _running_0_exec(self, parameters):
-        self.update_timers()
+        self.big_step.outputEvent(Event("update_text", self.getOutPortName("ui"), [self.canvas_id, self.text_id, str('%.2f' % (self.getSimulatedTime() / 1000.0)), self.inports['field_ui']]))
     
     def _running_1_exec(self, parameters):
         self.update_timers()
@@ -124,7 +190,7 @@ class MainApp(RuntimeClassBase):
     
     def initializeStatechart(self):
         # enter default state
-        self.default_targets = self.states["/running"].getEffectiveTargetStates()
+        self.default_targets = self.states["/creating_window"].getEffectiveTargetStates()
         RuntimeClassBase.initializeStatechart(self)
 
 class ObjectManager(ObjectManagerBase):

+ 122 - 39
examples/FixedTimer/sccd.xml

@@ -1,54 +1,137 @@
 <?xml version="1.0" ?>
 <diagram author="Simon Van Mierlo" name="Timer (Eventloop Version)">
     <top>
-        from sccd.runtime.libs.ui import ui_v2 as ui 
+        from sccd.runtime.libs.ui import ui
         from time import time
 
-        CANVAS_WIDTH = 500
-        CANVAS_HEIGHT = 250
-        FONT_SIZE = 50
+        CANVAS_WIDTH = 800
+        CANVAS_HEIGHT = 550
     </top>
     
     <inport name="ui" />
 
     <class name="MainApp" default="true">
-        <method name="MainApp">
-            <body>
-                <![CDATA[
-                self.canvas = ui.append_canvas(ui.window,CANVAS_WIDTH,CANVAS_HEIGHT,{'background':'#222222'})
-                self.clock_text = self.canvas.element.create_text(
-                    CANVAS_WIDTH / 2,
-                    CANVAS_HEIGHT / 2,
-                    text='0.0', 
-                    anchor='center',
-                    font=("TkDefaultFont", FONT_SIZE)
-                    )
-                self.actual_clock_text = self.canvas.element.create_text(
-                    CANVAS_WIDTH / 2, 
-                    (CANVAS_HEIGHT / 2) + FONT_SIZE, 
-                    text='0.0', 
-                    anchor='center',
-                    font=("TkDefaultFont", FONT_SIZE)
-                )
-                interrupt_button = ui.append_button(ui.window, 'INTERRUPT');
-                continue_button = ui.append_button(ui.window, 'CONTINUE');
-                #ui.bind_event(interrupt_button.element, ui.EVENTS.MOUSE_CLICK, self.controller, 'interrupt_clicked');
-                #ui.bind_event(continue_button.element, ui.EVENTS.MOUSE_CLICK, self.controller, 'continue_clicked');
-                ]]>
-            </body>        
-        </method>
-        <method name="update_timers">
-            <body>
-                self.canvas.element.itemconfigure(self.clock_text, text=str('%.2f' % (self.getSimulatedTime() / 1000.0)))
-                self.canvas.element.itemconfigure(self.actual_clock_text, text='%.2f' % (time() / 1000.0))
-            </body>
-        </method>
-        <scxml initial="running">
-            <state id="running">
-                <transition target="." after="0.05">
+        <attribute name="window_id" />
+        <attribute name="canvas_id" />
+        <attribute name="text_id" />
+        <inport name="field_ui"/>
+        <scxml initial="creating_window">
+            <state id="creating_window">
+                <onentry>
+                    <raise port="ui" event="create_window">
+                        <parameter expr="800"/><!-- width -->
+                        <parameter expr="600"/><!-- height -->
+                        <parameter expr='"Fixed Timer"'/><!-- 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.update_timers()
+                        <![CDATA[
+                        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_WIDTH"/><!-- width -->
+                        <parameter expr="CANVAS_HEIGHT"/><!-- height -->
+                        <parameter expr="{'background':'#222222'}"/><!-- style -->
+                        <parameter expr="self.inports['field_ui']"/><!-- inport for response -->
+                    </raise>
+                </onentry>
+                <transition event="canvas_created" target="../creating_clock_text">
+                    <parameter name="canvas_id" type="int"/>
+                    <script>
+                        <![CDATA[
+                        self.canvas_id = canvas_id
+                        ]]>
                     </script>
+                    <raise port="ui" event="bind_event">
+                        <parameter expr="canvas_id"/><!-- widget_id -->
+                        <parameter expr="ui.EVENTS.MOUSE_RIGHT_CLICK"/><!-- tk_event -->
+                        <parameter expr="'right_click'"/><!-- sccd_event_name -->
+                        <parameter expr="self.inports['field_ui']"/><!-- inport for response -->
+                    </raise>
+                    <raise port="ui" event="bind_event">
+                        <parameter expr="canvas_id"/><!-- widget_id -->
+                        <parameter expr="ui.EVENTS.MOUSE_MOVE"/><!-- tk_event -->
+                        <parameter expr="'mouse_move'"/><!-- sccd_event_name -->
+                        <parameter expr="self.inports['field_ui']"/><!-- inport for response -->
+                    </raise>
+                    <raise port="ui" event="bind_event">
+                        <parameter expr="canvas_id"/><!-- widget_id -->
+                        <parameter expr="ui.EVENTS.MOUSE_RELEASE"/><!-- tk_event -->
+                        <parameter expr="'mouse_release'"/><!-- sccd_event_name -->
+                        <parameter expr="self.inports['field_ui']"/><!-- inport for response -->
+                    </raise>
+                </transition>
+            </state>
+            <state id="creating_clock_text">
+                <onentry>
+                    <raise port="ui" event="create_text">
+                        <parameter expr="self.canvas_id" />
+                        <parameter expr="50" />
+                        <parameter expr="50" />
+                        <parameter expr="'00:00'" />
+                        <parameter expr="self.inports['field_ui']" />
+                    </raise>
+                </onentry>
+                <transition event="text_created" target="../creating_interrupt_button">
+                    <parameter name="text_id" type="int" />
+                    <script>
+                        <![CDATA[
+                        self.text_id = text_id
+                        ]]>
+                    </script>
+                </transition>
+            </state>
+            <state id="creating_interrupt_button">
+                <onentry>
+                    <raise port="ui" event="create_button">
+                        <parameter expr="self.window_id" />
+                        <parameter expr="'INTERRUPT'" />
+                        <parameter expr="self.inports['field_ui']" />
+                    </raise>
+                </onentry>
+                <transition event="button_created" target="../creating_resume_button">
+                </transition>
+            </state>
+            <state id="creating_resume_button">
+                <onentry>
+                    <raise port="ui" event="create_button">
+                        <parameter expr="self.window_id" />
+                        <parameter expr="'RESUME'" />
+                        <parameter expr="self.inports['field_ui']" />
+                    </raise>
+                </onentry>
+                <transition event="button_created" target="../running">
+                </transition>
+            </state>
+            <state id="running">
+                <transition target="." after="0.05">
+                    <raise port="ui" event="update_text">
+                        <parameter expr="self.canvas_id" />
+                        <parameter expr="self.text_id" />
+                        <parameter expr="str('%.2f' % (self.getSimulatedTime() / 1000.0))" />
+                        <parameter expr="self.inports['field_ui']" />
+                    </raise>
                 </transition>
                 <transition target="../interrupted" event="interrupt_clicked" port="ui">
                     <script>

+ 1 - 2
paper/02-Background.tex

@@ -374,5 +374,4 @@ Coupling of ports is performed through the connectPorts method. Its first parame
 destination port. A coupling is rejected and an error message issued if the coupling is invalid.
 
 The source and destination ports are instances of the class Port. This class defines channels where events may pass between DEVS models. 
-These channels are defined in the Port's inLine and outLine attributes.
-
+These channels are defined in the Port's inLine and outLine attributes.

+ 9 - 9
paper/MasterThesis.fdb_latexmk

@@ -1,13 +1,13 @@
 # Fdb version 3
-["bibtex MasterThesis"] 0 "MasterThesis.aux" "MasterThesis.bbl" "MasterThesis" 1714375830
+["bibtex MasterThesis"] 0 "MasterThesis.aux" "MasterThesis.bbl" "MasterThesis" 1714397675
   "/usr/local/texlive/2019/texmf-dist/bibtex/bst/base/plain.bst" 1292289607 20613 bd3fbfa9f64872b81ac57a0dd2ed855f ""
   "MasterThesis.aux" 0 -1 0 "pdflatex"
   "references.bib" 1312367667 789 20803d158fccdc749b2e64f161e2607a ""
   (generated)
   "MasterThesis.bbl"
   "MasterThesis.blg"
-["pdflatex"] 1714375829 "/Users/sampieters/Desktop/VSCodeProjects/SCCD2DEVS/paper/MasterThesis.tex" "/Users/sampieters/Desktop/VSCodeProjects/SCCD2DEVS/paper/MasterThesis.pdf" "MasterThesis" 1714375830
-  "/Users/sampieters/Desktop/VSCodeProjects/SCCD2DEVS/paper/MasterThesis.aux" 1714375829 8 a94a2480d3289e625eea47cd1b285758 ""
+["pdflatex"] 1714397674 "/Users/sampieters/Desktop/VSCodeProjects/SCCD2DEVS/paper/MasterThesis.tex" "/Users/sampieters/Desktop/VSCodeProjects/SCCD2DEVS/paper/MasterThesis.pdf" "MasterThesis" 1714397675
+  "/Users/sampieters/Desktop/VSCodeProjects/SCCD2DEVS/paper/MasterThesis.aux" 1714397674 8 a94a2480d3289e625eea47cd1b285758 ""
   "/Users/sampieters/Desktop/VSCodeProjects/SCCD2DEVS/paper/MasterThesis.tex" 1708595575 2030 b07d38d40f55a12ddbb2150cd1cb0161 ""
   "/usr/local/texlive/2019/texmf-dist/fonts/map/fontname/texfonts.map" 1511824771 3332 103109f5612ad95229751940c61aada0 ""
   "/usr/local/texlive/2019/texmf-dist/fonts/tfm/public/cm/cmbx12.tfm" 1136768653 1324 c910af8c371558dc20f2d7822f66fe64 ""
@@ -96,7 +96,7 @@
   "00-Acknowledgements.tex" 1714059530 667 8e107c839354f000e37d04dc25ae918a ""
   "00-NedSamenvatting.tex" 1312367667 167 8399376b625bface729d36e4e2250554 ""
   "01-Introduction.tex" 1714128909 4068 1b7abf65cd933cb114e95a696e069d8b ""
-  "02-Background.tex" 1714375829 24623 51c848e8c64d3a8d3bc89c5b8987c5a8 ""
+  "02-Background.tex" 1714397673 24621 e803b54ac801b9deb14b541ef1e967bd ""
   "03-Methodology.tex" 1708865037 5239 30d99e6e522d5663924569fc8bdf8d22 ""
   "04-Implementation.tex" 1708595418 112 55cb6455e2f9f0104ec4d8e6d0f49273 ""
   "05-Examples.tex" 1708595429 100 9e94dd9a3549d797588d04c14167759b ""
@@ -118,11 +118,11 @@
   "titlesec.sty" 1312367667 47627 5593f18067f6da9a34ba2dc08abaee8e ""
   (generated)
   "MasterThesis.out"
-  "MasterThesis.toc"
-  "MasterThesis.pdf"
-  "MasterThesis.aux"
+  "MasterThesis.log"
+  "/Users/sampieters/Desktop/VSCodeProjects/SCCD2DEVS/paper/MasterThesis.log"
   "MasterThesis.lof"
+  "MasterThesis.aux"
+  "MasterThesis.toc"
   "/Users/sampieters/Desktop/VSCodeProjects/SCCD2DEVS/paper/MasterThesis.pdf"
-  "/Users/sampieters/Desktop/VSCodeProjects/SCCD2DEVS/paper/MasterThesis.log"
-  "MasterThesis.log"
+  "MasterThesis.pdf"
   "MasterThesis.lot"

BIN
paper/MasterThesis.pdf


BIN
paper/MasterThesis.synctex.gz


+ 28 - 9
sccd/compiler/DEVS_generator.py

@@ -413,12 +413,27 @@ class DEVSGenerator(Visitor):
         self.writer.endElseIf()
 
         self.writer.beginElseIf(GLC.EqualsExpression("input[2].name", GLC.String("delete_instance")))
-        self.writer.endElseIf()
-
-        self.writer.beginElseIf(GLC.EqualsExpression("input[2].name", GLC.String("associate_instance")))
-        self.writer.endElseIf()
+        
+        self.writer.beginForLoopIterateArray("input[2].parameters[1]", "index")
+        self.writer.addAssignment("i", "self.instances[index]")
+        
+        # TODO: Try, except block 
+        self.writer.beginForLoopIterateArray("i.associations", "assoc_name")
+        self.writer.beginIf(GLC.NotExpression(GLC.EqualsExpression("assoc_name", GLC.String("parent"))))
+        self.writer.addAssignment("traversal_list", "self.processAssociationReference(assoc_name)")
+        self.writer.addAssignment("instances", "self.getInstances(i[\"instance\"], traversal_list)")
+        self.writer.beginIf(GLC.GreaterThanExpression("len(instances)", "0"))
+        self.writer.addRawCode("pass")
+        self.writer.endIf()
+        self.writer.endIf()
+        self.writer.endForLoopIterateArray()
 
-        self.writer.beginElseIf(GLC.EqualsExpression("input[2].name", GLC.String("disassociate_instance")))
+        self.writer.add(GLC.FunctionCall("i.user_defined_destructor"))
+        self.writer.add(GLC.FunctionCall("i.stop"))
+        self.writer.endForLoopIterateArray()
+        self.writer.addAssignment("self.instances", "[self.instances[i] for i in range(len(self.instances)) if i not in input[2].parameters[1]]")
+        self.writer.addAssignment("ev", "Event(\"instance_deleted\", None, input[2].parameters[1], input[2].instance)")
+        self.writer.add(GLC.FunctionCall("self.to_send.append", ["(input[1], input[0], ev)"]))
         self.writer.endElseIf()
 
         self.writer.beginElseIf(GLC.EqualsExpression("input[2].name", GLC.String("instance_created")))
@@ -432,12 +447,16 @@ class DEVSGenerator(Visitor):
         self.writer.endElseIf()
 
         self.writer.beginElseIf(GLC.EqualsExpression("input[2].name", GLC.String("instance_deleted")))
-        self.writer.endElseIf()
+        self.writer.addAssignment("instance", "self.instances[input[2].instance]")
+        self.writer.beginForLoopIterateArray("instance.associations.items()", "association")
+        self.writer.beginIf(GLC.EqualsExpression("association[1].to_class", "input[0]"))
 
-        self.writer.beginElseIf(GLC.EqualsExpression("input[2].name", GLC.String("instance_associated")))
-        self.writer.endElseIf()
+        self.writer.beginForLoopIterateArray("input[2].parameters", "index")
+        self.writer.add(GLC.FunctionCall("association[1].removeInstance", ["index"]))
+        self.writer.endForLoopIterateArray()
 
-        self.writer.beginElseIf(GLC.EqualsExpression("input[2].name", GLC.String("instance_disassociated")))
+        self.writer.endIf()
+        self.writer.endForLoopIterateArray()
         self.writer.endElseIf()
 
         self.writer.beginElse()

+ 5 - 6
sccd/runtime/DEVS_statecharts_core.py

@@ -65,8 +65,7 @@ class Association(object):
 
     def removeInstance(self, instance):
         if self.allowedToRemove():
-            #index = self.instances_to_ids[instance]
-            index = instance
+            index = self.instances_to_ids[instance]
             del self.instances[index]
             del self.instances_to_ids[instance]
             self.size -= 1
@@ -894,9 +893,6 @@ class ObjectManagerBase(object):
             instances = self.getInstances(source, traversal_list)
             association = source.associations[traversal_list[0][0]]
 
-            for assoc in association.instances:
-                association.removeInstance(assoc)
-            
             #for i in instances:
             #    try:
             #        for assoc_name in i["instance"].associations:
@@ -922,7 +918,10 @@ class ObjectManagerBase(object):
 
             params = list(association.instances.values())
 
-            self.to_send.append((source.association_name, association.to_class, Event("delete_instance", None, [parameters[1], params], index)))
+            self.to_send.append((self.name, association.to_class, Event("delete_instance", None, [parameters[1], params], index)))
+
+            #for assoc in association.instances:
+            #    association.removeInstance(assoc)
         
 
 

+ 15 - 0
sccd/runtime/libs/ui_v2.py

@@ -102,6 +102,21 @@ class UI:
             self.tk.destroy()
         self.tk.after(0, callback)
 
+    def create_text(self, canvas_id, x, y, the_text, res_port):
+        def callback():
+            canvas = self.mapping[canvas_id]
+            text_id = canvas.create_text(x, y, text=the_text)
+            self.controller.addInput(Event("text_created", res_port, [canvas_id, text_id]))
+        # schedule in mainloop:
+        self.tk.after(0, callback)
+
+    def update_text(self, canvas_id, text_id, the_text, res_port):
+        def callback():
+            canvas = self.mapping[canvas_id]
+            canvas.itemconfigure(text_id, text=the_text)
+        # schedule in mainloop:
+        self.tk.after(0, callback)
+
     def create_circle(self, canvas_id, x, y, r, style, res_port):
         def callback():
             canvas = self.mapping[canvas_id]