plugins/svgui/svgui.py
author etisserant
Sat, 24 May 2008 15:55:19 +0200
changeset 154 f3134b2c6d92
parent 147 ccc5e683583d
child 158 771578d7580e
permissions -rw-r--r--
Fixed killing app on Linux in wxPopen. Do not use shell anymore. Command line is splitted into args, taking care of double and simple cotes. To be tested on win32.
import os, shutil, sys
base_folder = os.path.split(sys.path[0])[0]
sys.path.append(os.path.join(base_folder, "wxsvg", "SVGUIEditor"))
sys.path.append(os.path.join(base_folder, "plcopeneditor", "graphics"))

import wx

from SVGUIGenerator import *
from SVGUIControler import *
from SVGUIEditor import *
from FBD_Objects import *

from wxPopen import ProcessLogger

[ID_SVGUIEDITORFBDPANEL, 
] = [wx.NewId() for _init_ctrls in range(1)]

SVGUIFB_Types = {ITEM_CONTAINER : "Container",
                 ITEM_BUTTON : "Button", 
                 ITEM_TEXT : "TextCtrl", 
                 ITEM_SCROLLBAR : "ScrollBar", 
                 ITEM_ROTATING : "RotatingCtrl", 
                 ITEM_NOTEBOOK : "NoteBook", 
                 ITEM_TRANSFORM : "Transform"}

class _SVGUIEditor(SVGUIEditor):
    """
    This Class add IEC specific features to the SVGUIEditor :
        - FDB preview
        - FBD begin drag 
    """
    
    def _init_coll_EditorGridSizer_Items(self, parent):
        SVGUIEditor._init_coll_EditorGridSizer_Items(self, parent)
        parent.AddWindow(self.FBDPanel, 0, border=0, flag=wx.GROW)
    
    def _init_ctrls(self, prnt):
        SVGUIEditor._init_ctrls(self, prnt, False)
        
        self.FBDPanel = wx.Panel(id=ID_SVGUIEDITORFBDPANEL, 
                  name='FBDPanel', parent=self.EditorPanel, pos=wx.Point(0, 0),
                  size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL|wx.SIMPLE_BORDER)
        self.FBDPanel.SetBackgroundColour(wx.WHITE)
        self.FBDPanel.Bind(wx.EVT_LEFT_DOWN, self.OnFBDPanelClick)
        self.FBDPanel.Bind(wx.EVT_PAINT, self.OnPaintFBDPanel)
        
        setattr(self.FBDPanel, "GetScaling", lambda: None) 
        
        self._init_sizers()
    
    def __init__(self, parent, controler = None, fileOpen = None):
        SVGUIEditor.__init__(self, parent, controler, fileOpen)
        
        self.FBDBlock = None
    
    def RefreshView(self, select_id = None):
        SVGUIEditor.RefreshView(self, select_id)
        self.FBDPanel.Refresh()
    
    def OnPaintFBDPanel(self,event):
        dc = wx.ClientDC(self.FBDPanel)
        dc.Clear()
        selected = self.GetSelected()
        if selected is not None:
            selected_type = self.Controler.GetElementType(selected)
            if selected_type is not None:
                self.FBDBlock = FBD_Block(parent=self.FBDPanel,type=SVGUIFB_Types[selected_type],name=self.Controler.GetElementName(selected))
                width, height = self.FBDBlock.GetMinSize()
                self.FBDBlock.SetSize(width,height)
                clientsize = self.FBDPanel.GetClientSize()
                x = (clientsize.width - width) / 2
                y = (clientsize.height - height) / 2
                self.FBDBlock.SetPosition(x, y)
                self.FBDBlock.Draw(dc)
        else:
            self.FBDBlock = None
        event.Skip()
        
    def OnFBDPanelClick(self, event):
        if self.FBDBlock:
            data = wx.TextDataObject(str((self.FBDBlock.GetType(), "functionBlock", self.FBDBlock.GetName())))
            DropSrc = wx.DropSource(self.FBDPanel)
            DropSrc.SetData(data)
            DropSrc.DoDragDrop()
        event.Skip()
    
    def OnInterfaceTreeItemSelected(self, event):
        self.FBDPanel.Refresh()
        SVGUIEditor.OnInterfaceTreeItemSelected(self, event)
    
    def OnGenerate(self,event):
        self.SaveProject()
        self.Controler.PlugGenerate_C(sys.path[0],(0,0,4,5),None)
        event.Skip()    
    
TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L",
    "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", "REAL" : "D", "LREAL" : "L",
    "STRING" : "B", "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L", "WSTRING" : "W"}

CTYPECONVERSION = {"BOOL" : "IEC_BOOL", "UINT" : "IEC_UINT", "STRING" : "IEC_STRING", "REAL" : "IEC_REAL"}
CPRINTTYPECONVERSION = {"BOOL" : "d", "UINT" : "d", "STRING" : "s", "REAL" : "f"}

class RootClass(SVGUIControler):

    def __init__(self):
        SVGUIControler.__init__(self)
        filepath = os.path.join(self.PlugPath(), "gui.xml")
        
        if os.path.isfile(filepath):
            svgfile = os.path.join(self.PlugPath(), "gui.svg")
            if os.path.isfile(svgfile):
                self.SvgFilepath = svgfile
            self.OpenXMLFile(filepath)
        else:
            self.CreateNewInterface()
            self.SetFilePath(filepath)

    def GetElementIdFromName(self, name):
        element = self.GetElementByName(name)
        if element is not None:
            return element.getid()
        return None

    _View = None
    def _OpenView(self, logger):
        if not self._View:
            def _onclose():
                self._View = None
            def _onsave():
                self.GetPlugRoot().SaveProject()
            self._View = _SVGUIEditor(self.GetPlugRoot().AppFrame, self)
            self._View._onclose = _onclose
            self._View._onsave = _onsave
            self._View.Show()

    def _ImportSVG(self, logger):
        if not self._View:
            dialog = wx.FileDialog(self.GetPlugRoot().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, os.path.join(self.PlugPath(), "gui.svg"))
                else:
                    logger.write_error("No such SVG file: %s\n"%svgpath)
            dialog.Destroy()

    def _ImportXML(self, logger):
        if not self._View:
            dialog = wx.FileDialog(self.GetPlugRoot().AppFrame, "Choose a XML file", os.getcwd(), "",  "XML files (*.xml)|*.xml|All files|*.*", wx.OPEN)
            if dialog.ShowModal() == wx.ID_OK:
                xmlpath = dialog.GetPath()
                if os.path.isfile(xmlpath):
                    shutil.copy(xmlpath, os.path.join(self.PlugPath(), "gui.xml"))
                else:
                    logger.write_error("No such XML file: %s\n"%xmlpath)
            dialog.Destroy()

    PluginMethods = [
        {"bitmap" : os.path.join("images","HMIEditor"),
         "name" : "HMI Editor",
         "tooltip" : "HMI Editor",
         "method" : "_OpenView"},
        {"bitmap" : os.path.join("images","ImportSVG"),
         "name" : "Import SVG",
         "tooltip" : "Import SVG",
         "method" : "_ImportSVG"},
        {"bitmap" : os.path.join("images","ImportDEF"),
         "name" : "Import XML",
         "tooltip" : "Import XML",
         "method" : "_ImportXML"},
    ]
    
    def OnPlugSave(self):
        self.SaveXMLFile()
        return True
    
    def PlugGenerate_C(self, buildpath, locations, logger):
        progname = "SVGUI_%s"%"_".join(map(str, self.GetCurrentLocation()))
        
        generator = _SVGUICGenerator(self.GetElementsByType(), self.GetSVGFilePath(), self.GetFilePath(), self.GetCurrentLocation())
        generator.GenerateProgram((0, 0), buildpath, progname)
        Gen_C_file = os.path.join(buildpath, progname+".cpp" )
        
        if wx.Platform == '__WXMSW__':
            cxx_flags = "-I..\\..\\wxPython-src-2.8.7.1\\bld\\lib\\wx\\include\\msw-unicode-release-2.8 -I..\\..\\wxPython-src-2.8.7.1\\include -I..\\..\\wxPython-src-2.8.7.1\\contrib\\include -I..\\..\\matiec\\lib -DWXUSINGDLL -D__WXMSW__ -mthreads"
            libs = "\"..\\lib\\libwxsvg.a\" \"..\\lib\\libwxsvg_agg.a\" \"..\\lib\\libagg.a\" \"..\\lib\\libaggplatformwin32.a\" \"..\\lib\\libaggfontwin32tt.a\" -L..\\..\\wxPython-src-2.8.7.1\\bld\\lib -mno-cygwin -mwindows -mthreads  -mno-cygwin -mwindows -Wl,--subsystem,windows -mwindows -lwx_mswu_richtext-2.8 -lwx_mswu_aui-2.8 -lwx_mswu_xrc-2.8 -lwx_mswu_qa-2.8 -lwx_mswu_html-2.8 -lwx_mswu_adv-2.8 -lwx_mswu_core-2.8 -lwx_baseu_xml-2.8 -lwx_baseu_net-2.8 -lwx_baseu-2.8"
        else:
            status, result, err_result = ProcessLogger(logger, "wx-config --cxxflags", no_stdout=True).spin()
            if status:
                logger.write_error("Unable to get wx cxxflags\n")
            cxx_flags = result.strip() + " -I../matiec/lib"
            
            status, result, err_result = ProcessLogger(logger, "wx-config --libs", no_stdout=True).spin()
            if status:
                logger.write_error("Unable to get wx libs\n")
            libs = result.strip() + " -lwxsvg"
        
        return [(Gen_C_file, cxx_flags)],libs,True
    
    def BlockTypesFactory(self):
        def generate_svgui_block(generator, block, body, link, order=False):
            name = block.getinstanceName()
            block_id = self.GetElementIdFromName(name)
            if block_id == None:
                raise ValueError, "No corresponding block found"
            type = block.gettypeName()
            block_infos = GetBlockType(type)
            current_location = ".".join(map(str, self.GetCurrentLocation()))
            if not generator.ComputedBlocks.get(name, False) and not order:
                generator.ComputedBlocks[block] = True
                for num, variable in enumerate(block.inputVariables.getvariable()):
                    connections = variable.connectionPointIn.getconnections()
                    if connections and len(connections) == 1:
                        parameter = "%sQ%s%s.%d.%d"%("%", TYPECONVERSION[block_infos["inputs"][num][1]], current_location, block_id, num+1)
                        value = generator.ComputeFBDExpression(body, connections[0])
                        generator.Program += ("  %s := %s;\n"%(parameter, generator.ExtractModifier(variable, value)))
            if link:
                connectionPoint = link.getposition()[-1]
                for num, variable in enumerate(block.outputVariables.getvariable()):
                    blockPointx, blockPointy = variable.connectionPointOut.getrelPositionXY()
                    if block.getx() + blockPointx == connectionPoint.getx() and block.gety() + blockPointy == connectionPoint.gety():
                        return "%sI%s%s.%d.%d"%("%", TYPECONVERSION[block_infos["outputs"][num][1]], current_location, block_id, num+1)
                raise ValueError, "No output variable found"
            else:
                return None

        def initialise_block(type, name, block = None):
            block_id = self.GetElementIdFromName(name)
            if block_id == None:
                raise ValueError, "No corresponding block found"
            block_infos = GetBlockType(type)
            current_location = ".".join(map(str, self.GetCurrentLocation()))
            variables = []
            if block is not None:
                input_variables = block.inputVariables.getvariable()
                output_variables = block.outputVariables.getvariable()
            else:
                input_variables = None
                output_variables = None
            for num, (input_name, input_type, input_modifier) in enumerate(block_infos["inputs"]):
                if input_variables is not None and num < len(input_variables):
                    connections = input_variables[num].connectionPointIn.getconnections()
                if input_variables is None or connections and len(connections) == 1:
                    variables.append((input_type, None, "%sQ%s%s.%d.%d"%("%", TYPECONVERSION[input_type], current_location, block_id, num+1), None))
            for num, (output_name, output_type, output_modifier) in enumerate(block_infos["outputs"]):
                variables.append((output_type, None, "%sI%s%s.%d.%d"%("%", TYPECONVERSION[input_type], current_location, block_id, num+1), None))
            return variables

        return [{"name" : "SVGUI function blocks", "list" :
                [{"name" : "Container", "type" : "functionBlock", "extensible" : False, 
                    "inputs" : [("Show","BOOL","none"),("Enable","BOOL","none")], 
                    "outputs" : [],
                    "comment" : "SVGUI Container",
                    "generate" : generate_svgui_block, "initialise" : initialise_block},
                {"name" : "Button", "type" : "functionBlock", "extensible" : False, 
                    "inputs" : [("Show","BOOL","none"),("Enable","BOOL","none"),("Toggle","BOOL","none")], 
                    "outputs" : [("State","BOOL","none")],
                    "comment" : "SVGUI Button",
                    "generate" : generate_svgui_block, "initialise" : initialise_block},
                {"name" : "TextCtrl", "type" : "functionBlock", "extensible" : False, 
                    "inputs" : [("Show","BOOL","none"),("Enable","BOOL","none"),("SetText","STRING","none")], 
                    "outputs" : [("Text","STRING","none")],
                    "comment" : "SVGUI Text Control",
                    "generate" : generate_svgui_block, "initialise" : initialise_block},
                {"name" : "ScrollBar", "type" : "functionBlock", "extensible" : False, 
                    "inputs" : [("Show","BOOL","none"),("Enable","BOOL","none"),("SetThumb","UINT","none"),("SetRange","UINT","none"),("SetPosition","UINT","none")], 
                    "outputs" : [("Position","UINT","none")],
                    "comment" : "SVGUI ScrollBar",
                    "generate" : generate_svgui_block, "initialise" : initialise_block},
                {"name" : "NoteBook", "type" : "functionBlock", "extensible" : False, 
                    "inputs" : [("Show","BOOL","none"),("Enable","BOOL","none"),("SetSelected","BOOL","none")], 
                    "outputs" : [("Selected","UINT","none")],
                    "comment" : "SVGUI Notebook",
                    "generate" : generate_svgui_block, "initialise" : initialise_block},
                {"name" : "RotatingCtrl", "type" : "functionBlock", "extensible" : False, 
                    "inputs" : [("Show","BOOL","none"),("Enable","BOOL","none"),("SetAngle","REAL","none")], 
                    "outputs" : [("Angle","REAL","none")],
                    "comment" : "SVGUI Rotating Control",
                    "generate" : generate_svgui_block, "initialise" : initialise_block},
                {"name" : "Transform", "type" : "functionBlock", "extensible" : False, 
                    "inputs" : [("Show","BOOL","none"),("Enable","BOOL","none"),("SetX","REAL","none"),("SetY","REAL","none"),("SetXScale","REAL","none"),("SetYScale","REAL","none"),("SetAngle","REAL","none")], 
                    "outputs" : [("X","REAL","none"),("Y","REAL","none")],
                    "comment" : "SVGUI Transform",
                    "generate" : generate_svgui_block, "initialise" : initialise_block},
               ]}
        ]



class _SVGUICGenerator(SVGUICGenerator):

    def __init__(self, elements, svgfile, xmlfile, current_location):
        SVGUICGenerator.__init__(self, elements, svgfile, xmlfile)
        
        self.CurrentLocation = current_location

    def GenerateProgramHeadersPublicVars(self):
        text = """    void OnPlcOutEvent(wxEvent& event);

    void Retrieve();
    void Publish();
    void Initialize();
"""
#        text += "    void Print();\n"
        return text
    
    def GenerateIECVars(self):
        text = ""
        for element in self.Elements:
            text += "STATE_TYPE out_state_%d;\n"%element.getid()
            text += "STATE_TYPE in_state_%d;\n"%element.getid()
        text +="\n"
        current_location = "_".join(map(str, self.CurrentLocation))
        #Declaration des variables
        for element in self.Elements:
            block_infos = GetBlockType(SVGUIFB_Types[GetElementType(element)])
            block_id = element.getid()
            for i, input in enumerate(block_infos["inputs"]):
                element_c_type = CTYPECONVERSION[input[1]]
                variable = "__Q%s%s_%d_%d"%(TYPECONVERSION[input[1]], current_location, block_id, i + 1)
                text += "%s %s;\n"%(element_c_type, variable)
                text += "%s _copy%s;\n"%(element_c_type, variable)
            for i, output in enumerate(block_infos["outputs"]):
                element_c_type = CTYPECONVERSION[output[1]]
                variable = "__I%s%s_%d_%d"%(TYPECONVERSION[output[1]], current_location, block_id, i + 1)
                text += "%s %s;\n"%(element_c_type, variable)
                text += "%s _copy%s;\n"%(element_c_type, variable)
            text +="\n"
        return text
    
    def GenerateGlobalVarsAndFuncs(self, size):
        text = """#include \"iec_types.h\"

#ifdef __WXMSW__
#define COMPARE_AND_SWAP_VAL(Destination, comparand, exchange) InterlockedCompareExchange(Destination, exchange, comparand)
#define THREAD_RETURN_TYPE DWORD WINAPI
#define STATE_TYPE long int
#else
#define COMPARE_AND_SWAP_VAL(Destination, comparand, exchange) __sync_val_compare_and_swap(Destination, comparand, exchange)
#define THREAD_RETURN_TYPE void*
#define STATE_TYPE volatile int
#endif

"""
        
        text += self.GenerateIECVars()
        
        text += """IMPLEMENT_APP_NO_MAIN(SVGViewApp);
IMPLEMENT_WX_THEME_SUPPORT;
SVGViewApp *myapp = NULL;

#ifdef __WXMSW__
HANDLE wxMainLoop;
DWORD wxMainLoopId;
#else
pthread_t wxMainLoop;
#endif

"""

#        text += "pthread_t wxMainLoop,automate;\n"
        text += """int myargc = 0;
char** myargv = NULL;
        
#define UNCHANGED 1
#define PLC_BUSY 2
#define CHANGED 3
#define GUI_BUSY 4
#ifdef __WXMSW__
#else
#endif

bool refresh = false;
bool refreshing = false;

THREAD_RETURN_TYPE InitWxEntry(void* args)
{
  wxEntry(myargc,myargv);
  return 0;
}

"""
#        text += """void* SimulAutomate(void* args)
#{
#  while(1){
#    myapp->frame->m_svgCtrl->IN_"+self.BusNumber+"();
#    //printf(\"AUTOMATE\\n\");
#    myapp->frame->m_svgCtrl->OUT_"+self.BusNumber+"();
#    sleep(1);
#  }
#  return args;
#}
#
#"""
      
        text += """bool SVGViewApp::OnInit()
{
  #ifndef __WXMSW__
    setlocale(LC_NUMERIC, "C");
  #endif
"""
        #text += "  frame = new MainFrame(NULL, wxT(\"Program\"),wxDefaultPosition, wxSize(%d, %d));\n"%size
        text += """  frame = new MainFrame(NULL, wxT("Program"),wxDefaultPosition, wxDefaultSize);
  frame->Show();
  myapp = this;
"""
#        text += "  pthread_create(&automate, NULL, SimulAutomate, NULL);\n"
        text += """  return true;
}

extern "C" {

int __init_%(location)s(int argc, char** argv)
{
  myargc = argc;
  myargv = argv;
#ifdef __WXMSW__
  wxMainLoop = CreateThread(NULL, 0, InitWxEntry, 0, 0, &wxMainLoopId);
#else
  pthread_create(&wxMainLoop, NULL, InitWxEntry, NULL);
#endif
  return 0;
}

void __cleanup_%(location)s()
{
}

void __retrieve_%(location)s()
{
  if(myapp){
    myapp->frame->m_svgCtrl->Retrieve();
  }        
}

void __publish_%(location)s()
{
  if(myapp){
    myapp->frame->m_svgCtrl->Publish();
  }
}

}

IEC_STRING wxStringToIEC_STRING(wxString s)
{
  IEC_STRING res = {0,""};
  int i;
  for(i = 0; i<s.Length() && i<STR_MAX_LEN; i++)
    res.body[i] = s.GetChar(i);
  res.len = i;
  return res;
}

"""%{"location" : "_".join(map(str, self.CurrentLocation))}
        
        return text
    
    def GenerateProgramEventTable(self):
        text = """BEGIN_DECLARE_EVENT_TYPES()
DECLARE_LOCAL_EVENT_TYPE( EVT_PLC, wxNewEventType() )
END_DECLARE_EVENT_TYPES()
         
DEFINE_LOCAL_EVENT_TYPE( EVT_PLC )

"""     
        #Event Table Declaration
        text += "BEGIN_EVENT_TABLE(Program, SVGUIWindow)\n"
        for element in self.Elements:
            element_type = GetElementType(element)
            element_name = element.getname()
            if element_type == ITEM_BUTTON:
                text += "  EVT_BUTTON (SVGUIID(\"%s\"), Program::On%sClick)\n"%(element_name, element_name)
            elif element_type in [ITEM_SCROLLBAR, ITEM_ROTATING, ITEM_TRANSFORM]:
                text += "  EVT_COMMAND_SCROLL_THUMBTRACK (SVGUIID(\"%s\"), Program::On%sChanging)\n"%(element_name, element_name)
            elif element_type == ITEM_NOTEBOOK:
                text += "  EVT_NOTEBOOK_PAGE_CHANGED (SVGUIID(\"%s\"), Program::On%sTabChanged)\n"%(element_name, element_name)
        text += "  EVT_CUSTOM(EVT_PLC, wxID_ANY, Program::OnPlcOutEvent)\n"
        text += "END_EVENT_TABLE()\n\n"
        return text
    
    def GenerateProgramInitFrame(self):
        text = """MainFrame::MainFrame(wxWindow *parent, const wxString& title, const wxPoint& pos,const wxSize& size, long style): wxFrame(parent, wxID_ANY, title, pos, size, style)
{
  m_svgCtrl = new Program(this);
  if (m_svgCtrl->LoadFiles(wxT("%s"), wxT("%s")))
  {
    Show(true);
    m_svgCtrl->SetFocus();
    m_svgCtrl->SetFitToFrame(true);
    m_svgCtrl->RefreshScale();
    m_svgCtrl->InitScrollBars();
    m_svgCtrl->Initialize();
    m_svgCtrl->Update();
  }
  else
  {
    printf("Error while opening files\\n");
    exit(0);
  }
}


"""%(self.SVGFilePath, self.XMLFilePath)

        return text
    
    def GenerateProgramInitProgram(self):
        text = "Program::Program(wxWindow* parent):SVGUIWindow(parent)\n{\n"
        for element in self.Elements:
            text += "    out_state_%d = UNCHANGED;\n"%element.getid()
            text += "    in_state_%d = UNCHANGED;\n"%element.getid()
        text += "}\n\n"
        return text
    
    def GenerateProgramEventFunctions(self):
        text = ""
        current_location = "_".join(map(str, self.CurrentLocation))
        for element in self.Elements:
            element_type = GetElementType(element)
            element_lock = """  if (COMPARE_AND_SWAP_VAL(&in_state_%d, CHANGED, GUI_BUSY) == CHANGED ||
      COMPARE_AND_SWAP_VAL(&in_state_%d, UNCHANGED, GUI_BUSY) == UNCHANGED) {
"""%(element.getid(), element.getid())
            element_unlock = """    COMPARE_AND_SWAP_VAL(&in_state_%d, GUI_BUSY, CHANGED);
  }
  else
      ProcessEvent(event);
"""%element.getid()
            element_name = element.getname()
                
            if element_type == ITEM_BUTTON:
                text += """void Program::On%sClick(wxCommandEvent& event)
{
  SVGUIButton* button = (SVGUIButton*)GetElementByName(wxT("%s"));\n"""%(element_name, element_name)
                text += element_lock
                text += "    _copy__IX%s_%d_1 = button->GetToggle();\n"%(current_location, element.getid())
                text += element_unlock
                text += "  event.Skip();\n}\n\n"
            elif element_type == ITEM_ROTATING:
                text += """void Program::On%sChanging(wxScrollEvent& event)
{
  SVGUIRotatingCtrl* rotating = (SVGUIRotatingCtrl*)GetElementByName(wxT("%s"));
"""%(element_name, element_name)
                text += element_lock
                text += "    _copy__ID%s_%d_1 = rotating->GetAngle();\n"%(current_location, element.getid())
                text += element_unlock
                text += "  event.Skip();\n}\n\n"
            elif element_type == ITEM_NOTEBOOK:
                text += """void Program::On%sTabChanged(wxNotebookEvent& event)
{
  SVGUINoteBook* notebook = (SVGUINoteBook*)GetElementByName(wxT("%s"));
"""%(element_name, element_name)
                text += element_lock
                text += "    _copy__IB%s_%d_1 = notebook->GetCurrentPage();\n"%(current_location, element.getid())
                text += element_unlock
                text += "  event.Skip();\n}\n\n"
            elif element_type == ITEM_TRANSFORM:
                text += """void Program::On%sChanging(wxScrollEvent& event)
{
  SVGUITransform* transform = (SVGUITransform*)GetElementByName(wxT("%s"));
"""%(element_name, element_name)
                text += element_lock
                text += "    _copy__ID%s_%d_1 = transform->GetX();\n"%(current_location, element.getid())
                text += "    _copy__ID%s_%d_2 = transform->GetY();\n"%(current_location, element.getid())
                text += element_unlock
                text += "  event.Skip();\n}\n\n"
        
        text += "/* OnPlcOutEvent update GUI with provided IEC __Q* PLC output variables */\n"
        text += """void Program::OnPlcOutEvent(wxEvent& event)
{
  SVGUIElement* element;
  
  refreshing = true;

  wxMutexGuiEnter();
"""
        for element in self.Elements:
            element_type = GetElementType(element)
            texts = {"location" : current_location, "id" : element.getid()}
            
            text += """  if (COMPARE_AND_SWAP_VAL(&out_state_%(id)d, CHANGED, GUI_BUSY) == CHANGED)
  {
    element = (SVGUIElement*)GetElementById(wxT("%(id)d"));
            
    if (_copy__QX%(location)s_%(id)d_1 != element->IsVisible()) {
      if (_copy__QX%(location)s_%(id)d_1)
        element->Show();
      else
        element->Hide();
    }
    if (_copy__QX%(location)s_%(id)d_2 != element->IsEnabled()) {
      if (_copy__QX%(location)s_%(id)d_2)
        element->Enable();
      else
        element->Disable();
    }
"""%texts
            if element_type == ITEM_BUTTON:
                text += """    if (_copy__QX%(location)s_%(id)d_3 != ((SVGUIButton*)element)->GetToggle())
      ((SVGUIButton*)element)->SetToggle(_copy__QX%(location)s_%(id)d_3);
"""%texts
            elif element_type == ITEM_TEXT:
                text += """    if (((SVGUITextCtrl*)element)->GetValue().compare(_copy__QX%(location)s_%(id)d_3))
    {
      wxString str = wxString::FromAscii(_copy__QB%(location)s_%(id)d_3);
      ((SVGUITextCtrl*)element)->SetText(str);
    }
"""%texts
            elif  element_type == ITEM_SCROLLBAR:
                text += """    if (_copy__QW%(location)s_%(id)d_3 != ((SVGUIScrollBar*)element)->GetThumbPosition() ||
        _copy__QW%(location)s_%(id)d_4 != ((SVGUIScrollBar*)element)->GetThumbSize() ||
        _copy__QW%(location)s_%(id)d_5 != ((SVGUIScrollBar*)element)->GetRange())
      ((SVGUIScrollBar*)element)->Init_ScrollBar(_copy__QW%(location)s_%(id)d_3, _copy__QW%(location)s_%(id)d_4, _copy__QW%(location)s_%(id)d_5);
"""%texts
            elif element_type == ITEM_ROTATING:
                text += """    if (_copy__QD%(location)s_%(id)d_3 != ((SVGUIRotatingCtrl*)element)->GetAngle())
      ((SVGUIRotatingCtrl*)element)->SetAngle(_copy__QD%(location)s_%(id)d_3);
"""%texts
            elif element_type == ITEM_NOTEBOOK:
                text += """    if (_copy__QB%(location)s_%(id)d_3 != ((SVGUINoteBook*)element)->GetCurrentPage())
      ((SVGUINoteBook*)element)->SetCurrentPage(_copy__QB%(location)s_%(id)d_3);
"""%texts
            elif element_type == ITEM_TRANSFORM:
                text += """    if (_copy__QD%(location)s_%(id)d_3 != ((SVGUITransform*)element)->GetX() ||
        copy__QD%(location)s_%(id)d_4 != ((SVGUITransform*)element)->GetY())
      transform->Move(_copy__QD%(location)s_%(id)d_3, _copy__QD%(location)s_%(id)d_4);
    if (_copy__QD%(location)s_%(id)d_5 != ((SVGUITransform*)element)->GetXScale() ||
        copy__QD%(location)s_%(id)d_6 != ((SVGUITransform*)element)->GetYScale())
      transform->Scale(_copy__QD%(location)s_%(id)d_5, _copy__QD%(location)s_%(id)d_6);
    if (_copy__QD%(location)s_%(id)d_7 != ((SVGUITransform*)element)->GetAngle())
      transform->Rotate(_copy__QD%(location)s_%(id)d_7);
"""%texts
            text += "    COMPARE_AND_SWAP_VAL(&out_state_%(id)d, GUI_BUSY, UNCHANGED);\n  }\n"%texts
            
        text += """  wxMutexGuiLeave();

  refreshing = false;

  event.Skip();
}

"""
        return text
    
    def GenerateProgramPrivateFunctions(self):
        current_location = "_".join(map(str, self.CurrentLocation))
        
        text = "void Program::Retrieve()\n{\n"
        for element in self.Elements:
            element_type = GetElementType(element)
            texts = {"location" : current_location, "id" : element.getid()}
            block_infos = GetBlockType(SVGUIFB_Types[GetElementType(element)])
            if len(block_infos["outputs"]) > 0:
                text += """  if (COMPARE_AND_SWAP_VAL(&in_state_%(id)d, CHANGED, PLC_BUSY) == CHANGED) {
"""%texts
                for i, output in enumerate(block_infos["outputs"]):
                    texts["type"] = TYPECONVERSION[output[1]]
                    texts["pin"] = i + 1
                    
                    variable = "__I%(type)s%(location)s_%(id)d_%(pin)d"%texts
                    text +="    %s = _copy%s;\n"%(variable, variable)
                
                text += """    COMPARE_AND_SWAP_VAL(&in_state_%(id)d, PLC_BUSY, UNCHANGED);
  }
"""%texts
        text += "}\n\n" 

        text += "void Program::Publish()\n{\n  STATE_TYPE new_state;\n\n"
        for element in self.Elements:
            element_type = GetElementType(element)
            texts = {"location" : current_location, "id" : element.getid()}
            block_infos = GetBlockType(SVGUIFB_Types[GetElementType(element)])
            
            text += """  if ((new_state = COMPARE_AND_SWAP_VAL(&out_state_%(id)d, UNCHANGED, PLC_BUSY)) == UNCHANGED ||
       (new_state = COMPARE_AND_SWAP_VAL(&out_state_%(id)d, CHANGED, PLC_BUSY)) == CHANGED) {
"""%texts
            for i, input in enumerate(block_infos["inputs"]):
                texts["type"] = TYPECONVERSION[input[1]]
                texts["pin"] = i + 1
                variable = "__Q%(type)s%(location)s_%(id)d_%(pin)d"%texts
                text += "    if (_copy%s != %s) {\n"%(variable, variable)
                text += "      _copy%s = %s;\n"%(variable, variable)
                text += "      new_state = CHANGED;\n    }\n"%texts
            text += """    COMPARE_AND_SWAP_VAL(&out_state_%(id)d, PLC_BUSY, new_state);
    refresh |= new_state == CHANGED;
  }
"""%texts
        
        text += """  /* Replace this with determinist signal if called from RT */
  if (refresh && !refreshing) {
    wxCommandEvent event( EVT_PLC );
    ProcessEvent(event);
    refresh = false;
  }
};

"""

        text += """void Program::Initialize()
{
  SVGUIElement* element;
"""
        for element in self.Elements:
            element_type = GetElementType(element)
            texts = {"location" : current_location, "id" : element.getid()}
            
            text += """
  element = (SVGUIElement*)GetElementById(wxT("%(id)d"));
  __QX%(location)s_%(id)d_1 = 1;
  _copy__QX%(location)s_%(id)d_1 = 1;
  __QX%(location)s_%(id)d_2 = 1;
  _copy__QX%(location)s_%(id)d_2 = 1;
"""%texts
            if element_type == ITEM_BUTTON:
                text += "  _copy__IX%(location)s_%(id)d_1 = ((SVGUIButton*)element)->GetToggle();\n"%texts
            elif element_type == ITEM_TEXT:
                text += "  _copy__IB%(location)s_%(id)d_1 = ((SVGUITextCtrl*)element)->GetValue();\n"%texts
            elif element_type == ITEM_SCROLLBAR:
                text += "  _copy__IW%(location)s_%(id)d_1 = ((SVGUIScrollBar*)element)->GetThumbPosition();\n"%texts
            elif element_type == ITEM_ROTATING:
                text += "  _copy__ID%(location)s_%(id)d_1 = ((SVGUIRotatingCtrl*)element)->GetAngle();\n"%texts
            elif element_type == ITEM_NOTEBOOK:
                text += "  _copy__IB%(location)s_%(id)d_1 = ((SVGUINoteBook*)element)->GetCurrentPage();\n"%texts
            elif element_type == ITEM_TRANSFORM:
                text += "  _copy__ID%(location)s_%(id)d_1 = ((SVGUITransform*)element)->GetX();\n"%texts
                text += "  _copy__ID%(location)s_%(id)d_2 = ((SVGUITransform*)element)->GetY();\n"%texts
        text += "}\n\n"
        
        return text