# HG changeset patch # User Edouard Tisserant # Date 1562925502 -7200 # Node ID 535eb0b8bd9d32c8ddbf1d6125c5f7358a99f66f # Parent 26ba948a2e51bade47cd1fbb037bc53a8b2a66b7 Skeleton for svghmi extension diff -r 26ba948a2e51 -r 535eb0b8bd9d svghmi/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/svghmi/README Fri Jul 12 11:58:22 2019 +0200 @@ -0,0 +1,1 @@ +SVG HMI diff -r 26ba948a2e51 -r 535eb0b8bd9d svghmi/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/svghmi/__init__.py Fri Jul 12 11:58:22 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 * diff -r 26ba948a2e51 -r 535eb0b8bd9d svghmi/pous.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/svghmi/pous.xml Fri Jul 12 11:58:22 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> diff -r 26ba948a2e51 -r 535eb0b8bd9d svghmi/svghmi.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/svghmi/svghmi.py Fri Jul 12 11:58:22 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)