editors/ConfTreeNodeEditor.py
changeset 814 5743cbdff669
parent 781 cdc6393705ce
child 840 980863738cf6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/editors/ConfTreeNodeEditor.py	Fri Sep 07 16:45:55 2012 +0200
@@ -0,0 +1,573 @@
+
+import os
+import types
+
+import wx
+import wx.lib.buttons
+
+from EditorPanel import EditorPanel
+
+from IDEFrame import TITLE, FILEMENU, PROJECTTREE, PAGETITLES
+
+from controls import TextCtrlAutoComplete
+from dialogs import BrowseValuesLibraryDialog
+from util.BitmapLibrary import GetBitmap
+
+if wx.Platform == '__WXMSW__':
+    faces = { 'times': 'Times New Roman',
+              'mono' : 'Courier New',
+              'helv' : 'Arial',
+              'other': 'Comic Sans MS',
+              'size' : 16,
+             }
+else:
+    faces = { 'times': 'Times',
+              'mono' : 'Courier',
+              'helv' : 'Helvetica',
+              'other': 'new century schoolbook',
+              'size' : 18,
+             }
+
+SCROLLBAR_UNIT = 10
+WINDOW_COLOUR = wx.Colour(240, 240, 240)
+
+CWD = os.path.split(os.path.realpath(__file__))[0]
+
+def Bpath(*args):
+    return os.path.join(CWD,*args)
+
+# Some helpers to tweak GenBitmapTextButtons
+# TODO: declare customized classes instead.
+gen_mini_GetBackgroundBrush = lambda obj:lambda dc: wx.Brush(obj.GetParent().GetBackgroundColour(), wx.SOLID)
+gen_textbutton_GetLabelSize = lambda obj:lambda:(wx.lib.buttons.GenButton._GetLabelSize(obj)[:-1] + (False,))
+
+def make_genbitmaptogglebutton_flat(button):
+    button.GetBackgroundBrush = gen_mini_GetBackgroundBrush(button)
+    button.labelDelta = 0
+    button.SetBezelWidth(0)
+    button.SetUseFocusIndicator(False)
+
+# Patch wx.lib.imageutils so that gray is supported on alpha images
+import wx.lib.imageutils
+from wx.lib.imageutils import grayOut as old_grayOut
+def grayOut(anImage):
+    if anImage.HasAlpha():
+        AlphaData = anImage.GetAlphaData()
+    else :
+        AlphaData = None
+
+    old_grayOut(anImage)
+
+    if AlphaData is not None:
+        anImage.SetAlphaData(AlphaData)
+
+wx.lib.imageutils.grayOut = grayOut
+
+class GenBitmapTextButton(wx.lib.buttons.GenBitmapTextButton):
+    def _GetLabelSize(self):
+        """ used internally """
+        w, h = self.GetTextExtent(self.GetLabel())
+        if not self.bmpLabel:
+            return w, h, False       # if there isn't a bitmap use the size of the text
+
+        w_bmp = self.bmpLabel.GetWidth()+2
+        h_bmp = self.bmpLabel.GetHeight()+2
+        height = h + h_bmp
+        if w_bmp > w:
+            width = w_bmp
+        else:
+            width = w
+        return width, height, False
+
+    def DrawLabel(self, dc, width, height, dw=0, dy=0):
+        bmp = self.bmpLabel
+        if bmp != None:     # if the bitmap is used
+            if self.bmpDisabled and not self.IsEnabled():
+                bmp = self.bmpDisabled
+            if self.bmpFocus and self.hasFocus:
+                bmp = self.bmpFocus
+            if self.bmpSelected and not self.up:
+                bmp = self.bmpSelected
+            bw,bh = bmp.GetWidth(), bmp.GetHeight()
+            if not self.up:
+                dw = dy = self.labelDelta
+            hasMask = bmp.GetMask() != None
+        else:
+            bw = bh = 0     # no bitmap -> size is zero
+
+        dc.SetFont(self.GetFont())
+        if self.IsEnabled():
+            dc.SetTextForeground(self.GetForegroundColour())
+        else:
+            dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
+
+        label = self.GetLabel()
+        tw, th = dc.GetTextExtent(label)        # size of text
+        if not self.up:
+            dw = dy = self.labelDelta
+
+        pos_x = (width-bw)/2+dw      # adjust for bitmap and text to centre
+        pos_y = (height-bh-th)/2+dy
+        if bmp !=None:
+            dc.DrawBitmap(bmp, pos_x, pos_y, hasMask) # draw bitmap if available
+            pos_x = (width-tw)/2+dw      # adjust for bitmap and text to centre
+            pos_y += bh + 2
+
+        dc.DrawText(label, pos_x, pos_y)      # draw the text
+
+
+class GenStaticBitmap(wx.lib.statbmp.GenStaticBitmap):
+    """ Customized GenStaticBitmap, fix transparency redraw bug on wx2.8/win32, 
+    and accept image name as __init__ parameter, fail silently if file do not exist"""
+    def __init__(self, parent, ID, bitmapname,
+                 pos = wx.DefaultPosition, size = wx.DefaultSize,
+                 style = 0,
+                 name = "genstatbmp"):
+        
+        wx.lib.statbmp.GenStaticBitmap.__init__(self, parent, ID, 
+                 GetBitmap(bitmapname),
+                 pos, size,
+                 style,
+                 name)
+        
+    def OnPaint(self, event):
+        dc = wx.PaintDC(self)
+        colour = self.GetParent().GetBackgroundColour()
+        dc.SetPen(wx.Pen(colour))
+        dc.SetBrush(wx.Brush(colour ))
+        dc.DrawRectangle(0, 0, *dc.GetSizeTuple())
+        if self._bitmap:
+            dc.DrawBitmap(self._bitmap, 0, 0, True)
+
+class ConfTreeNodeEditor(EditorPanel):
+    
+    SHOW_BASE_PARAMS = True
+    SHOW_PARAMS = True
+    
+    def _init_ConfNodeEditor(self, prnt):
+        self.ConfNodeEditor = None
+    
+    def _init_Editor(self, parent):
+        self.Editor = wx.SplitterWindow(parent,
+              style=wx.SUNKEN_BORDER|wx.SP_3D)
+        self.SetNeedUpdating(True)
+        self.SetMinimumPaneSize(1)
+        
+        if self.SHOW_PARAMS:
+            self.ParamsEditor = wx.ScrolledWindow(self.Editor, 
+                  style=wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER|wx.HSCROLL|wx.VSCROLL)
+            self.ParamsEditor.SetBackgroundColour(WINDOW_COLOUR)
+            self.ParamsEditor.Bind(wx.EVT_SIZE, self.OnWindowResize)
+            self.ParamsEditor.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
+            
+            # Variable allowing disabling of ParamsEditor scroll when Popup shown 
+            self.ScrollingEnabled = True
+            
+            if self.SHOW_BASE_PARAMS:
+                self.ParamsEditorSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
+                self.ParamsEditorSizer.AddGrowableCol(0)
+                self.ParamsEditorSizer.AddGrowableRow(1)
+                
+                self.ParamsEditor.SetSizer(self.ParamsEditorSizer)
+                
+                baseparamseditor_sizer = wx.BoxSizer(wx.HORIZONTAL)
+                self.ParamsEditorSizer.AddSizer(baseparamseditor_sizer, border=5, 
+                      flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.TOP)
+                
+                self.FullIECChannel = wx.StaticText(self.ParamsEditor, -1)
+                self.FullIECChannel.SetFont(
+                    wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, 
+                            wx.BOLD, faceName = faces["helv"]))
+                baseparamseditor_sizer.AddWindow(self.FullIECChannel, 
+                      flag=wx.ALIGN_CENTER_VERTICAL)
+                
+                updownsizer = wx.BoxSizer(wx.VERTICAL)
+                baseparamseditor_sizer.AddSizer(updownsizer, border=5, 
+                      flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL)
+                
+                self.IECCUpButton = wx.lib.buttons.GenBitmapTextButton(self.ParamsEditor, 
+                      bitmap=GetBitmap('IECCDown'), size=wx.Size(16, 16), style=wx.NO_BORDER)
+                self.IECCUpButton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(1), 
+                      self.IECCUpButton)
+                updownsizer.AddWindow(self.IECCUpButton, flag=wx.ALIGN_LEFT)
+                
+                self.IECCDownButton = wx.lib.buttons.GenBitmapButton(self.ParamsEditor, 
+                      bitmap=GetBitmap('IECCUp'), size=wx.Size(16, 16), style=wx.NO_BORDER)
+                self.IECCDownButton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(-1), 
+                      self.IECCDownButton)
+                updownsizer.AddWindow(self.IECCDownButton, flag=wx.ALIGN_LEFT)
+                
+                self.ConfNodeName = wx.TextCtrl(self.ParamsEditor, 
+                      size=wx.Size(150, 25), style=wx.NO_BORDER)
+                self.ConfNodeName.SetFont(
+                    wx.Font(faces["size"] * 0.75, wx.DEFAULT, wx.NORMAL, 
+                            wx.BOLD, faceName = faces["helv"]))
+                self.ConfNodeName.Bind(wx.EVT_TEXT, 
+                      self.GetTextCtrlCallBackFunction(self.ConfNodeName, "BaseParams.Name", True), 
+                      self.ConfNodeName)
+                baseparamseditor_sizer.AddWindow(self.ConfNodeName, border=5, 
+                      flag=wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
+                
+                buttons_sizer = self.GenerateMethodButtonSizer()
+                baseparamseditor_sizer.AddSizer(buttons_sizer, flag=wx.ALIGN_CENTER)
+            
+            else:
+                self.ParamsEditorSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=1, vgap=5)
+                self.ParamsEditorSizer.AddGrowableCol(0)
+                self.ParamsEditorSizer.AddGrowableRow(0)
+            
+            self.ConfNodeParamsSizer = wx.BoxSizer(wx.VERTICAL)
+            self.ParamsEditorSizer.AddSizer(self.ConfNodeParamsSizer, border=5, 
+                  flag=wx.LEFT|wx.RIGHT|wx.BOTTOM)
+            
+            self.RefreshConfNodeParamsSizer()
+        else:
+            self.ParamsEditor = None
+        
+        self._init_ConfNodeEditor(self.Editor)
+            
+        if self.ConfNodeEditor is not None:
+            if self.ParamsEditor is not None:
+                min_size = self.ParamsEditorSizer.GetMinSize()
+                self.Editor.SplitHorizontally(self.ParamsEditor, 
+                                              self.ConfNodeEditor, 
+                                              min(min_size.height, 200))
+            else:
+                self.Editor.Initialize(self.ConfNodeEditor)
+        elif self.ParamsEditor is not None:
+            self.Editor.Initialize(self.ParamsEditor)
+    
+    def __init__(self, parent, controler, window, tagname=""):
+        EditorPanel.__init__(self, parent, tagname, window, controler)
+        
+        icon_name = self.Controler.GetIconName()
+        if icon_name is not None:
+            self.SetIcon(GetBitmap(icon_name))
+        else:
+            self.SetIcon(GetBitmap("Extension"))
+        
+    def __del__(self):
+        self.Controler.OnCloseEditor(self)
+    
+    def GetTagName(self):
+        return self.Controler.CTNFullName()
+    
+    def GetTitle(self):
+        fullname = self.Controler.CTNFullName()
+        if self.Controler.CTNTestModified():
+            return "~%s~" % fullname
+        return fullname
+    
+    def HasNoModel(self):
+        return False
+    
+    def GetBufferState(self):
+        return False, False
+    
+    def Undo(self):
+        pass
+    
+    def Redo(self):
+        pass
+    
+    def RefreshView(self):
+        EditorPanel.RefreshView(self)
+        if self.ParamsEditor is not None:
+            if self.SHOW_BASE_PARAMS:
+                self.ConfNodeName.ChangeValue(self.Controler.MandatoryParams[1].getName())
+                self.RefreshIECChannelControlsState()
+            self.RefreshConfNodeParamsSizer()
+    
+    def EnableScrolling(self, enable):
+        self.ScrollingEnabled = enable
+    
+    def RefreshIECChannelControlsState(self):
+        self.FullIECChannel.SetLabel(self.Controler.GetFullIEC_Channel())
+        self.IECCDownButton.Enable(self.Controler.BaseParams.getIEC_Channel() > 0)
+    
+    def RefreshConfNodeParamsSizer(self):
+        self.Freeze()
+        self.ConfNodeParamsSizer.Clear(True)
+        
+        confnode_infos = self.Controler.GetParamsAttributes()
+        if len(confnode_infos) > 0:
+            self.GenerateSizerElements(self.ConfNodeParamsSizer, confnode_infos, None, False)
+        
+        self.ParamsEditorSizer.Layout()
+        self.Thaw()
+    
+    def GenerateMethodButtonSizer(self):
+        normal_bt_font=wx.Font(faces["size"] / 3, wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = faces["helv"])
+        mouseover_bt_font=wx.Font(faces["size"] / 3, wx.DEFAULT, wx.NORMAL, wx.NORMAL, underline=True, faceName = faces["helv"])
+        
+        msizer = wx.BoxSizer(wx.HORIZONTAL)
+        
+        for confnode_method in self.Controler.ConfNodeMethods:
+            if "method" in confnode_method and confnode_method.get("shown",True):
+                button = GenBitmapTextButton(self.ParamsEditor,
+                    bitmap=GetBitmap(confnode_method.get("bitmap", "Unknown")), 
+                    label=confnode_method["name"], style=wx.NO_BORDER)
+                button.SetFont(normal_bt_font)
+                button.SetToolTipString(confnode_method["tooltip"])
+                if confnode_method.get("push", False):
+                    button.Bind(wx.EVT_LEFT_DOWN, self.GetButtonCallBackFunction(confnode_method["method"], True))
+                else:
+                    button.Bind(wx.EVT_BUTTON, self.GetButtonCallBackFunction(confnode_method["method"]), button)
+                # a fancy underline on mouseover
+                def setFontStyle(b, s):
+                    def fn(event):
+                        b.SetFont(s)
+                        b.Refresh()
+                        event.Skip()
+                    return fn
+                button.Bind(wx.EVT_ENTER_WINDOW, setFontStyle(button, mouseover_bt_font))
+                button.Bind(wx.EVT_LEAVE_WINDOW, setFontStyle(button, normal_bt_font))
+                #hack to force size to mini
+                if not confnode_method.get("enabled",True):
+                    button.Disable()
+                msizer.AddWindow(button, flag=wx.ALIGN_CENTER)
+        return msizer
+    
+    def GenerateSizerElements(self, sizer, elements, path, clean = True):
+        if clean:
+            sizer.Clear(True)
+        first = True
+        for element_infos in elements:
+            if path:
+                element_path = "%s.%s"%(path, element_infos["name"])
+            else:
+                element_path = element_infos["name"]
+            if element_infos["type"] == "element":
+                label = element_infos["name"]
+                staticbox = wx.StaticBox(self.ParamsEditor, 
+                      label=_(label), size=wx.Size(10, 0))
+                staticboxsizer = wx.StaticBoxSizer(staticbox, wx.VERTICAL)
+                if first:
+                    sizer.AddSizer(staticboxsizer, border=5, 
+                          flag=wx.GROW|wx.TOP|wx.BOTTOM)
+                else:
+                    sizer.AddSizer(staticboxsizer, border=5, 
+                          flag=wx.GROW|wx.BOTTOM)
+                self.GenerateSizerElements(staticboxsizer, 
+                                           element_infos["children"], 
+                                           element_path)
+            else:
+                boxsizer = wx.FlexGridSizer(cols=3, rows=1)
+                boxsizer.AddGrowableCol(1)
+                if first:
+                    sizer.AddSizer(boxsizer, border=5, 
+                          flag=wx.GROW|wx.ALL)
+                else:
+                    sizer.AddSizer(boxsizer, border=5, 
+                          flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
+                
+                staticbitmap = GenStaticBitmap(ID=-1, bitmapname=element_infos["name"],
+                    name="%s_bitmap"%element_infos["name"], parent=self.ParamsEditor,
+                    pos=wx.Point(0, 0), size=wx.Size(24, 24), style=0)
+                boxsizer.AddWindow(staticbitmap, border=5, flag=wx.RIGHT)
+                
+                statictext = wx.StaticText(self.ParamsEditor, 
+                      label="%s:"%_(element_infos["name"]))
+                boxsizer.AddWindow(statictext, border=5, 
+                      flag=wx.ALIGN_CENTER_VERTICAL|wx.RIGHT)
+                
+                if isinstance(element_infos["type"], types.ListType):
+                    if isinstance(element_infos["value"], types.TupleType):
+                        browse_boxsizer = wx.BoxSizer(wx.HORIZONTAL)
+                        boxsizer.AddSizer(browse_boxsizer)
+                        
+                        textctrl = wx.TextCtrl(self.ParamsEditor, 
+                              size=wx.Size(275, 25), style=wx.TE_READONLY)
+                        if element_infos["value"] is not None:
+                            textctrl.SetValue(element_infos["value"][0])
+                            value_infos = element_infos["value"][1]
+                        else:
+                            value_infos = None
+                        browse_boxsizer.AddWindow(textctrl)
+                        
+                        button = wx.Button(self.ParamsEditor, 
+                              label="...", size=wx.Size(25, 25))
+                        browse_boxsizer.AddWindow(button)
+                        button.Bind(wx.EVT_BUTTON, 
+                                    self.GetBrowseCallBackFunction(element_infos["name"], textctrl, element_infos["type"], 
+                                                                   value_infos, element_path), 
+                                    button)
+                    else:
+                        combobox = wx.ComboBox(self.ParamsEditor, 
+                              size=wx.Size(300, 28), style=wx.CB_READONLY)
+                        boxsizer.AddWindow(combobox)
+                        
+                        if element_infos["use"] == "optional":
+                            combobox.Append("")
+                        if len(element_infos["type"]) > 0 and isinstance(element_infos["type"][0], types.TupleType):
+                            for choice, xsdclass in element_infos["type"]:
+                                combobox.Append(choice)
+                            name = element_infos["name"]
+                            value = element_infos["value"]
+                        
+                            staticbox = wx.StaticBox(self.ParamsEditor, 
+                                  label="%s - %s"%(_(name), _(value)), size=wx.Size(10, 0))
+                            staticboxsizer = wx.StaticBoxSizer(staticbox, wx.VERTICAL)
+                            sizer.AddSizer(staticboxsizer, border=5, flag=wx.GROW|wx.BOTTOM)
+                            self.GenerateSizerElements(staticboxsizer, element_infos["children"], element_path)
+                            callback = self.GetChoiceContentCallBackFunction(combobox, staticboxsizer, element_path)
+                        else:
+                            for choice in element_infos["type"]:
+                                combobox.Append(choice)
+                            callback = self.GetChoiceCallBackFunction(combobox, element_path)
+                        if element_infos["value"] is None:
+                            combobox.SetStringSelection("")
+                        else:
+                            combobox.SetStringSelection(element_infos["value"])
+                        combobox.Bind(wx.EVT_COMBOBOX, callback, combobox)
+                
+                elif isinstance(element_infos["type"], types.DictType):
+                    scmin = -(2**31)
+                    scmax = 2**31-1
+                    if "min" in element_infos["type"]:
+                        scmin = element_infos["type"]["min"]
+                    if "max" in element_infos["type"]:
+                        scmax = element_infos["type"]["max"]
+                    spinctrl = wx.SpinCtrl(self.ParamsEditor, 
+                          size=wx.Size(300, 25), style=wx.SP_ARROW_KEYS|wx.ALIGN_RIGHT)
+                    spinctrl.SetRange(scmin, scmax)
+                    boxsizer.AddWindow(spinctrl)
+                    if element_infos["value"] is not None:
+                        spinctrl.SetValue(element_infos["value"])
+                    spinctrl.Bind(wx.EVT_SPINCTRL, 
+                                  self.GetTextCtrlCallBackFunction(spinctrl, element_path),
+                                  spinctrl)
+                
+                else:
+                    if element_infos["type"] == "boolean":
+                        checkbox = wx.CheckBox(self.ParamsEditor, size=wx.Size(17, 25))
+                        boxsizer.AddWindow(checkbox)
+                        if element_infos["value"] is not None:
+                            checkbox.SetValue(element_infos["value"])
+                        checkbox.Bind(wx.EVT_CHECKBOX, 
+                                      self.GetCheckBoxCallBackFunction(checkbox, element_path), 
+                                      checkbox)
+                    
+                    elif element_infos["type"] in ["unsignedLong", "long","integer"]:
+                        if element_infos["type"].startswith("unsigned"):
+                            scmin = 0
+                        else:
+                            scmin = -(2**31)
+                        scmax = 2**31-1
+                        spinctrl = wx.SpinCtrl(self.ParamsEditor, 
+                              size=wx.Size(300, 25), style=wx.SP_ARROW_KEYS|wx.ALIGN_RIGHT)
+                        spinctrl.SetRange(scmin, scmax)
+                        boxsizer.AddWindow(spinctrl)
+                        if element_infos["value"] is not None:
+                            spinctrl.SetValue(element_infos["value"])
+                        spinctrl.Bind(wx.EVT_SPINCTRL, 
+                                      self.GetTextCtrlCallBackFunction(spinctrl, element_path), 
+                                      spinctrl)
+                    
+                    else:
+                        choices = self.ParentWindow.GetConfigEntry(element_path, [""])
+                        textctrl = TextCtrlAutoComplete(name=element_infos["name"], 
+                                                        parent=self.ParamsEditor, 
+                                                        appframe=self, 
+                                                        choices=choices, 
+                                                        element_path=element_path,
+                                                        size=wx.Size(300, 25))
+                        
+                        boxsizer.AddWindow(textctrl)
+                        if element_infos["value"] is not None:
+                            textctrl.ChangeValue(str(element_infos["value"]))
+                        textctrl.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(textctrl, element_path))
+            first = False
+    
+    
+    def GetItemChannelChangedFunction(self, dir):
+        def OnConfNodeTreeItemChannelChanged(event):
+            confnode_IECChannel = self.Controler.BaseParams.getIEC_Channel()
+            res = self.SetConfNodeParamsAttribute("BaseParams.IEC_Channel", confnode_IECChannel + dir)
+            wx.CallAfter(self.RefreshIECChannelControlsState)
+            wx.CallAfter(self.ParentWindow._Refresh, TITLE, FILEMENU, PROJECTTREE)
+            wx.CallAfter(self.ParentWindow.SelectProjectTreeItem, self.GetTagName())
+            event.Skip()
+        return OnConfNodeTreeItemChannelChanged
+    
+    def SetConfNodeParamsAttribute(self, *args, **kwargs):
+        res, StructChanged = self.Controler.SetParamsAttribute(*args, **kwargs)
+        if StructChanged:
+            wx.CallAfter(self.RefreshConfNodeParamsSizer)
+        wx.CallAfter(self.ParentWindow._Refresh, TITLE, FILEMENU)
+        return res
+    
+    def GetButtonCallBackFunction(self, method, push=False):
+        """ Generate the callbackfunc for a given confnode method"""
+        def OnButtonClick(event):
+            # Disable button to prevent re-entrant call 
+            event.GetEventObject().Disable()
+            # Call
+            getattr(self.Controler,method)()
+            # Re-enable button 
+            event.GetEventObject().Enable()
+            
+            if not push:
+                event.Skip()
+        return OnButtonClick
+    
+    def GetChoiceCallBackFunction(self, choicectrl, path):
+        def OnChoiceChanged(event):
+            res = self.SetConfNodeParamsAttribute(path, choicectrl.GetStringSelection())
+            choicectrl.SetStringSelection(res)
+            event.Skip()
+        return OnChoiceChanged
+    
+    def GetChoiceContentCallBackFunction(self, choicectrl, staticboxsizer, path):
+        def OnChoiceContentChanged(event):
+            res = self.SetConfNodeParamsAttribute(path, choicectrl.GetStringSelection())
+            wx.CallAfter(self.RefreshConfNodeParamsSizer)
+            event.Skip()
+        return OnChoiceContentChanged
+    
+    def GetTextCtrlCallBackFunction(self, textctrl, path, refresh=False):
+        def OnTextCtrlChanged(event):
+            res = self.SetConfNodeParamsAttribute(path, textctrl.GetValue())
+            if res != textctrl.GetValue():
+                textctrl.ChangeValue(res)
+            if refresh:
+                wx.CallAfter(self.ParentWindow._Refresh, TITLE, FILEMENU, PROJECTTREE, PAGETITLES)
+                wx.CallAfter(self.ParentWindow.SelectProjectTreeItem, self.GetTagName())
+            event.Skip()
+        return OnTextCtrlChanged
+    
+    def GetCheckBoxCallBackFunction(self, chkbx, path):
+        def OnCheckBoxChanged(event):
+            res = self.SetConfNodeParamsAttribute(path, chkbx.IsChecked())
+            chkbx.SetValue(res)
+            event.Skip()
+        return OnCheckBoxChanged
+    
+    def GetBrowseCallBackFunction(self, name, textctrl, library, value_infos, path):
+        infos = [value_infos]
+        def OnBrowseButton(event):
+            dialog = BrowseValuesLibraryDialog(self, name, library, infos[0])
+            if dialog.ShowModal() == wx.ID_OK:
+                value, value_infos = self.SetConfNodeParamsAttribute(path, dialog.GetValueInfos())
+                textctrl.ChangeValue(value)
+                infos[0] = value_infos
+            dialog.Destroy()
+            event.Skip()
+        return OnBrowseButton
+    
+    def OnWindowResize(self, event):
+        self.ParamsEditor.GetBestSize()
+        xstart, ystart = self.ParamsEditor.GetViewStart()
+        window_size = self.ParamsEditor.GetClientSize()
+        maxx, maxy = self.ParamsEditorSizer.GetMinSize()
+        posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
+        posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
+        self.ParamsEditor.Scroll(posx, posy)
+        self.ParamsEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
+                maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
+        event.Skip()
+    
+    def OnMouseWheel(self, event):
+        if self.ScrollingEnabled:
+            event.Skip()
+