diff -r 000000000000 -r b622defdfd98 LDViewer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LDViewer.py Wed Jan 31 16:31:39 2007 +0100 @@ -0,0 +1,1184 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C): Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU Lesser General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#Lesser General Public License for more details. +# +#You should have received a copy of the GNU Lesser General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from wxPython.wx import * +import wx +from types import * + +from plcopen.structures import * +from graphics.GraphicCommons import * +from graphics.FBD_Objects import * +from Viewer import * + +def ExtractNextBlocks(block, block_list): + current_list = [block] + while len(current_list) > 0: + next_list = [] + for current in current_list: + connectors = current.GetConnectors() + input_connectors = [] + if isinstance(current, LD_PowerRail) and current.GetType() == RIGHTRAIL: + input_connectors = connectors + else: + if "inputs" in connectors: + input_connectors = connectors["inputs"] + if "input" in connectors: + input_connectors = [connectors["input"]] + for connector in input_connectors: + for wire, handle in connector.GetWires(): + next = wire.EndConnected.GetParentBlock() + if not isinstance(next, LD_PowerRail) and next not in block_list: + block_list.append(next) + next_list.append(next) + current_list = next_list + +def CalcBranchSize(elements, stop): + branch_size = 0 + stop_list = [stop] + ExtractNextBlocks(stop, stop_list) + element_tree = {} + for element in elements: + if element not in element_tree: + element_tree[element] = {"parents":["start"], "children":[], "weight":None} + GenerateTree(element, element_tree, stop_list) + elif element_tree[element]: + element_tree[element]["parents"].append("start") + for element, values in element_tree.items(): + if values and values["children"] == ["stop"]: + CalcWeight(element, element_tree) + if values["weight"]: + branch_size += values["weight"] + else: + return 1 + return branch_size + +def RemoveElement(remove, element_tree): + if remove in element_tree and element_tree[remove]: + for child in element_tree[remove]["children"]: + if child != "stop": + RemoveElement(child, element_tree) + element_tree[remove] = None + +def GenerateTree(element, element_tree, stop_list): + if element in element_tree: + connectors = element.GetConnectors() + input_connectors = [] + if isinstance(element, LD_PowerRail) and element.GetType() == RIGHTRAIL: + input_connectors = connectors + else: + if "inputs" in connectors: + input_connectors = connectors["inputs"] + if "input" in connectors: + input_connectors = [connectors["input"]] + for connector in input_connectors: + for wire, handle in connector.GetWires(): + next = wire.EndConnected.GetParentBlock() + if isinstance(next, LD_PowerRail) and next.GetType() == LEFTRAIL or next in stop_list: + for remove in element_tree[element]["children"]: + RemoveElement(remove, element_tree) + element_tree[element]["children"] = ["stop"] + elif element_tree[element]["children"] == ["stop"]: + element_tree[next] = None + elif next not in element_tree or element_tree[next]: + element_tree[element]["children"].append(next) + if next in element_tree: + element_tree[next]["parents"].append(element) + else: + element_tree[next] = {"parents":[element], "children":[], "weight":None} + GenerateTree(next, element_tree, stop_list) + +def CalcWeight(element, element_tree): + weight = 0 + parts = None + if element in element_tree: + for parent in element_tree[element]["parents"]: + if parent == "start": + weight += 1 + elif parent in element_tree: + if not parts: + parts = len(element_tree[parent]["children"]) + else: + parts = min(parts, len(element_tree[parent]["children"])) + if not element_tree[parent]["weight"]: + CalcWeight(parent, element_tree) + if element_tree[parent]["weight"]: + weight += element_tree[parent]["weight"] + else: + element_tree[element]["weight"] = None + return + else: + element_tree[element]["weight"] = None + return + if not parts: + parts = 1 + element_tree[element]["weight"] = max(1, weight / parts) + + +#------------------------------------------------------------------------------- +# Ladder Diagram Graphic elements Viewer class +#------------------------------------------------------------------------------- + +""" +Class derived from Viewer class that implements a Viewer of Ladder Diagram +""" + +class LD_Viewer(Viewer): + + def __init__(self, parent, window, controler): + Viewer.__init__(self, parent, window, controler) + self.Rungs = [] + self.Comments = [] + +#------------------------------------------------------------------------------- +# Refresh functions +#------------------------------------------------------------------------------- + + def RefreshView(self): + Viewer.RefreshView(self) + for i, rung in enumerate(self.Rungs): + bbox = rung.GetBoundingBox() + if i < len(self.Comments): + pos = self.Comments[i].GetPosition() + if pos[1] > bbox.y: + self.Comment.insert(i, None) + else: + self.Comment.insert(i, None) + + def loadInstance(self, instance, ids): + Viewer.loadInstance(self, instance, ids) + if instance["type"] == "leftPowerRail": + element = self.FindElementById(instance["id"]) + rung = Graphic_Group(self) + rung.SelectElement(element) + self.Rungs.append(rung) + elif instance["type"] == "rightPowerRail": + rungs = [] + for connector in instance["connectors"]: + for link in connector["links"]: + connected = self.FindElementById(link["refLocalId"]) + rung = self.FindRung(connected) + if rung not in rungs: + rungs.append(rung) + if len(rungs) > 1: + raise "ValueError", "Ladder element with id %d is on more than one rung."%instance["id"] + element = self.FindElementById(instance["id"]) + self.Rungs[rungs[0]].SelectElement(element) + for connector in element.GetConnectors(): + for wire, num in connector.GetWires(): + self.Rungs[rungs[0]].SelectElement(wire) + self.RefreshPosition(element) + elif instance["type"] in ["contact", "coil"]: + rungs = [] + for link in instance["connectors"]["input"]["links"]: + connected = self.FindElementById(link["refLocalId"]) + rung = self.FindRung(connected) + if rung not in rungs: + rungs.append(rung) + if len(rungs) > 1: + raise "ValueError", "Ladder element with id %d is on more than one rung."%instance["id"] + element = self.FindElementById(instance["id"]) + self.Rungs[rungs[0]].SelectElement(element) + for wire, num in element.GetConnectors()["input"].GetWires(): + self.Rungs[rungs[0]].SelectElement(wire) + self.RefreshPosition(element) + elif instance["type"] == "comment": + element = self.FindElementById(instance["id"]) + pos = element.GetPosition() + i = 0 + inserted = False + while i < len(self.Comments) and not inserted: + ipos = self.Comments[i].GetPosition() + if pos[1] < ipos[1]: + self.Comments.insert(i, element) + inserted = True + i += 1 + if not inserted: + self.Comments.append(element) + +#------------------------------------------------------------------------------- +# Search Element functions +#------------------------------------------------------------------------------- + + def FindRung(self, element): + for i, rung in enumerate(self.Rungs): + if rung.IsElementIn(element): + return i + return None + + def FindElement(self, pos): + elements = [] + for element in self.Elements: + if element.HitTest(pos) or element.TestHandle(pos) != (0, 0): + elements.append(element) + if len(elements) == 1: + return elements[0] + elif len(elements) > 1: + group = Graphic_Group(self) + for element in elements: + if element in self.Blocks: + return element + group.SelectElement(element) + return group + return None + + def SearchElements(self, bbox): + elements = [] + for element in self.Blocks: + element_bbox = element.GetBoundingBox() + if element_bbox.x >= bbox.x and element_bbox.y >= bbox.y and element_bbox.x + element_bbox.width <= bbox.x + bbox.width and element_bbox.y + element_bbox.height <= bbox.y + bbox.height: + elements.append(element) + return elements + +#------------------------------------------------------------------------------- +# Mouse event functions +#------------------------------------------------------------------------------- + + def OnViewerLeftDown(self, event): + if self.Mode == MODE_SELECTION: + pos = event.GetPosition() + element = self.FindElement(pos) + if self.SelectedElement: + if self.SelectedElement in self.Elements: + if self.SelectedElement != element: + if self.SelectedElement in self.Wires: + self.SelectedElement.SetSelectedSegment(None) + else: + self.SelectedElement.SetSelected(False) + else: + self.SelectedElement = None + elif element and element not in self.Elements: + if self.SelectedElement.GetElements() != element.GetElements(): + for elt in self.SelectedElement.GetElements(): + if elt in self.Wires: + elt.SetSelectedSegment(None) + self.SelectedElement.SetSelected(False) + self.SelectedElement = None + else: + for elt in self.SelectedElement.GetElements(): + if elt in self.Wires: + elt.SetSelectedSegment(None) + self.SelectedElement.SetSelected(False) + self.SelectedElement = None + self.Refresh() + if element: + self.SelectedElement = element + self.SelectedElement.OnLeftDown(event, self.Scaling) + self.Refresh() + else: + self.rubberBand.Reset() + self.rubberBand.OnLeftDown(event, self.Scaling) + event.Skip() + + def OnViewerLeftUp(self, event): + if self.rubberBand.IsShown(): + if self.Mode == MODE_SELECTION: + elements = self.SearchElements(self.rubberBand.GetCurrentExtent()) + self.rubberBand.OnLeftUp(event, self.Scaling) + if len(elements) > 0: + self.SelectedElement = Graphic_Group(self) + self.SelectedElement.SetElements(elements) + self.SelectedElement.SetSelected(True) + self.Refresh() + elif self.Mode == MODE_SELECTION and self.SelectedElement: + if self.SelectedElement in self.Elements: + if self.SelectedElement in self.Wires: + result = self.SelectedElement.TestSegment(event.GetPosition(), True) + if result and result[1] in [EAST, WEST]: + self.SelectedElement.SetSelectedSegment(result[0]) + else: + self.SelectedElement.OnLeftUp(event, self.Scaling) + else: + for element in self.SelectedElement.GetElements(): + if element in self.Wires: + result = element.TestSegment(event.GetPosition(), True) + if result and result[1] in [EAST, WEST]: + element.SetSelectedSegment(result[0]) + else: + element.OnLeftUp(event, self.Scaling) + wxCallAfter(self.SetCursor, wxNullCursor) + self.ReleaseMouse() + self.Refresh() + event.Skip() + + def OnViewerRightUp(self, event): + pos = event.GetPosition() + element = self.FindElement(pos) + if element: + if self.SelectedElement and self.SelectedElement != element: + self.SelectedElement.SetSelected(False) + self.SelectedElement = element + if self.SelectedElement in self.Wires: + self.SelectedElement.SetSelectedSegment(0) + else: + self.SelectedElement.SetSelected(True) + self.SelectedElement.OnRightUp(event, self.Scaling) + wxCallAfter(self.SetCursor, wxNullCursor) + self.ReleaseMouse() + self.Refresh() + event.Skip() + + def OnViewerLeftDClick(self, event): + if self.Mode == MODE_SELECTION and self.SelectedElement: + self.SelectedElement.OnLeftDClick(event, self.Scaling) + self.Refresh() + event.Skip() + + def OnViewerMotion(self, event): + if self.rubberBand.IsShown(): + self.rubberBand.OnMotion(event, self.Scaling) + event.Skip() + +#------------------------------------------------------------------------------- +# Keyboard event functions +#------------------------------------------------------------------------------- + + def OnChar(self, event): + keycode = event.GetKeyCode() + if keycode == WXK_DELETE and self.SelectedElement: + if self.SelectedElement in self.Blocks: + self.SelectedElement.Delete() + elif self.SelectedElement in self.Wires: + self.DeleteWire(self.SelectedElement) + elif self.SelectedElement not in self.Elements: + all_wires = True + for element in self.SelectedElement.GetElements(): + all_wires &= element in self.Wires + if all_wires: + self.DeleteWire(self.SelectedElement) + else: + self.SelectedElement.Delete() + self.Refresh() + event.Skip() + +#------------------------------------------------------------------------------- +# Adding element functions +#------------------------------------------------------------------------------- + + def AddRung(self): + dialog = LDElementDialog(self.Parent, "coil") + varlist = [] + vars = self.Controler.GetCurrentElementEditingInterfaceVars() + if vars: + for var in vars: + if var["Type"] != "Input" and var["Value"] == "BOOL": + varlist.append(var["Name"]) + returntype = self.Controler.GetCurrentElementEditingInterfaceReturnType() + if returntype == "BOOL": + varlist.append(self.Controler.GetCurrentElementEditingName()) + dialog.SetVariables(varlist) + dialog.SetValues({"name":"","type":COIL_NORMAL}) + if dialog.ShowModal() == wxID_OK: + values = dialog.GetValues() + startx, starty = LD_OFFSET[0], 0 + if len(self.Rungs) > 0: + bbox = self.Rungs[-1].GetBoundingBox() + starty = bbox.y + bbox.height + starty += LD_OFFSET[1] + rung = Graphic_Group(self) + # Create comment + id = self.GetNewId() + comment = Comment(self, "Commentaire", id) + comment.SetPosition(startx, starty) + comment.SetSize(LD_COMMENT_DEFAULTSIZE[0], LD_COMMENT_DEFAULTSIZE[1]) + self.Elements.append(comment) + self.Comments.append(comment) + self.Controler.AddCurrentElementEditingComment(id) + self.RefreshCommentModel(comment) + starty += LD_COMMENT_DEFAULTSIZE[1] + LD_OFFSET[1] + # Create LeftPowerRail + id = self.GetNewId() + leftpowerrail = LD_PowerRail(self, LEFTRAIL, id) + leftpowerrail.SetPosition(startx, starty) + self.Elements.append(leftpowerrail) + self.Blocks.append(leftpowerrail) + rung.SelectElement(leftpowerrail) + self.Controler.AddCurrentElementEditingPowerRail(id, LEFTRAIL) + self.RefreshPowerRailModel(leftpowerrail) + # Create Coil + id = self.GetNewId() + coil = LD_Coil(self, values["type"], values["name"], id) + coil.SetPosition(startx, starty + (LD_LINE_SIZE - LD_ELEMENT_SIZE[1]) / 2) + self.Elements.append(coil) + self.Blocks.append(coil) + rung.SelectElement(coil) + self.Controler.AddCurrentElementEditingCoil(id) + # Create Wire between LeftPowerRail and Coil + wire = Wire(self) + start_connector = coil.GetConnectors()["input"] + end_connector = leftpowerrail.GetConnectors()[0] + start_connector.Connect((wire, 0), False) + end_connector.Connect((wire, -1), False) + wire.ConnectStartPoint(None, start_connector) + wire.ConnectEndPoint(None, end_connector) + self.Wires.append(wire) + self.Elements.append(wire) + rung.SelectElement(wire) + # Create RightPowerRail + id = self.GetNewId() + rightpowerrail = LD_PowerRail(self, RIGHTRAIL, id) + rightpowerrail.SetPosition(startx, starty) + self.Elements.append(rightpowerrail) + self.Blocks.append(rightpowerrail) + rung.SelectElement(rightpowerrail) + self.Controler.AddCurrentElementEditingPowerRail(id, RIGHTRAIL) + # Create Wire between LeftPowerRail and Coil + wire = Wire(self) + start_connector = rightpowerrail.GetConnectors()[0] + end_connector = coil.GetConnectors()["output"] + start_connector.Connect((wire, 0), False) + end_connector.Connect((wire, -1), False) + wire.ConnectStartPoint(None, start_connector) + wire.ConnectEndPoint(None, end_connector) + self.Wires.append(wire) + self.Elements.append(wire) + rung.SelectElement(wire) + self.RefreshPosition(coil) + self.Rungs.append(rung) + self.Refresh() + + def AddContact(self): + wires = [] + if self.SelectedElement in self.Wires: + left_element = self.SelectedElement.EndConnected + if not isinstance(left_element.GetParentBlock(), LD_Coil): + wires.append(self.SelectedElement) + elif self.SelectedElement and self.SelectedElement not in self.Elements: + if False not in [element in self.Wires for element in self.SelectedElement.GetElements()]: + for element in self.SelectedElement.GetElements(): + wires.append(element) + if len(wires) > 0: + dialog = LDElementDialog(self.Parent, "contact") + varlist = [] + vars = self.Controler.GetCurrentElementEditingInterfaceVars() + if vars: + for var in vars: + if var["Type"] != "Output" and var["Value"] == "BOOL": + varlist.append(var["Name"]) + dialog.SetVariables(varlist) + dialog.SetValues({"name":"","type":CONTACT_NORMAL}) + if dialog.ShowModal() == wxID_OK: + values = dialog.GetValues() + points = wires[0].GetSelectedSegmentPoints() + id = self.GetNewId() + contact = LD_Contact(self, values["type"], values["name"], id) + contact.SetPosition(0, points[0].y - (LD_ELEMENT_SIZE[1] + 1) / 2) + self.Elements.append(contact) + self.Blocks.append(contact) + self.Controler.AddCurrentElementEditingContact(id) + rungindex = self.FindRung(wires[0]) + rung = self.Rungs[rungindex] + old_bbox = rung.GetBoundingBox() + rung.SelectElement(contact) + connectors = contact.GetConnectors() + left_elements = [] + right_elements = [] + left_index = [] + right_index = [] + for wire in wires: + if wire.EndConnected not in left_elements: + left_elements.append(wire.EndConnected) + left_index.append(wire.EndConnected.GetWireIndex(wire)) + else: + idx = left_elements.index(wire.EndConnected) + left_index[idx] = min(left_index[idx], wire.EndConnected.GetWireIndex(wire)) + if wire.StartConnected not in right_elements: + right_elements.append(wire.StartConnected) + right_index.append(wire.StartConnected.GetWireIndex(wire)) + else: + idx = right_elements.index(wire.StartConnected) + right_index[idx] = min(right_index[idx], wire.StartConnected.GetWireIndex(wire)) + wire.SetSelectedSegment(None) + wire.Clean() + rung.SelectElement(wire) + self.Wires.remove(wire) + self.Elements.remove(wire) + wires = [] + right_wires = [] + for i, left_element in enumerate(left_elements): + wire = Wire(self) + wires.append(wire) + connectors["input"].Connect((wire, 0), False) + left_element.InsertConnect(left_index[i], (wire, -1), False) + wire.ConnectStartPoint(None, connectors["input"]) + wire.ConnectEndPoint(None, left_element) + for i, right_element in enumerate(right_elements): + wire = Wire(self) + wires.append(wire) + right_wires.append(wire) + right_element.InsertConnect(right_index[i], (wire, 0), False) + connectors["output"].Connect((wire, -1), False) + wire.ConnectStartPoint(None, right_element) + wire.ConnectEndPoint(None, connectors["output"]) + right_wires.reverse() + for wire in wires: + self.Wires.append(wire) + self.Elements.append(wire) + rung.SelectElement(wire) + self.RefreshPosition(contact) + if len(right_wires) > 1: + group = Graphic_Group(self) + group.SetSelected(False) + for wire in right_wires: + wire.SetSelectedSegment(-1) + group.SelectElement(wire) + self.SelectedElement = group + else: + right_wires[0].SetSelectedSegment(-1) + self.SelectedElement = right_wires[0] + rung.RefreshBoundingBox() + new_bbox = rung.GetBoundingBox() + self.RefreshRungs(new_bbox.height - old_bbox.height, rungindex + 1) + self.Refresh() + + def AddBranch(self): + blocks = [] + if self.SelectedElement in self.Blocks: + blocks = [self.SelectedElement] + elif self.SelectedElement not in self.Elements: + elements = self.SelectedElement.GetElements() + for element in elements: + if isinstance(element, (LD_PowerRail, LD_Coil)): + return + blocks.append(element) + if len(blocks) > 0: + blocks_infos = [] + left_elements = [] + left_index = [] + right_elements = [] + right_index = [] + for block in blocks: + connectors = block.GetConnectors() + block_infos = {"inputs":[],"outputs":[],"lefts":[],"rights":[]} + if "inputs" in connectors: + block_infos["inputs"] = connectors["inputs"] + if "outputs" in connectors: + block_infos["outputs"] = connectors["outputs"] + if "input" in connectors: + block_infos["inputs"] = [connectors["input"]] + if "output" in connectors: + block_infos["outputs"] = [connectors["output"]] + for connector in block_infos["inputs"]: + for wire, handle in connector.GetWires(): + found = False + for infos in blocks_infos: + if wire.EndConnected in infos["outputs"]: + for left_element in infos["lefts"]: + if left_element not in block_infos["lefts"]: + block_infos["lefts"].append(left_element) + found = True + if not found and wire.EndConnected not in block_infos["lefts"]: + block_infos["lefts"].append(wire.EndConnected) + if wire.EndConnected not in left_elements: + left_elements.append(wire.EndConnected) + left_index.append(wire.EndConnected.GetWireIndex(wire)) + else: + index = left_elements.index(wire.EndConnected) + left_index[index] = max(left_index[index], wire.EndConnected.GetWireIndex(wire)) + for connector in block_infos["outputs"]: + for wire, handle in connector.GetWires(): + found = False + for infos in blocks_infos: + if wire.StartConnected in infos["inputs"]: + for right_element in infos["rights"]: + if right_element not in block_infos["rights"]: + block_infos["rights"].append(right_element) + found = True + if not found and wire.StartConnected not in block_infos["rights"]: + block_infos["rights"].append(wire.StartConnected) + if wire.StartConnected not in right_elements: + right_elements.append(wire.StartConnected) + right_index.append(wire.StartConnected.GetWireIndex(wire)) + else: + index = right_elements.index(wire.StartConnected) + right_index[index] = max(right_index[index], wire.StartConnected.GetWireIndex(wire)) + for connector in block_infos["inputs"]: + for infos in blocks_infos: + if connector in infos["rights"]: + infos["rights"].remove(connector) + if connector in right_elements: + index = right_elements.index(connector) + right_elements.pop(index) + right_index.pop(index) + for right_element in block_infos["rights"]: + if right_element not in infos["rights"]: + infos["rights"].append(right_element) + for connector in block_infos["outputs"]: + for infos in blocks_infos: + if connector in infos["lefts"]: + infos["lefts"].remove(connector) + if connector in left_elements: + index = left_elements.index(connector) + left_elements.pop(index) + left_index.pop(index) + for left_element in block_infos["lefts"]: + if left_element not in infos["lefts"]: + infos["lefts"].append(left_element) + blocks_infos.append(block_infos) + for infos in blocks_infos: + left_elements = [element for element in infos["lefts"]] + for left_element in left_elements: + if isinstance(left_element.GetParentBlock(), LD_PowerRail): + infos["lefts"].remove(left_element) + if "LD_PowerRail" not in infos["lefts"]: + infos["lefts"].append("LD_PowerRail") + right_elements = [element for element in infos["rights"]] + for right_element in right_elements: + if isinstance(right_element.GetParentBlock(), LD_PowerRail): + infos["rights"].remove(tight_element) + if "LD_PowerRail" not in infos["rights"]: + infos["rights"].append("LD_PowerRail") + infos["lefts"].sort() + infos["rights"].sort() + lefts = blocks_infos[0]["lefts"] + rights = blocks_infos[0]["rights"] + good = True + for infos in blocks_infos[1:]: + good &= infos["lefts"] == lefts + good &= infos["rights"] == rights + if good: + rungindex = self.FindRung(blocks[0]) + rung = self.Rungs[rungindex] + old_bbox = rung.GetBoundingBox() + left_powerrail = True + right_powerrail = True + for element in left_elements: + left_powerrail &= isinstance(element.GetParentBlock(), LD_PowerRail) + for element in right_elements: + right_powerrail &= isinstance(element.GetParentBlock(), LD_PowerRail) + if not left_powerrail or not right_powerrail: + if left_powerrail: + powerrail = left_elements[0].GetParentBlock() + index = 0 + for left_element in left_elements: + index = max(index, powerrail.GetConnectorIndex(left_element)) + if powerrail.IsNullConnector(index + 1): + powerrail.DeleteConnector(index + 1) + powerrail.InsertConnector(index + 1) + powerrail.RefreshModel() + connectors = powerrail.GetConnectors() + for i, right_element in enumerate(right_elements): + new_wire = Wire(self) + right_element.InsertConnect(right_index[i] + 1, (new_wire, 0), False) + connectors[index + 1].Connect((new_wire, -1), False) + new_wire.ConnectStartPoint(None, right_element) + new_wire.ConnectEndPoint(None, connectors[index + 1]) + self.Wires.append(new_wire) + self.Elements.append(new_wire) + rung.SelectElement(new_wire) + right_elements.reverse() + elif right_powerrail: + pass + else: + left_elements.reverse() + right_elements.reverse() + wires = [] + for i, left_element in enumerate(left_elements): + for j, right_element in enumerate(right_elements): + exist = False + for wire, handle in right_element.GetWires(): + exist |= wire.EndConnected == left_element + if not exist: + new_wire = Wire(self) + wires.append(new_wire) + right_element.InsertConnect(right_index[j] + 1, (new_wire, 0), False) + left_element.InsertConnect(left_index[i] + 1, (new_wire, -1), False) + new_wire.ConnectStartPoint(None, right_element) + new_wire.ConnectEndPoint(None, left_element) + wires.reverse() + for wire in wires: + self.Wires.append(wire) + self.Elements.append(wire) + rung.SelectElement(wire) + right_elements.reverse() + for block in blocks: + self.RefreshPosition(block) + for right_element in right_elements: + self.RefreshPosition(right_element.GetParentBlock()) + self.SelectedElement.RefreshBoundingBox() + rung.RefreshBoundingBox() + new_bbox = rung.GetBoundingBox() + self.RefreshRungs(new_bbox.height - old_bbox.height, rungindex + 1) + self.Refresh() + +#------------------------------------------------------------------------------- +# Delete element functions +#------------------------------------------------------------------------------- + + def DeleteContact(self, contact): + rungindex = self.FindRung(contact) + rung = self.Rungs[rungindex] + old_bbox = rung.GetBoundingBox() + connectors = contact.GetConnectors() + input_wires = [wire for wire, handle in connectors["input"].GetWires()] + output_wires = [wire for wire, handle in connectors["output"].GetWires()] + left_elements = [(wire.EndConnected, wire.EndConnected.GetWireIndex(wire)) for wire in input_wires] + right_elements = [(wire.StartConnected, wire.StartConnected.GetWireIndex(wire)) for wire in output_wires] + for wire in input_wires: + wire.Clean() + rung.SelectElement(wire) + self.Wires.remove(wire) + self.Elements.remove(wire) + for wire in output_wires: + wire.Clean() + rung.SelectElement(wire) + self.Wires.remove(wire) + self.Elements.remove(wire) + rung.SelectElement(contact) + contact.Clean() + left_elements.reverse() + right_elements.reverse() + powerrail = len(left_elements) == 1 and isinstance(left_elements[0][0].GetParentBlock(), LD_PowerRail) + for left_element, left_index in left_elements: + for right_element, right_index in right_elements: + wire_removed = [] + for wire, handle in right_element.GetWires(): + if wire.EndConnected == left_element: + wire_removed.append(wire) + elif isinstance(wire.EndConnected.GetParentBlock(), LD_PowerRail) and powerrail: + left_powerrail = wire.EndConnected.GetParentBlock() + index = left_powerrail.GetConnectorIndex(wire.EndConnected) + left_powerrail.DeleteConnector(index) + wire_removed.append(wire) + for wire in wire_removed: + wire.Clean() + self.Wires.remove(wire) + self.Elements.remove(wire) + rung.SelectElement(wire) + wires = [] + for left_element, left_index in left_elements: + for right_element, right_index in right_elements: + wire = Wire(self) + wires.append(wire) + right_element.InsertConnect(right_index, (wire, 0), False) + left_element.InsertConnect(left_index, (wire, -1), False) + wire.ConnectStartPoint(None, right_element) + wire.ConnectEndPoint(None, left_element) + wires.reverse() + for wire in wires: + self.Wires.append(wire) + self.Elements.append(wire) + rung.SelectElement(wire) + right_elements.reverse() + for right_element, right_index in right_elements: + self.RefreshPosition(right_element.GetParentBlock()) + self.Blocks.remove(contact) + self.Elements.remove(contact) + self.Controler.RemoveCurrentElementEditingInstance(contact.GetId()) + rung.RefreshBoundingBox() + new_bbox = rung.GetBoundingBox() + self.RefreshRungs(new_bbox.height - old_bbox.height, rungindex + 1) + self.SelectedElement = None + + def DeleteCoil(self, coil): + rungindex = self.FindRung(coil) + rung = self.Rungs[rungindex] + bbox = rung.GetBoundingBox() + for element in rung.GetElements(): + if element in self.Wires: + element.Clean() + self.Wires.remove(element) + self.Elements.remove(element) + for element in rung.GetElements(): + if element in self.Blocks: + self.Controler.RemoveCurrentElementEditingInstance(element.GetId()) + self.Blocks.remove(element) + self.Elements.remove(element) + self.Controler.RemoveCurrentElementEditingInstance(self.Comments[rungindex].GetId()) + self.Elements.remove(self.Comments[rungindex]) + self.Comments.pop(rungindex) + self.Rungs.pop(rungindex) + if rungindex < len(self.Rungs): + next_bbox = self.Rungs[rungindex].GetBoundingBox() + self.RefreshRungs(bbox.y - next_bbox.y, rungindex) + self.SelectedElement = None + + def DeleteWire(self, wire): + wires = [] + left_elements = [] + right_elements = [] + if wire in self.Wires: + wires = [wire] + elif wire not in self.Elements: + for element in wire.GetElements(): + if element in self.Wires: + wires.append(element) + else: + wires = [] + break + if len(wires) > 0: + rungindex = self.FindRung(wires[0]) + rung = self.Rungs[rungindex] + old_bbox = rung.GetBoundingBox() + for wire in wires: + connections = wire.GetSelectedSegmentConnections() + left_block = wire.EndConnected.GetParentBlock() + if wire.EndConnected not in left_elements: + left_elements.append(wire.EndConnected) + if wire.StartConnected not in right_elements: + right_elements.append(wire.StartConnected) + if connections == (False, False) or connections == (False, True) and isinstance(left_block, LD_PowerRail): + wire.Clean() + self.Wires.remove(wire) + self.Elements.remove(wire) + rung.SelectElement(wire) + for left_element in left_elements: + left_block = left_element.GetParentBlock() + if isinstance(left_block, LD_PowerRail): + if len(left_element.GetWires()) == 0: + index = left_block.GetConnectorIndex(left_element) + left_block.DeleteConnector(index) + else: + connectors = left_block.GetConnectors() + output_connectors = [] + if "outputs" in connectors: + output_connectors = connectors["outputs"] + if "output" in connectors: + output_connectors = [connectors["output"]] + for connector in output_connectors: + for wire, handle in connector.GetWires(): + self.RefreshPosition(wire.StartConnected.GetParentBlock()) + for right_element in right_elements: + self.RefreshPosition(right_element.GetParentBlock()) + rung.RefreshBoundingBox() + new_bbox = rung.GetBoundingBox() + self.RefreshRungs(new_bbox.height - old_bbox.height, rungindex + 1) + self.SelectedElement = None + +#------------------------------------------------------------------------------- +# Refresh element position functions +#------------------------------------------------------------------------------- + + def RefreshPosition(self, element): + if isinstance(element, LD_PowerRail) and element.GetType() == LEFTRAIL: + element.RefreshModel() + return + connectors = element.GetConnectors() + input_connectors = [] + output_connectors = [] + if isinstance(element, LD_PowerRail) and element.GetType() == RIGHTRAIL: + input_connectors = connectors + else: + if "inputs" in connectors: + input_connectors = connectors["inputs"] + if "outputs" in connectors: + output_connectors = connectors["outputs"] + if "input" in connectors: + input_connectors = [connectors["input"]] + if "output" in connectors: + output_connectors = [connectors["output"]] + position = element.GetPosition() + minx = 0 + onlyone = [] + for connector in input_connectors: + onlyone.append(len(connector.GetWires()) == 1) + for wire, handle in connector.GetWires(): + onlyone[-1] &= len(wire.EndConnected.GetWires()) == 1 + leftblock = wire.EndConnected.GetParentBlock() + pos = leftblock.GetPosition() + size = leftblock.GetSize() + minx = max(minx, pos[0] + size[0]) + if isinstance(element, LD_Coil): + interval = LD_WIRECOIL_SIZE + else: + interval = LD_WIRE_SIZE + if False in onlyone: + interval += LD_WIRE_SIZE + movex = minx + interval - position[0] + element.Move(movex, 0) + for i, connector in enumerate(input_connectors): + startpoint = connector.GetPosition(False) + previous_blocks = [] + block_list = [] + start_offset = 0 + if not onlyone[i]: + middlepoint = minx + LD_WIRE_SIZE + for j, (wire, handle) in enumerate(connector.GetWires()): + block = wire.EndConnected.GetParentBlock() + endpoint = wire.EndConnected.GetPosition(False) + if j == 0: + if not onlyone[i] and wire.EndConnected.GetWireIndex(wire) > 0: + start_offset = endpoint.y - startpoint.y + offset = start_offset + else: + offset = start_offset + LD_LINE_SIZE * CalcBranchSize(previous_blocks, block) + if block in block_list: + wires = wire.EndConnected.GetWires() + endmiddlepoint = wires[0][0].StartConnected.GetPosition(False)[0] - LD_WIRE_SIZE + points = [startpoint, wxPoint(middlepoint, startpoint.y), + wxPoint(middlepoint, startpoint.y + offset), + wxPoint(endmiddlepoint, startpoint.y + offset), + wxPoint(endmiddlepoint, endpoint.y), endpoint] + else: + if startpoint.y + offset != endpoint.y: + if isinstance(block, LD_PowerRail): + index = block.GetConnectorIndex(wire.EndConnected) + if index: + diff = (startpoint.y - endpoint.y) / LD_LINE_SIZE + for k in xrange(abs(diff)): + if diff < 0: + block.DeleteConnector(index - 1 - k) + else: + block.InsertConnector(index + k, False) + else: + block.Move(0, startpoint.y + offset - endpoint.y) + self.RefreshPosition(block) + endpoint = wire.EndConnected.GetPosition(False) + if not onlyone[i]: + points = [startpoint, wxPoint(middlepoint, startpoint.y), + wxPoint(middlepoint, endpoint.y), endpoint] + else: + points = [startpoint, endpoint] + wire.SetPoints(points) + previous_blocks.append(block) + ExtractNextBlocks(block, block_list) + element.RefreshModel(False) + for connector in output_connectors: + for wire, handle in connector.GetWires(): + self.RefreshPosition(wire.StartConnected.GetParentBlock()) + + def RefreshRungs(self, movey, fromidx): + if movey != 0: + for i in xrange(fromidx, len(self.Rungs)): + self.Comments[i].Move(0, movey) + self.Comments[i].RefreshModel() + self.Rungs[i].Move(0, movey) + for element in self.Rungs[i].GetElements(): + if element in self.Blocks: + self.RefreshPosition(element) + +#------------------------------------------------------------------------------- +# Edit element content functions +#------------------------------------------------------------------------------- + + def EditContactContent(self, contact): + dialog = LDElementDialog(self.Parent, "contact") + varlist = [] + vars = self.Controler.GetCurrentElementEditingInterfaceVars() + if vars: + for var in vars: + if var["Type"] != "Output" and var["Value"] == "BOOL": + varlist.append(var["Name"]) + dialog.SetVariables(varlist) + dialog.SetValues({"name":contact.GetName(),"type":contact.GetType()}) + if dialog.ShowModal() == wxID_OK: + values = dialog.GetValues() + contact.SetName(values["name"]) + contact.SetType(values["type"]) + contact.RefreshModel(False) + self.Refresh() + dialog.Destroy() + + def EditCoilContent(self, coil): + dialog = LDElementDialog(self.Parent, "coil") + varlist = [] + vars = self.Controler.GetCurrentElementEditingInterfaceVars() + if vars: + for var in vars: + if var["Type"] != "Input" and var["Value"] == "BOOL": + varlist.append(var["Name"]) + returntype = self.Controler.GetCurrentElementEditingInterfaceReturnType() + if returntype == "BOOL": + varlist.append(self.Controler.GetCurrentElementEditingName()) + dialog.SetVariables(varlist) + dialog.SetValues({"name":coil.GetName(),"type":coil.GetType()}) + if dialog.ShowModal() == wxID_OK: + values = dialog.GetValues() + coil.SetName(values["name"]) + coil.SetType(values["type"]) + coil.RefreshModel(False) + self.Refresh() + dialog.Destroy() + +#------------------------------------------------------------------------------- +# Edit Ladder Element Properties Dialog +#------------------------------------------------------------------------------- + +[wxID_LDELEMENTDIALOG, wxID_LDELEMENTDIALOGMAINPANEL, + wxID_LDELEMENTDIALOGNAME, wxID_LDELEMENTDIALOGRADIOBUTTON1, + wxID_LDELEMENTDIALOGRADIOBUTTON2, wxID_LDELEMENTDIALOGRADIOBUTTON3, + wxID_LDELEMENTDIALOGRADIOBUTTON4, wxID_LDELEMENTDIALOGPREVIEW, + wxID_LDELEMENTDIALOGSTATICTEXT1, wxID_LDELEMENTDIALOGSTATICTEXT2, + wxID_LDELEMENTDIALOGSTATICTEXT3, +] = [wx.NewId() for _init_ctrls in range(11)] + +class LDElementDialog(wx.Dialog): + def _init_coll_flexGridSizer1_Items(self, parent): + # generated method, don't edit + + parent.AddWindow(self.MainPanel, 0, border=0, flag=0) + + def _init_sizers(self): + # generated method, don't edit + self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) + + self._init_coll_flexGridSizer1_Items(self.flexGridSizer1) + + self.SetSizer(self.flexGridSizer1) + + def _init_ctrls(self, prnt, title, labels): + # generated method, don't edit + wx.Dialog.__init__(self, id=wxID_LDELEMENTDIALOG, + name='VariablePropertiesDialog', parent=prnt, pos=wx.Point(376, 223), + size=wx.Size(350, 260), style=wx.DEFAULT_DIALOG_STYLE, + title=title) + self.SetClientSize(wx.Size(350, 260)) + + self.MainPanel = wx.Panel(id=wxID_LDELEMENTDIALOGMAINPANEL, + name='MainPanel', parent=self, pos=wx.Point(0, 0), + size=wx.Size(340, 200), style=wx.TAB_TRAVERSAL) + self.MainPanel.SetAutoLayout(True) + + self.staticText1 = wx.StaticText(id=wxID_LDELEMENTDIALOGSTATICTEXT1, + label='Type:', name='staticText1', parent=self.MainPanel, + pos=wx.Point(24, 24), size=wx.Size(70, 17), style=0) + + self.staticText2 = wx.StaticText(id=wxID_LDELEMENTDIALOGSTATICTEXT2, + label='Name:', name='staticText2', parent=self.MainPanel, + pos=wx.Point(24, 150), size=wx.Size(70, 17), style=0) + + self.staticText3 = wx.StaticText(id=wxID_LDELEMENTDIALOGSTATICTEXT3, + label='Preview:', name='staticText3', parent=self.MainPanel, + pos=wx.Point(174, 24), size=wx.Size(100, 17), style=0) + + self.radioButton1 = wx.RadioButton(id=wxID_LDELEMENTDIALOGRADIOBUTTON1, + label=labels[0], name='radioButton1', parent=self.MainPanel, + pos=wx.Point(24, 48), size=wx.Size(114, 24), style=0) + EVT_RADIOBUTTON(self, wxID_LDELEMENTDIALOGRADIOBUTTON1, self.OnTypeChanged) + self.radioButton1.SetValue(True) + + self.radioButton2 = wx.RadioButton(id=wxID_LDELEMENTDIALOGRADIOBUTTON2, + label=labels[1], name='radioButton2', parent=self.MainPanel, + pos=wx.Point(24, 72), size=wx.Size(128, 24), style=0) + EVT_RADIOBUTTON(self, wxID_LDELEMENTDIALOGRADIOBUTTON2, self.OnTypeChanged) + + self.radioButton3 = wx.RadioButton(id=wxID_LDELEMENTDIALOGRADIOBUTTON3, + label=labels[2], name='radioButton3', parent=self.MainPanel, + pos=wx.Point(24, 96), size=wx.Size(114, 24), style=0) + EVT_RADIOBUTTON(self, wxID_LDELEMENTDIALOGRADIOBUTTON3, self.OnTypeChanged) + + self.radioButton4 = wx.RadioButton(id=wxID_LDELEMENTDIALOGRADIOBUTTON4, + label=labels[3], name='radioButton4', parent=self.MainPanel, + pos=wx.Point(24, 120), size=wx.Size(128, 24), style=0) + EVT_RADIOBUTTON(self, wxID_LDELEMENTDIALOGRADIOBUTTON4, self.OnTypeChanged) + + self.Name = wx.Choice(id=wxID_LDELEMENTDIALOGNAME, + name='Name', parent=self.MainPanel, pos=wx.Point(24, 174), + size=wx.Size(145, 24), style=0) + EVT_CHOICE(self, wxID_LDELEMENTDIALOGNAME, self.OnNameChanged) + + self.Preview = wx.Panel(id=wxID_LDELEMENTDIALOGPREVIEW, + name='Preview', parent=self.MainPanel, pos=wx.Point(174, 48), + size=wx.Size(150, 150), style=wx.TAB_TRAVERSAL|wx.SIMPLE_BORDER) + self.Preview.SetBackgroundColour(wxColour(255,255,255)) + + self._init_sizers() + + def __init__(self, parent, type): + self.Type = type + if type == "contact": + self._init_ctrls(parent, "Edit Contact Values", ['Normal','Reverse','Rising Edge','Falling Edge']) + self.Element = LD_Contact(self.Preview, CONTACT_NORMAL, "") + elif type == "coil": + self._init_ctrls(parent, "Edit Coil Values", ['Normal','Reverse','Set','Reset']) + self.Element = LD_Coil(self.Preview, COIL_NORMAL, "") + self.Element.SetPosition((150 - LD_ELEMENT_SIZE[0]) / 2, (150 - LD_ELEMENT_SIZE[1]) / 2) + + self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL) + self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT) + + EVT_PAINT(self, self.OnPaint) + + def SetVariables(self, vars): + self.Name.Clear() + for name in vars: + self.Name.Append(name) + self.Name.Enable(self.Name.GetCount() > 0) + + def SetValues(self, values): + for name, value in values.items(): + if name == "name": + self.Element.SetName(value) + self.Name.SetStringSelection(value) + elif name == "type": + self.Element.SetType(value) + if self.Type == "contact": + if value == CONTACT_NORMAL: + self.radioButton1.SetValue(True) + elif value == CONTACT_REVERSE: + self.radioButton2.SetValue(True) + elif value == CONTACT_RISING: + self.radioButton3.SetValue(True) + elif value == CONTACT_FALLING: + self.radioButton4.SetValue(True) + elif self.Type == "coil": + if value == COIL_NORMAL: + self.radioButton1.SetValue(True) + elif value == COIL_REVERSE: + self.radioButton2.SetValue(True) + elif value == COIL_SET: + self.radioButton3.SetValue(True) + elif value == COIL_RESET: + self.radioButton4.SetValue(True) + + def GetValues(self): + values = {} + values["name"] = self.Element.GetName() + values["type"] = self.Element.GetType() + return values + + def OnTypeChanged(self, event): + if self.Type == "contact": + if self.radioButton1.GetValue(): + self.Element.SetType(CONTACT_NORMAL) + elif self.radioButton2.GetValue(): + self.Element.SetType(CONTACT_REVERSE) + elif self.radioButton3.GetValue(): + self.Element.SetType(CONTACT_RISING) + elif self.radioButton4.GetValue(): + self.Element.SetType(CONTACT_FALLING) + elif self.Type == "coil": + if self.radioButton1.GetValue(): + self.Element.SetType(COIL_NORMAL) + elif self.radioButton2.GetValue(): + self.Element.SetType(COIL_REVERSE) + elif self.radioButton3.GetValue(): + self.Element.SetType(COIL_SET) + elif self.radioButton4.GetValue(): + self.Element.SetType(COIL_RESET) + self.RefreshPreview() + event.Skip() + + def OnNameChanged(self, event): + self.Element.SetName(self.Name.GetStringSelection()) + self.RefreshPreview() + event.Skip() + + def RefreshPreview(self): + dc = wxClientDC(self.Preview) + dc.Clear() + self.Element.Draw(dc) + + def OnPaint(self, event): + self.RefreshPreview() + event.Skip()