--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/svghmi/README Mon Jul 15 09:05:00 2019 +0200
@@ -0,0 +1,1 @@
+SVG HMI
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/svghmi/__init__.py Mon Jul 15 09:05:00 2019 +0200
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# This file is part of Beremiz
+# Copyright (C) 2019: Edouard TISSERANT
+#
+# See COPYING file for copyrights details.
+
+from __future__ import absolute_import
+from svghmi.svghmi import *
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/svghmi/pous.xml Mon Jul 15 09:05:00 2019 +0200
@@ -0,0 +1,55 @@
+<?xml version='1.0' encoding='utf-8'?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.plcopen.org/xml/tc6_0201" xmlns:xhtml="http://www.w3.org/1999/xhtml" xsi:schemaLocation="http://www.plcopen.org/xml/tc6_0201">
+ <fileHeader companyName="Beremiz" productName="Beremiz" productVersion="0.0" creationDateTime="2008-12-14T16:53:26"/>
+ <contentHeader name="Beremiz non-standard POUs library" modificationDateTime="2019-07-09T11:05:01">
+ <coordinateInfo>
+ <fbd>
+ <scaling x="0" y="0"/>
+ </fbd>
+ <ld>
+ <scaling x="0" y="0"/>
+ </ld>
+ <sfc>
+ <scaling x="0" y="0"/>
+ </sfc>
+ </coordinateInfo>
+ </contentHeader>
+ <types>
+ <dataTypes>
+ <dataType name="HMI_INT">
+ <baseType>
+ <INT/>
+ </baseType>
+ </dataType>
+ <dataType name="HMI_REAL">
+ <baseType>
+ <REAL/>
+ </baseType>
+ </dataType>
+ <dataType name="HMI_STRING">
+ <baseType>
+ <STRING/>
+ </baseType>
+ </dataType>
+ <dataType name="HMI_BOOL">
+ <baseType>
+ <BOOL/>
+ </baseType>
+ </dataType>
+ <dataType name="HMI_CLASS">
+ <baseType>
+ <BOOL/>
+ </baseType>
+ </dataType>
+ <dataType name="HMI_LABEL">
+ <baseType>
+ <BOOL/>
+ </baseType>
+ </dataType>
+ </dataTypes>
+ <pous/>
+ </types>
+ <instances>
+ <configurations/>
+ </instances>
+</project>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/svghmi/svghmi.py Mon Jul 15 09:05:00 2019 +0200
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# This file is part of Beremiz
+# Copyright (C) 2019: Edouard TISSERANT
+#
+# See COPYING file for copyrights details.
+
+from __future__ import absolute_import
+import os
+import shutil
+
+import wx
+
+import util.paths as paths
+from POULibrary import POULibrary
+from docutil import open_svg
+
+
+class SVGHMILibrary(POULibrary):
+ def GetLibraryPath(self):
+ return paths.AbsNeighbourFile(__file__, "pous.xml")
+
+
+class SVGHMI(object):
+ XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="SVGHMI">
+ <xsd:complexType>
+ <xsd:attribute name="enableHTTP" type="xsd:boolean" use="optional" default="false"/>
+ <xsd:attribute name="bindAddress" type="xsd:string" use="optional" default="localhost"/>
+ <xsd:attribute name="port" type="xsd:string" use="optional" default="8080"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ """
+
+ ConfNodeMethods = [
+ {
+ "bitmap": "ImportSVG",
+ "name": _("Import SVG"),
+ "tooltip": _("Import SVG"),
+ "method": "_ImportSVG"
+ },
+ {
+ "bitmap": "ImportSVG", # should be something different
+ "name": _("Inkscape"),
+ "tooltip": _("Edit HMI"),
+ "method": "_StartInkscape"
+ },
+ ]
+
+ def _getSVGpath(self, project_path=None):
+ if project_path is None:
+ project_path = self.CTNPath()
+ # define name for SVG file containing gui layout
+ return os.path.join(project_path, "gui.svg")
+
+
+ def OnCTNSave(self, from_project_path=None):
+ if from_project_path is not None:
+ shutil.copyfile(self._getSVGpath(from_project_path),
+ self._getSVGpath())
+ return PythonFileCTNMixin.OnCTNSave(self, from_project_path)
+
+ def CTNGenerate_C(self, buildpath, locations):
+ """
+ Return C code generated by iec2c compiler
+ when _generate_softPLC have been called
+ @param locations: ignored
+ @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
+ """
+
+ # TODO : get variable list from Controller
+ # self.GetCTRoot().blah
+ # TODO deduce HMI tree
+
+ svgfile = self._getSVGpath()
+ if os.path.exists(svgfile):
+ # TODO : call xslt transform on Inkscape's SVG to generate
+ # - Errors on HMI semantics
+ # - Target XHTML as a DOM
+ # - ... maybe something to have a global view of what is declared in SVG.
+ pass
+ else:
+ # TODO : use default svg that expose the HMI tree as-is
+ pass
+
+
+ res = ([], "", False)
+
+ targetpath = os.path.join(self._getBuildPath(), "target.xhtml")
+ targetfile = open(targetpath, 'w')
+
+ # TODO : DOM to string
+ targetfile.write("TODO")
+ targetfile.close()
+ res += (("target.js", open(targetpath, "rb")),)
+
+ # TODO add C code to expose HMI tree variables to shared memory
+ # TODO generate a description of shared memory (xml or CSV)
+ # that can be loaded by svghmi QTWeb* app or svghmi server
+
+
+ return res
+
+ def _ImportSVG(self):
+ dialog = wx.FileDialog(self.GetCTRoot().AppFrame, _("Choose a SVG file"), os.getcwd(), "", _("SVG files (*.svg)|*.svg|All files|*.*"), wx.OPEN)
+ if dialog.ShowModal() == wx.ID_OK:
+ svgpath = dialog.GetPath()
+ if os.path.isfile(svgpath):
+ shutil.copy(svgpath, self._getSVGpath())
+ else:
+ self.GetCTRoot().logger.write_error(_("No such SVG file: %s\n") % svgpath)
+ dialog.Destroy()
+
+ def _StartInkscape(self):
+ svgfile = self._getSVGpath()
+ open_inkscape = True
+ if not self.GetCTRoot().CheckProjectPathPerm():
+ dialog = wx.MessageDialog(self.GetCTRoot().AppFrame,
+ _("You don't have write permissions.\nOpen Inkscape anyway ?"),
+ _("Open Inkscape"),
+ wx.YES_NO | wx.ICON_QUESTION)
+ open_inkscape = dialog.ShowModal() == wx.ID_YES
+ dialog.Destroy()
+ if open_inkscape:
+ if not os.path.isfile(svgfile):
+ svgfile = None
+ open_svg(svgfile)