Sfoglia il codice sorgente

Split of canvas elements and allow them to be dragged around

Yentl Van Tendeloo 8 anni fa
parent
commit
adba36af0a

BIN
classes/canvas/.canvas_element.xml.swp


+ 34 - 22
classes/canvas/canvas.xml

@@ -3,6 +3,7 @@
         <association name="parent" class="A" min="1" max="1" />
         <association name="parent" class="A" min="1" max="1" />
         <inheritance class="SCCDWidget" priority='0'/>
         <inheritance class="SCCDWidget" priority='0'/>
         <inheritance class="tk.Canvas" priority='1'/>
         <inheritance class="tk.Canvas" priority='1'/>
+        <association name="elements" class="CanvasElement"/>
     </relationships>
     </relationships>
     <constructor>
     <constructor>
         <parameter name="parent" />
         <parameter name="parent" />
@@ -23,13 +24,12 @@
             self.config(background='white', yscrollcommand=vbar.set, xscrollcommand=hbar.set)
             self.config(background='white', yscrollcommand=vbar.set, xscrollcommand=hbar.set)
             self.focus_set()
             self.focus_set()
 
 
-            self.elements = {}
-            self.shift = {}
+            self.assoc_links = {}
+            self.element_group = {}
         </body>
         </body>
     </constructor>
     </constructor>
     <destructor>
     <destructor>
         <body>
         <body>
-            self.delete("all")
             self.destroy()
             self.destroy()
         </body>
         </body>
     </destructor>
     </destructor>
@@ -45,45 +45,57 @@
 
 
         <state id="ready">
         <state id="ready">
             <transition event="clear_canvas" target=".">
             <transition event="clear_canvas" target=".">
+                <raise event="delete_instance" scope="cd">
+                    <parameter expr="'elements'"/>
+                </raise>
                 <script>
                 <script>
-                    self.delete("all")
-                    self.elements = {}
                     self.shift = {}
                     self.shift = {}
                 </script>
                 </script>
             </transition>
             </transition>
 
 
-            <transition event="define_group" target=".">
+            <transition event="define_group" target="../creating_group">
                 <parameter name="element"/>
                 <parameter name="element"/>
                 <script>
                 <script>
-                    self.elements[element["id"]] = element
-                    self.shift[element["id"]] = (element["x"], element["y"])
+                    self.creating_id = element["id"]
                 </script>
                 </script>
+                <raise event="create_instance" scope="cd">
+                    <parameter expr="'elements'"/>
+                    <parameter expr="'CanvasElement'"/>
+                    <parameter expr="self"/>
+                    <parameter expr="(element['x'], element['y'])"/>
+                </raise>
             </transition>
             </transition>
 
 
             <transition event="define_contains" target=".">
             <transition event="define_contains" target=".">
                 <parameter name="element"/>
                 <parameter name="element"/>
                 <script>
                 <script>
-                    self.shift[element["__target"]] = self.shift[element["__source"]]
+                    self.element_group[element["__target"]] = element["__source"]
+                    print("Binding element %s to group %s" % (element["__target"], element["__source"]))
                 </script>
                 </script>
             </transition>
             </transition>
 
 
             <transition event="draw_canvas" target=".">
             <transition event="draw_canvas" target=".">
                 <parameter name="element"/>
                 <parameter name="element"/>
                 <script>
                 <script>
-                    print("Render: " + str(element))
-                    self.elements[element["id"]] = element
-                    shift_x, shift_y = self.shift[element["id"]]
-                    elem_x = shift_x + element["x"]
-                    elem_y = shift_y + element["y"]
-                    if element["type"] == "Rectangle":
-                        self.create_rectangle(elem_x, elem_y, elem_x + element["width"], elem_y + element["height"], fill=element["fillColour"], outline=element["lineColour"])
-                    elif element["type"] == "Text":
-                        self.create_text(elem_x, elem_y, fill=element["lineColour"], text=element["text"], anchor=tk.NW)
-                    elif element["type"] == "Line":
-                        self.create_line(elem_x, elem_y, shift_x + element["targetX"], shift_y + element["targetY"], fill=element["lineColour"], width=element["lineWidth"], arrow=tk.LAST if element["arrow"] else tk.NONE)
-                    else:
-                        print("Undefined render format: " + str(element))
+                    print("Drawing element %s" % element["id"])
+                </script>
+                <raise event="draw_element" scope="narrow" target="self.assoc_links[self.element_group[element['id']]]">
+                    <parameter expr="element"/>
+                </raise>
+            </transition>
+        </state>
+
+        <state id="creating_group">
+            <transition event="instance_created" target="../ready">
+                <parameter name="assoc_name"/>
+                <raise event="start_instance" scope="cd">
+                    <parameter expr="assoc_name"/>
+                </raise>
+                <script>
+                    self.assoc_links[self.creating_id] = assoc_name
+                    print("Defining group " + str(self.creating_id))
                 </script>
                 </script>
+                <raise event="group_ready" scope="narrow" target="'parent'"/>
             </transition>
             </transition>
         </state>
         </state>
     </scxml>
     </scxml>

+ 81 - 0
classes/canvas/canvas_element.xml

@@ -0,0 +1,81 @@
+<class name="CanvasElement">
+    <relationships>
+        <association name="parent" class="A" min="1" max="1" />
+        <inheritance class="SCCDWidget" priority='0'/>
+        <association name="elements" class="CanvasElement"/>
+    </relationships>
+    <constructor>
+        <parameter name="parent"/>
+        <parameter name="coordinates"/>
+        <super class="SCCDWidget">
+            <parameter expr="True"/>
+        </super>
+        <body>
+            self.containing_canvas = parent
+            self.coordinates = coordinates
+            self.elements = []
+        </body>
+    </constructor>
+    <destructor>
+        for f in self.elements:
+            self.containing_canvas.delete(f)
+    </destructor>
+
+    <scxml initial="main">
+        <state id="main">
+            <transition event="draw_element" target=".">
+                <parameter name="element"/>
+                <script>
+                    elem_x = self.coordinates[0] + element["x"]
+                    elem_y = self.coordinates[1] + element["y"]
+                    if element["type"] == "Rectangle":
+                        result = self.containing_canvas.create_rectangle(elem_x, elem_y, elem_x + element["width"], elem_y + element["height"], fill=element["fillColour"], outline=element["lineColour"])
+                    elif element["type"] == "Text":
+                        result = self.containing_canvas.create_text(elem_x, elem_y, fill=element["lineColour"], text=element["text"], anchor=tk.NW)
+                    elif element["type"] == "Line":
+                        result = self.containing_canvas.create_line(elem_x, elem_y, self.coordinates[0] + element["targetX"], self.coordinates[1] + element["targetY"], fill=element["lineColour"], width=element["lineWidth"], arrow=tk.LAST if element["arrow"] else tk.NONE)
+                    else:
+                        print("Undefined render format: " + str(element))
+                        result = None
+
+                    if result is not None:
+                        self.elements.append(result)
+                        self.set_bindable_and_tagorid(self.containing_canvas, result)
+                </script>
+            </transition>
+
+            <transition event="left-click" cond="id(self) == ID" target="../dragging">
+                <parameter name="ID"/>
+                <script>
+                    self.original_coords = self.last_x, self.last_y
+                </script>
+            </transition>
+        </state>
+
+        <state id="dragging">
+            <transition event="motion" cond="id(self) == ID" target=".">
+                <parameter name="ID"/>
+                <script>
+                    for f in self.elements:
+                        old_coords = self.containing_canvas.coords(f)
+                        new_x = self.coordinates[0] - self.original_coords[0] + self.last_x
+                        new_y = self.coordinates[1] - self.original_coords[1] + self.last_y
+
+                        if len(old_coords) == 2:
+                            self.containing_canvas.coords(f, (new_x, new_y))
+                        elif len(old_coords) == 4:
+                            height = old_coords[3] - old_coords[1]
+                            width = old_coords[2] - old_coords[0]
+                            self.containing_canvas.coords(f, (new_x, new_y, new_x + width, new_y + height))
+                </script>
+            </transition>
+
+            <transition event="left-release" cond="id(self) == ID" target="../main">
+                <parameter name="ID"/>
+                <script>
+                    self.coordinates = self.coordinates[0] - (self.original_coords[0] - self.last_x), self.coordinates[1] - (self.original_coords[1] - self.last_y)
+                </script>
+            </transition>
+        </state>
+    </scxml>
+</class>

+ 5 - 1
classes/window/main_window.xml

@@ -424,7 +424,7 @@
                     </onentry>
                     </onentry>
 
 
                     <state id="allocate_groups">
                     <state id="allocate_groups">
-                        <transition cond="len(self.groups) > 0" target=".">
+                        <transition cond="len(self.groups) > 0" target="../allocating_group">
                             <raise event="define_group" scope="narrow" target="'canvas'">
                             <raise event="define_group" scope="narrow" target="'canvas'">
                                 <parameter expr="self.groups.pop()"/>
                                 <parameter expr="self.groups.pop()"/>
                             </raise>
                             </raise>
@@ -432,6 +432,10 @@
                         <transition cond="len(self.groups) == 0" target="../allocate_contains"/>
                         <transition cond="len(self.groups) == 0" target="../allocate_contains"/>
                     </state>
                     </state>
 
 
+                    <state id="allocating_group">
+                        <transition event="group_ready" target="../allocate_groups"/>
+                    </state>
+
                     <state id="allocate_contains">
                     <state id="allocate_contains">
                         <transition cond="len(self.contains) > 0" target=".">
                         <transition cond="len(self.contains) > 0" target=".">
                             <raise event="define_contains" scope="narrow" target="'canvas'">
                             <raise event="define_contains" scope="narrow" target="'canvas'">

+ 172 - 22
frontend.py

@@ -1,7 +1,7 @@
 """
 """
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 
 
-Date:   Wed Sep 13 11:45:24 2017
+Date:   Wed Sep 13 14:34:26 2017
 
 
 Model author: Yentl Van Tendeloo and Addis Gebremichael
 Model author: Yentl Van Tendeloo and Addis Gebremichael
 Model name:   Modelverse Visual Editor - Tkinter Version 
 Model name:   Modelverse Visual Editor - Tkinter Version 
@@ -3961,14 +3961,17 @@ class MainWindow(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         # state /running/rerender_model/render_model/allocate_groups
         # state /running/rerender_model/render_model/allocate_groups
         self.states["/running/rerender_model/render_model/allocate_groups"] = State(27, "/running/rerender_model/render_model/allocate_groups", self)
         self.states["/running/rerender_model/render_model/allocate_groups"] = State(27, "/running/rerender_model/render_model/allocate_groups", self)
         
         
+        # state /running/rerender_model/render_model/allocating_group
+        self.states["/running/rerender_model/render_model/allocating_group"] = State(28, "/running/rerender_model/render_model/allocating_group", self)
+        
         # state /running/rerender_model/render_model/allocate_contains
         # state /running/rerender_model/render_model/allocate_contains
-        self.states["/running/rerender_model/render_model/allocate_contains"] = State(28, "/running/rerender_model/render_model/allocate_contains", self)
+        self.states["/running/rerender_model/render_model/allocate_contains"] = State(29, "/running/rerender_model/render_model/allocate_contains", self)
         
         
         # state /running/rerender_model/render_model/render_elements
         # state /running/rerender_model/render_model/render_elements
-        self.states["/running/rerender_model/render_model/render_elements"] = State(29, "/running/rerender_model/render_model/render_elements", self)
+        self.states["/running/rerender_model/render_model/render_elements"] = State(30, "/running/rerender_model/render_model/render_elements", self)
         
         
         # state /close
         # state /close
-        self.states["/close"] = State(30, "/close", self)
+        self.states["/close"] = State(31, "/close", self)
         self.states["/close"].setEnter(self._close_enter)
         self.states["/close"].setEnter(self._close_enter)
         
         
         # add children
         # add children
@@ -4000,6 +4003,7 @@ class MainWindow(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         self.states["/running/rerender_model"].addChild(self.states["/running/rerender_model/request_render"])
         self.states["/running/rerender_model"].addChild(self.states["/running/rerender_model/request_render"])
         self.states["/running/rerender_model"].addChild(self.states["/running/rerender_model/render_model"])
         self.states["/running/rerender_model"].addChild(self.states["/running/rerender_model/render_model"])
         self.states["/running/rerender_model/render_model"].addChild(self.states["/running/rerender_model/render_model/allocate_groups"])
         self.states["/running/rerender_model/render_model"].addChild(self.states["/running/rerender_model/render_model/allocate_groups"])
+        self.states["/running/rerender_model/render_model"].addChild(self.states["/running/rerender_model/render_model/allocating_group"])
         self.states["/running/rerender_model/render_model"].addChild(self.states["/running/rerender_model/render_model/allocate_contains"])
         self.states["/running/rerender_model/render_model"].addChild(self.states["/running/rerender_model/render_model/allocate_contains"])
         self.states["/running/rerender_model/render_model"].addChild(self.states["/running/rerender_model/render_model/render_elements"])
         self.states["/running/rerender_model/render_model"].addChild(self.states["/running/rerender_model/render_model/render_elements"])
         self.states[""].fixTree()
         self.states[""].fixTree()
@@ -4165,7 +4169,7 @@ class MainWindow(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         self.states["/running/rerender_model/request_render"].addTransition(_running_rerender_model_request_render_1)
         self.states["/running/rerender_model/request_render"].addTransition(_running_rerender_model_request_render_1)
         
         
         # transition /running/rerender_model/render_model/allocate_groups
         # transition /running/rerender_model/render_model/allocate_groups
-        _running_rerender_model_render_model_allocate_groups_0 = Transition(self, self.states["/running/rerender_model/render_model/allocate_groups"], [self.states["/running/rerender_model/render_model/allocate_groups"]])
+        _running_rerender_model_render_model_allocate_groups_0 = Transition(self, self.states["/running/rerender_model/render_model/allocate_groups"], [self.states["/running/rerender_model/render_model/allocating_group"]])
         _running_rerender_model_render_model_allocate_groups_0.setAction(self._running_rerender_model_render_model_allocate_groups_0_exec)
         _running_rerender_model_render_model_allocate_groups_0.setAction(self._running_rerender_model_render_model_allocate_groups_0_exec)
         _running_rerender_model_render_model_allocate_groups_0.setTrigger(None)
         _running_rerender_model_render_model_allocate_groups_0.setTrigger(None)
         _running_rerender_model_render_model_allocate_groups_0.setGuard(self._running_rerender_model_render_model_allocate_groups_0_guard)
         _running_rerender_model_render_model_allocate_groups_0.setGuard(self._running_rerender_model_render_model_allocate_groups_0_guard)
@@ -4175,6 +4179,11 @@ class MainWindow(RuntimeClassBase, tk.Toplevel, SCCDWidget):
         _running_rerender_model_render_model_allocate_groups_1.setGuard(self._running_rerender_model_render_model_allocate_groups_1_guard)
         _running_rerender_model_render_model_allocate_groups_1.setGuard(self._running_rerender_model_render_model_allocate_groups_1_guard)
         self.states["/running/rerender_model/render_model/allocate_groups"].addTransition(_running_rerender_model_render_model_allocate_groups_1)
         self.states["/running/rerender_model/render_model/allocate_groups"].addTransition(_running_rerender_model_render_model_allocate_groups_1)
         
         
+        # transition /running/rerender_model/render_model/allocating_group
+        _running_rerender_model_render_model_allocating_group_0 = Transition(self, self.states["/running/rerender_model/render_model/allocating_group"], [self.states["/running/rerender_model/render_model/allocate_groups"]])
+        _running_rerender_model_render_model_allocating_group_0.setTrigger(Event("group_ready", None))
+        self.states["/running/rerender_model/render_model/allocating_group"].addTransition(_running_rerender_model_render_model_allocating_group_0)
+        
         # transition /running/rerender_model/render_model/allocate_contains
         # transition /running/rerender_model/render_model/allocate_contains
         _running_rerender_model_render_model_allocate_contains_0 = Transition(self, self.states["/running/rerender_model/render_model/allocate_contains"], [self.states["/running/rerender_model/render_model/allocate_contains"]])
         _running_rerender_model_render_model_allocate_contains_0 = Transition(self, self.states["/running/rerender_model/render_model/allocate_contains"], [self.states["/running/rerender_model/render_model/allocate_contains"]])
         _running_rerender_model_render_model_allocate_contains_0.setAction(self._running_rerender_model_render_model_allocate_contains_0_exec)
         _running_rerender_model_render_model_allocate_contains_0.setAction(self._running_rerender_model_render_model_allocate_contains_0_exec)
@@ -5549,11 +5558,10 @@ class Canvas(RuntimeClassBase, tk.Canvas, SCCDWidget):
         self.config(background='white', yscrollcommand=vbar.set, xscrollcommand=hbar.set)
         self.config(background='white', yscrollcommand=vbar.set, xscrollcommand=hbar.set)
         self.focus_set()
         self.focus_set()
         
         
-        self.elements = {}
-        self.shift = {}
+        self.assoc_links = {}
+        self.element_group = {}
     
     
     def user_defined_destructor(self):
     def user_defined_destructor(self):
-        self.delete("all")
         self.destroy()
         self.destroy()
         # call super class destructors
         # call super class destructors
         if hasattr(tk.Canvas, "__del__"):
         if hasattr(tk.Canvas, "__del__"):
@@ -5574,9 +5582,13 @@ class Canvas(RuntimeClassBase, tk.Canvas, SCCDWidget):
         # state /ready
         # state /ready
         self.states["/ready"] = State(2, "/ready", self)
         self.states["/ready"] = State(2, "/ready", self)
         
         
+        # state /creating_group
+        self.states["/creating_group"] = State(3, "/creating_group", self)
+        
         # add children
         # add children
         self.states[""].addChild(self.states["/main"])
         self.states[""].addChild(self.states["/main"])
         self.states[""].addChild(self.states["/ready"])
         self.states[""].addChild(self.states["/ready"])
+        self.states[""].addChild(self.states["/creating_group"])
         self.states[""].fixTree()
         self.states[""].fixTree()
         self.states[""].default_state = self.states["/main"]
         self.states[""].default_state = self.states["/main"]
         
         
@@ -5591,7 +5603,7 @@ class Canvas(RuntimeClassBase, tk.Canvas, SCCDWidget):
         _ready_0.setAction(self._ready_0_exec)
         _ready_0.setAction(self._ready_0_exec)
         _ready_0.setTrigger(Event("clear_canvas", None))
         _ready_0.setTrigger(Event("clear_canvas", None))
         self.states["/ready"].addTransition(_ready_0)
         self.states["/ready"].addTransition(_ready_0)
-        _ready_1 = Transition(self, self.states["/ready"], [self.states["/ready"]])
+        _ready_1 = Transition(self, self.states["/ready"], [self.states["/creating_group"]])
         _ready_1.setAction(self._ready_1_exec)
         _ready_1.setAction(self._ready_1_exec)
         _ready_1.setTrigger(Event("define_group", None))
         _ready_1.setTrigger(Event("define_group", None))
         self.states["/ready"].addTransition(_ready_1)
         self.states["/ready"].addTransition(_ready_1)
@@ -5603,39 +5615,171 @@ class Canvas(RuntimeClassBase, tk.Canvas, SCCDWidget):
         _ready_3.setAction(self._ready_3_exec)
         _ready_3.setAction(self._ready_3_exec)
         _ready_3.setTrigger(Event("draw_canvas", None))
         _ready_3.setTrigger(Event("draw_canvas", None))
         self.states["/ready"].addTransition(_ready_3)
         self.states["/ready"].addTransition(_ready_3)
+        
+        # transition /creating_group
+        _creating_group_0 = Transition(self, self.states["/creating_group"], [self.states["/ready"]])
+        _creating_group_0.setAction(self._creating_group_0_exec)
+        _creating_group_0.setTrigger(Event("instance_created", None))
+        self.states["/creating_group"].addTransition(_creating_group_0)
     
     
     def _main_0_exec(self, parameters):
     def _main_0_exec(self, parameters):
         self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("tk_widget", None, [self])]))
         self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("tk_widget", None, [self])]))
     
     
     def _ready_0_exec(self, parameters):
     def _ready_0_exec(self, parameters):
-        self.delete("all")
-        self.elements = {}
+        self.big_step.outputEventOM(Event("delete_instance", None, [self, 'elements']))
         self.shift = {}
         self.shift = {}
     
     
     def _ready_1_exec(self, parameters):
     def _ready_1_exec(self, parameters):
         element = parameters[0]
         element = parameters[0]
-        self.elements[element["id"]] = element
-        self.shift[element["id"]] = (element["x"], element["y"])
+        self.creating_id = element["id"]
+        self.big_step.outputEventOM(Event("create_instance", None, [self, 'elements', 'CanvasElement', self, (element['x'], element['y'])]))
     
     
     def _ready_2_exec(self, parameters):
     def _ready_2_exec(self, parameters):
         element = parameters[0]
         element = parameters[0]
-        self.shift[element["__target"]] = self.shift[element["__source"]]
+        self.element_group[element["__target"]] = element["__source"]
+        print("Binding element %s to group %s" % (element["__target"], element["__source"]))
     
     
     def _ready_3_exec(self, parameters):
     def _ready_3_exec(self, parameters):
         element = parameters[0]
         element = parameters[0]
-        print("Render: " + str(element))
-        self.elements[element["id"]] = element
-        shift_x, shift_y = self.shift[element["id"]]
-        elem_x = shift_x + element["x"]
-        elem_y = shift_y + element["y"]
+        print("Drawing element %s" % element["id"])
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, self.assoc_links[self.element_group[element['id']]], Event("draw_element", None, [element])]))
+    
+    def _creating_group_0_exec(self, parameters):
+        assoc_name = parameters[0]
+        self.big_step.outputEventOM(Event("start_instance", None, [self, assoc_name]))
+        self.assoc_links[self.creating_id] = assoc_name
+        print("Defining group " + str(self.creating_id))
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("group_ready", None, [])]))
+    
+    def initializeStatechart(self):
+        # enter default state
+        self.default_targets = self.states["/main"].getEffectiveTargetStates()
+        RuntimeClassBase.initializeStatechart(self)
+
+class CanvasElement(RuntimeClassBase, SCCDWidget):
+    def __init__(self, controller, parent, coordinates):
+        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
+        CanvasElement.user_defined_constructor(self, parent, coordinates)
+    
+    def user_defined_constructor(self, parent, coordinates):
+        SCCDWidget.__init__(self, True)
+        self.containing_canvas = parent
+        self.coordinates = coordinates
+        self.elements = []
+    
+    def user_defined_destructor(self):
+        # call super class destructors
+        if hasattr(SCCDWidget, "__del__"):
+            SCCDWidget.__del__(self)
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, "", self)
+        
+        # state /main
+        self.states["/main"] = State(1, "/main", self)
+        
+        # state /dragging
+        self.states["/dragging"] = State(2, "/dragging", self)
+        
+        # add children
+        self.states[""].addChild(self.states["/main"])
+        self.states[""].addChild(self.states["/dragging"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/main"]
+        
+        # transition /main
+        _main_0 = Transition(self, self.states["/main"], [self.states["/main"]])
+        _main_0.setAction(self._main_0_exec)
+        _main_0.setTrigger(Event("draw_element", None))
+        self.states["/main"].addTransition(_main_0)
+        _main_1 = Transition(self, self.states["/main"], [self.states["/dragging"]])
+        _main_1.setAction(self._main_1_exec)
+        _main_1.setTrigger(Event("left-click", None))
+        _main_1.setGuard(self._main_1_guard)
+        self.states["/main"].addTransition(_main_1)
+        
+        # transition /dragging
+        _dragging_0 = Transition(self, self.states["/dragging"], [self.states["/dragging"]])
+        _dragging_0.setAction(self._dragging_0_exec)
+        _dragging_0.setTrigger(Event("motion", None))
+        _dragging_0.setGuard(self._dragging_0_guard)
+        self.states["/dragging"].addTransition(_dragging_0)
+        _dragging_1 = Transition(self, self.states["/dragging"], [self.states["/main"]])
+        _dragging_1.setAction(self._dragging_1_exec)
+        _dragging_1.setTrigger(Event("left-release", None))
+        _dragging_1.setGuard(self._dragging_1_guard)
+        self.states["/dragging"].addTransition(_dragging_1)
+    
+    def _main_0_exec(self, parameters):
+        element = parameters[0]
+        elem_x = self.coordinates[0] + element["x"]
+        elem_y = self.coordinates[1] + element["y"]
         if element["type"] == "Rectangle":
         if element["type"] == "Rectangle":
-            self.create_rectangle(elem_x, elem_y, elem_x + element["width"], elem_y + element["height"], fill=element["fillColour"], outline=element["lineColour"])
+            result = self.containing_canvas.create_rectangle(elem_x, elem_y, elem_x + element["width"], elem_y + element["height"], fill=element["fillColour"], outline=element["lineColour"])
         elif element["type"] == "Text":
         elif element["type"] == "Text":
-            self.create_text(elem_x, elem_y, fill=element["lineColour"], text=element["text"], anchor=tk.NW)
+            result = self.containing_canvas.create_text(elem_x, elem_y, fill=element["lineColour"], text=element["text"], anchor=tk.NW)
         elif element["type"] == "Line":
         elif element["type"] == "Line":
-            self.create_line(elem_x, elem_y, shift_x + element["targetX"], shift_y + element["targetY"], fill=element["lineColour"], width=element["lineWidth"], arrow=tk.LAST if element["arrow"] else tk.NONE)
+            result = self.containing_canvas.create_line(elem_x, elem_y, self.coordinates[0] + element["targetX"], self.coordinates[1] + element["targetY"], fill=element["lineColour"], width=element["lineWidth"], arrow=tk.LAST if element["arrow"] else tk.NONE)
         else:
         else:
             print("Undefined render format: " + str(element))
             print("Undefined render format: " + str(element))
+            result = None
+        
+        if result is not None:
+            self.elements.append(result)
+            self.set_bindable_and_tagorid(self.containing_canvas, result)
+    
+    def _main_1_exec(self, parameters):
+        ID = parameters[0]
+        print("LEFT CLICK on canvas element at " + str(self.coordinates))
+        self.original_coords = self.last_x, self.last_y
+        print("Store click location: " + str(self.original_coords))
+    
+    def _main_1_guard(self, parameters):
+        ID = parameters[0]
+        return id(self) == ID
+    
+    def _dragging_0_exec(self, parameters):
+        ID = parameters[0]
+        for f in self.elements:
+            old_coords = self.containing_canvas.coords(f)
+            new_x = self.coordinates[0] - self.original_coords[0] + self.last_x
+            new_y = self.coordinates[1] - self.original_coords[1] + self.last_y
+        
+            if len(old_coords) == 2:
+                self.containing_canvas.coords(f, (new_x, new_y))
+            elif len(old_coords) == 4:
+                height = old_coords[3] - old_coords[1]
+                width = old_coords[2] - old_coords[0]
+                self.containing_canvas.coords(f, (new_x, new_y, new_x + width, new_y + height))
+    
+    def _dragging_0_guard(self, parameters):
+        ID = parameters[0]
+        return id(self) == ID
+    
+    def _dragging_1_exec(self, parameters):
+        ID = parameters[0]
+        print("Release at %s, so move coordinates" % str((self.last_x, self.last_y)))
+        self.coordinates = self.coordinates[0] - (self.original_coords[0] - self.last_x), self.coordinates[1] - (self.original_coords[1] - self.last_y)
+        print("New coordinates of element: %s" % str(self.coordinates))
+    
+    def _dragging_1_guard(self, parameters):
+        ID = parameters[0]
+        return id(self) == ID
     
     
     def initializeStatechart(self):
     def initializeStatechart(self):
         # enter default state
         # enter default state
@@ -5705,6 +5849,12 @@ class ObjectManager(ObjectManagerBase):
             instance = Canvas(self.controller, construct_params[0])
             instance = Canvas(self.controller, construct_params[0])
             instance.associations = {}
             instance.associations = {}
             instance.associations["parent"] = Association("A", 1, 1)
             instance.associations["parent"] = Association("A", 1, 1)
+            instance.associations["elements"] = Association("CanvasElement", 0, -1)
+        elif class_name == "CanvasElement":
+            instance = CanvasElement(self.controller, construct_params[0], construct_params[1])
+            instance.associations = {}
+            instance.associations["parent"] = Association("A", 1, 1)
+            instance.associations["elements"] = Association("CanvasElement", 0, -1)
         else:
         else:
             raise Exception("Cannot instantiate class " + class_name)
             raise Exception("Cannot instantiate class " + class_name)
         return instance
         return instance

+ 1 - 0
frontend.xml

@@ -29,4 +29,5 @@
     <class src="classes/widgets/label.xml"/>
     <class src="classes/widgets/label.xml"/>
     <class src="classes/widgets/progress_bar.xml"/>
     <class src="classes/widgets/progress_bar.xml"/>
     <class src="classes/canvas/canvas.xml"/>
     <class src="classes/canvas/canvas.xml"/>
+    <class src="classes/canvas/canvas_element.xml"/>
 </diagram>
 </diagram>