# -*- coding: utf-8 -*-
"""
Created on Mon Dec  4 10:59:53 2017

@author: Weber

"""
import sys
import PyQt5
from PyQt5 import QtWidgets,QtGui
from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal, QLocale, Qt, QDate, QDateTime, QTime, QByteArray
from pyqtgraph.widgets import GradientWidget , ColorButton, SpinBox
import pyqtgraph.parametertree.parameterTypes as pTypes
from pyqtgraph.parametertree import Parameter, ParameterItem
from pyqtgraph.parametertree.Parameter import registerParameterType
from collections import OrderedDict
from decimal import Decimal as D


import xml.etree.ElementTree as ET

from pathlib import Path
import numpy as np




#%% with attribute
def walk_parameters_to_xml(parent_elt=None,param=None):
    """
        To convert a parameter object (and children) to xml data tree.

        =============== ================================ ==================================
        **Parameters**   **Type**                         **Description**

        *parent_elt*     XML element                      the root element
        *param*          instance of pyqtgraph parameter  Parameter object to be converted
        =============== ================================ ==================================

        Returns
        -------
        XML element : parent_elt
            XML element with subelements from Parameter object

        Examples
        -------
        >>> from pyqtgraph.parametertree import Parameter, ParameterItem
        >>> import xml.etree.ElementTree as ET
        >>> params = [{title': 'Scan2D settings', 'name': 'scan2D_settings', 'type': 'group', 'children': [
                        {'title': 'Scan type:','name': 'scan2D_type', 'type': 'list', 'values': ['Spiral','Linear', 'back&forth'],'value': 'Spiral'},
                        {'title': 'Rstep:','name': 'Rstep_2d', 'type': 'float', 'value': 1., 'visible':True},
                        {'title': 'Rmax:','name': 'Rmax_2d', 'type': 'float', 'value': 10., 'visible':True}
                        ]}]
        >>> settings=Parameter.create(name='Settings', type='group', children=params)
        >>> param_type=settings.type()
        >>> base_elt=ET.Element(settings.name(),title=str(settings.opts['title']),type=param_type)

        >>> XML_elt=walk_parameters_to_xml(param=settings)
        >>> tree=ET.ElementTree(XML_elt)
        >>> tree.write('settings.xml')


        See Also
        --------
        walk_parameters_to_xml

    """

    if type(param) is None:
        raise TypeError('No valid param input')

    if parent_elt is None:
        title=param.opts['title']
        if title is None:
            title=param.name()
        parent_elt=ET.Element(param.name(),title=title,type=str(param.type()))

    params_list=param.children()
    for param in params_list:
        param_type=str(param.type())
        title=param.opts['title']
        if title is None:
            title=param.name()
        if param.opts['visible']:
            visible='1'
        else:
            visible='0'
        if param.opts['removable']:
            removable='1'
        else:
            removable='0'
        if param.opts['readonly']:
            readonly='1'
        else:
            readonly='0'

        if 'show_pb' in param.opts:
            if param.opts['show_pb']:
                show_pb='1'
            else:
                show_pb = '0'
            elt = ET.Element(param.name(), title=title, type=param_type, visible=visible, removable=removable,
                             readonly=readonly,show_pb=show_pb)
        else:
            elt=ET.Element(param.name(),title=title,type=param_type,visible=visible,removable=removable,readonly=readonly)

        if 'group' not in param_type: #covers 'group', custom 'groupmove'...
            if param_type=='bool':
                if param.value():
                    text='1'
                else:
                    text='0'
            elif param_type=='itemselect':
                if param.value() is not None:
                    elt.set('all_items',str(param.value()['all_items'])) #use list(eval(val_str[1:-1])) to get back a list of strings
                    text=str(param.value()['selected']) #use list(eval(val_str[1:-1])) to get back a list of strings
                else:
                    text=str(None)
            elif param_type=='color':
                text=str([param.value().red(),param.value().green(),param.value().blue(),param.value().alpha()])

            else:
                text=str(param.value())
            elt.text=text
        else:
            walk_parameters_to_xml(elt,param)

        parent_elt.append(elt)
    return parent_elt

def parameter_to_xml_string(param):
    """
        Convert  the given parameter to XML string.

        =============== ================================ ===============================
        **Parameters**    **Type**                        **Description**
        paramm           instance of pyqtgraph parameter  The parameter to be converted
        =============== ================================ ===============================

        Returns
        -------
        string
            The converted string XML element.

        See Also
        --------
        walk_parameters_to_xml

        Examples
        --------

        >>> import custom_parameter_tree as cpt
        >>> from pyqtgraph.parametertree import Parameter
        >>>    #Create an instance of Parameter
        >>> settings=Parameter(name='settings')  
        >>> converted_xml=cpt.parameter_to_xml_string(settings)
        >>>    # The converted Parameter
        >>> print(converted_xml)                 
        b'<settings title="settings" type="None" />'
    """
    xml_elt=walk_parameters_to_xml(param=param)
    return ET.tostring(xml_elt)

def parameter_to_xml_file(param,filename):
    """
        Convert the given parameter to XML element and update the given XML file.

        =============== ================================= ================================
        **Parameters**    **Type**                          **Description**
        *param*           instance of pyqtgraph parameter   the parameter to be added
        *filename*        string                            the filename of the XML file
        =============== ================================= ================================

        See Also
        --------
        walk_parameters_to_xml  

        Examples
        --------
        >>> import custom_parameter_tree as cpt
        >>> from pyqtgraph.parametertree import Parameter
        >>> import pathlib as pl
        >>>    #Creating function parameters
        >>> settings=Parameter(name='settings')
        >>> filename="my_xml_file"
        >>> cpt.parameter_to_xml_file(settings,filename)
        >>>    #Verifiy the integrity of the converted xml file
        >>> check=open("my_xml_file.xml","r")
        >>> print(check.read())
        <settings title="settings" type="None" />      
    """
    fname=Path(filename)
    parent=fname.parent
    filename=fname.stem
    fname=parent.joinpath(filename+".xml") #forcing the right extension on the filename
    xml_elt=walk_parameters_to_xml(param=param)
    tree=ET.ElementTree(xml_elt)
    tree.write(str(fname))



def walk_xml_to_parameter(params=[],XML_elt=None):
    """ To convert an XML element (and children) to dict enabling creation of parameter object.

        =============== ================== =======================================
        **Parameters**   **Type**            **Description**

        *params*         dictionnary list    the list to create parameter object
        *XML_elt*        XML object          the XML object to be converted
        =============== ================== =======================================

        Returns
        -------
        params : dictionnary list
            list of dict to create parameter object

        Examples
        -------
        >>> from pyqtgraph.parametertree import Parameter, ParameterItem
        >>> import xml.etree.ElementTree as ET
        >>> tree = ET.parse('text_bis.xml')
        >>> root = tree.getroot()
        >>> params=walk_xml_to_parameter(XML_elt=root)
        >>> settings_xml=Parameter.create(name='Settings XML', type='group', children=params)
        >>> settings=Parameter.create(name='Settings', type='group', children=params)

        See Also
        --------
        walk_parameters_to_xml          
    """
    if type(XML_elt) is not ET.Element:
        raise TypeError('not valid XML element')

    for el in list(XML_elt):
        param_type=el.get('type')
        title=el.get('title')
        if title=='None':
            title=el.tag
        if 'visible' not in el.attrib.keys():
            visible=True
        else:
            visible=bool(int(el.get('visible')))
        if 'removable' not in el.attrib.keys():
            removable=False
        else:
            removable=bool(int(el.get('removable')))
        if 'readonly' not in el.attrib.keys():
            readonly=False
        else:
            readonly=bool(int(el.get('readonly')))
        if 'show_pb' in el.attrib.keys():
            show_pb = bool(int(el.get('show_pb')))
        else:
            show_pb = False


        if 'group' not in param_type: #covers 'group', custom 'groupmove'...
            val_text=el.text

            if param_type=='float':
                param_value=float(val_text)
            elif param_type=='int':
                param_value=int(val_text)
            elif param_type=='itemselect':
                if val_text=='None':
                    param_value=dict(all_items=[],selected=[])
                else:
                    param_value=dict(all_items=eval(el.get('all_items',val_text)),selected=eval(val_text))
            elif param_type=='bool':
                param_value=bool(int(val_text))
            elif param_type=='led':
                param_value=bool(val_text)
            elif param_type=='date_time':
                param_value=eval(val_text)
            elif param_type=='table':
                param_value=eval(val_text)
            elif param_type=='color':
                param_value=QtGui.QColor(*eval(val_text))
            else:
                param_value=val_text

            if param_type=='list':
                param=dict(name=el.tag,title=title,type=param_type,value=param_value,values=[param_value],visible=visible,removable=removable,readonly=readonly,show_pb=show_pb)
            else:
                param=dict(name=el.tag,title=title,type=param_type,value=param_value,visible=visible,removable=removable,readonly=readonly)
        else:
            subparams=[]

            param=dict(name=el.tag,title=title,type=param_type, visible=visible,removable=removable,readonly=readonly, children=walk_xml_to_parameter(subparams,el))

        params.append(param)
    return params

def XML_file_to_parameter(file_name):
    """
        Convert a xml file into pyqtgraph parameter object.

        =============== =========== ================================================
        **Parameters**   **Type**    **Description**

        *file_name*     string      the file name of the XML file to be converted
        =============== =========== ================================================

        Returns
        -------
        params : dictionnary list
            a parameter list of dictionnary to init a parameter

        See Also
        --------
        walk_parameters_to_xml  

        Examples
        --------
        >>> from pyqtgraph.parametertree import Parameter
        >>> import custom_parameter_tree as cpt
        >>>   #Creating test Parameter 
        >>> value=Parameter(name='value',value=10)
        >>> settings=Parameter(name='settings')
        >>> settings.addChild(value)
        <Parameter 'value' at 0x5655f78>
        >>>   #Creating test xml file
        >>> xml_file=cpt.parameter_to_xml_file(settings,"my_xml_file")
        >>> check=cpt.XML_file_to_parameter("my_xml_file.xml")
        >>>   #Verifiy the integrity of the converted parameter
        >>> print(check)
        [{'visible': True, 'type': 'None', 'name': 'value', 'value': '10', 'title': 'value'}]

    """
    tree = ET.parse(file_name)

    root = tree.getroot()
    params=walk_xml_to_parameter(params=[],XML_elt=root)
    return params

def XML_string_to_parameter(xml_string):
    """
        Convert a xml string into pyqtgraph parameter object.

        =============== =========== ================================
        **Parameters**   **Type**    **Description**

        xml_string       string      the xml string to be converted
        =============== =========== ================================

        Returns
        -------
        params: a parameter list of dict to init a parameter

        See Also
        --------
        walk_parameters_to_xml

        Examples
        --------
        >>> import custom_parameter_tree as cpt
        >>> from pyqtgraph.parametertree import Parameter
        >>>    #Creating test parameter
        >>> settings=Parameter(name='settings')
        >>> child=Parameter(name='info', value=10, visible=True)
        >>> settings.addChild(child)
        <Parameter 'info' at 0x84ab558>
        >>>    #Creating test xml string
        >>> xml_string=cpt.parameter_to_xml_string(settings)
        >>>    #Verifiy the integrity of the converted parameter
        >>> converted_parameter=cpt.XML_string_to_parameter(xml_string)
        >>> print(converted_parameter)
        [{'visible': True, 'type': 'None', 'name': 'info', 'value': '10', 'title': 'info'}]

    """
    root = ET.fromstring(xml_string)
    tree=ET.ElementTree(root)

    #tree.write('test.xml')
    params=walk_xml_to_parameter(params=[],XML_elt=root)

    return params

def iter_children(param,childlist=[]):
    """
        | Iterator over all sub children of a given parameters.
        | Returns all childrens names.

        =============== ================================= ====================================
        **Parameters**   **Type**                           **Description**
        *param*          instance of pyqtgraph parameter    the root node to be coursed
        *childlist*      list                               the child list recetion structure
        =============== ================================= ====================================

        Returns
        -------
        childlist : parameter list
            The list of the children from the given node.


        Examples
        --------
        >>> import custom_parameter_tree as cpt
        >>> from pyqtgraph.parametertree import Parameter
        >>>     #Creating the example tree
        >>> settings=Parameter(name='settings')
        >>> child1=Parameter(name='child1', value=10)
        >>> child2=Parameter(name='child2',value=10,visible=True,type='group')
        >>> child2_1=Parameter(name='child2_1', value=10)
        >>> child2_2=Parameter(name='child2_2', value=10)
        >>> child2.addChildren([child2_1,child2_2])
        >>> settings.addChildren([child1,child2])
        >>>     #Get the child list from the param argument
        >>> childlist=cpt.iter_children(settings)
        >>>     #Verify the integrity of result
        >>> print(childlist)
        ['child1', 'child2', 'child2_1', 'child2_2']

    """
    for child in param.children():
        childlist.append(child.name())
        if child.type()=='group':
            childlist.extend(iter_children(child,[]))
    return childlist





class GroupParameterItemCustom(pTypes.GroupParameterItem):
    """
        | Group parameters are used mainly as a generic parent item that holds (and groups!) a set of child parameters. It also provides a simple mechanism for displaying a button or combo that can be used to add new parameters to the group.
        |
        | This customization is made in order to respond to the visible options.
        | Overwrite the optsChanged method from GroupParameterItem class.

    """
    def __init__(self, param, depth):
        pTypes.GroupParameterItem.__init__(self, param, depth)


    def optsChanged(self, param, changed):
        if 'addList' in changed:
            self.updateAddList()
        elif 'visible' in changed:
            self.setHidden(not changed['visible'])


class GroupParameterCustom(pTypes.GroupParameter):
    """
        |
        | Group parameters are used mainly as a generic parent item that holds (and groups!) a set of child parameters.
        |
        | It also provides a simple mechanism for displaying a button or combo that can be used to add new parameters to the group.
        |
        | To enable this, the group  must be initialized with the 'addText' option (the text will be displayed on a button which, when clicked, will cause addNew() to be called).
        |
        | If the 'addList' option is specified as well, then a dropdown-list of addable items will be displayed instead of a button.
        |

        ============== ========================================
        **Attributes**    **Type**
        itemClass         instance of GroupParameterItemCustom
        ============== ========================================
    """
    itemClass = GroupParameterItemCustom
registerParameterType('group', GroupParameterCustom, override=True)



class SpinBoxCustom(SpinBox.SpinBox):
    def __init__(self, parent=None, value=0.0, **kwargs):
        SpinBox.SpinBox.__init__(self,parent=None, value=0.0, **kwargs)
    def setOpts(self, **opts):
        """
            Overriden class to add the field visible in the options.

            =============== =========== ======================
            **Parameters**    **Type**     **Description**
            *opts*            string       the vararg options 
            =============== =========== ======================

            See Also
            --------
            custom_parameter_tree.ItemSelect.setValue
        """
        #print opts
        for k in opts:
            if k == 'bounds':
                self.setMinimum(opts[k][0], update=False)
                self.setMaximum(opts[k][1], update=False)
            elif k == 'min':
                self.setMinimum(opts[k], update=False)
            elif k == 'max':
                self.setMaximum(opts[k], update=False)
            elif k in ['step', 'minStep']:
                self.opts[k] = D(str(opts[k]))
            elif k == 'value':
                pass   ## don't set value until bounds have been set
            elif k == 'visible':
                self.setVisible(opts[k])
            elif k == 'readonly':
                self.setReadOnly(opts[k])
            elif k in self.opts:
                self.opts[k] = opts[k]
            else:
                raise TypeError("Invalid keyword argument '%s'." % k)
        if 'value' in opts:
            self.setValue(opts['value'])

        ## If bounds have changed, update value to match
        if 'bounds' in opts and 'value' not in opts:
            self.setValue()

        ## sanity checks:
        if self.opts['int']:
            if 'step' in opts:
                step = opts['step']
                ## not necessary..
                #if int(step) != step:
                    #raise Exception('Integer SpinBox must have integer step size.')
            else:
                self.opts['step'] = int(self.opts['step'])

            if 'minStep' in opts:
                step = opts['minStep']
                if int(step) != step:
                    raise Exception('Integer SpinBox must have integer minStep size.')
            else:
                ms = int(self.opts.get('minStep', 1))
                if ms < 1:
                    ms = 1
                self.opts['minStep'] = ms

        if 'delay' in opts:
            self.proxy.setDelay(opts['delay'])

        self.updateText()

class Pixmap_check(QtWidgets.QWidget):
    """ value of this parameter is a dict with checked, data for the pixmap and optionally path in h5 node
    """
    #valuechanged=pyqtSignal(dict)

    def __init__(self):
        QLocale.setDefault(QLocale(QLocale.English, QLocale.UnitedStates))
        super(Pixmap_check,self).__init__()
        self.path=""
        self.data=None
        self.initUI()

    def initUI(self):
        """
            Init the User Interface.
        """
        self.ver_layout=QtWidgets.QVBoxLayout()
        self.label=QtWidgets.QLabel()
        self.checkbox=QtWidgets.QCheckBox('Show/Hide')
        self.checkbox.setChecked(False)
        self.ver_layout.addWidget(self.label)
        self.ver_layout.addWidget(self.checkbox)
        self.ver_layout.setSpacing(0)
        self.ver_layout.setContentsMargins(0,0,0,0);
        self.setLayout(self.ver_layout)

    def setValue(self,dic):
        self.data=QByteArray(dic['data'])
        im=QtGui.QImage.fromData(self.data)
        a=QtGui.QPixmap.fromImage(im)
        self.label.setPixmap(a)
        self.checkbox.setChecked(dic['checked'])
        self.path=dic['path']
        #self.valuechanged.emit(dic)

    def value(self):
        return dict(pixmap=self.label.pixmap,checked=self.checkbox.isChecked(),path=self.path)

class QTimeCustom(QtWidgets.QTimeEdit):
    def __init__(self,*args,**kwargs):
        super(QTimeCustom,self).__init__(*args,**kwargs)
        self.minutes_increment=1
        self.timeChanged.connect(self.updateTime)
        
    def setTime(self,time):
        hours=time.hour()
        minutes=time.minute()
        
        minutes=int(np.round(minutes/self.minutes_increment)*self.minutes_increment)
        if minutes==60:
            minutes=0
            hours+=1
            
        time.setHMS(hours,minutes,0)
        
        return super(QTimeCustom,self).setTime(time)
        
            
    def setMinuteIncrement(self,minutes_increment):
        self.minutes_increment=minutes_increment
        self.updateTime(self.time())
        
    @pyqtSlot(QTime)
    def updateTime(self,time):
        self.setTime(time)
        


class SliderSpinBox(QtWidgets.QWidget):

    def __init__(self,*args,**kwargs):
        QLocale.setDefault(QLocale(QLocale.English, QLocale.UnitedStates))
        super(SliderSpinBox,self).__init__()
        self.initUI(*args,**kwargs)
        
    @property
    def opts(self):
        return self.spinbox.opts

    @opts.setter
    def opts(self,**opts):
        self.setOpts(**opts)

    def setOpts(self, **opts):
        self.spinbox.setOpts(**opts)
        if 'visible' in opts:
            self.slider.setVisible(opts['visible'])


    def initUI(self,*args,**kwargs):
        """
            Init the User Interface.
        """
        self.hor_layout=QtWidgets.QHBoxLayout()
        self.slider=QtWidgets.QSlider(Qt.Horizontal)
        self.slider.setMinimum(0)
        self.slider.setMaximum(100)

        self.spinbox=SpinBoxCustom(parent=None, value=0.0, **kwargs)

        self.hor_layout.addWidget(self.slider)
        self.hor_layout.addWidget(self.spinbox)
        self.hor_layout.setSpacing(0)
        self.hor_layout.setContentsMargins(0,0,0,0);
        self.setLayout(self.hor_layout)

        self.slider.valueChanged.connect(self.update_spinbox)
        self.spinbox.valueChanged.connect(self.update_slide)


    def update_spinbox(self,val):
        """
        val is a percentage [0-100] used in order to set the spinbox value between its min and max
        """
        min=float(self.opts['bounds'][0])
        max=float(self.opts['bounds'][1])
        self.spinbox.setValue(val*(max-min)/100+min)


    def update_slide(self,val):
        """
        val is the spinbox value between its min and max
        """
        min=float(self.opts['bounds'][0])
        max=float(self.opts['bounds'][1])

        try:
            self.slider.valueChanged.disconnect(self.update_spinbox)
        except:
            pass
        self.slider.setValue(int((val-min)/(max-min)*100))
        self.slider.valueChanged.connect(self.update_spinbox)

    def setValue(self,val):
        self.spinbox.setValue(val)

    def value(self):
        return self.spinbox.value()

class WidgetParameterItemcustom(pTypes.WidgetParameterItem):
    """
        This is a subclass of widget parameteritem in order to deal with the visiblily of the spinbox when parameter visibility os toggled.
    """
    def __init__(self, param, depth):
        pTypes.WidgetParameterItem.__init__(self, param, depth)

    def makeWidget(self):
        """
            | Return a single widget that should be placed in the second tree column.
            | The widget must be given three attributes:

            ==========  ============================================================
            sigChanged  a signal that is emitted when the widget's value is changed
            value       a function that returns the value
            setValue    a function that sets the value
            ==========  ============================================================

            | This is a good function to override in subclasses.

            See Also
            --------
            SpinBoxCustom, custom_parameter_tree.setOpts
        """
        opts = self.param.opts
        t = opts['type']
        if t in ('int', 'float'):
            defs = {
                'value': 0, 'min': None, 'max': None,
                'step': 1.0, 'dec': False,
                'siPrefix': False, 'suffix': '', 'decimals': 12,
            }
            if t == 'int':
                defs['int'] = True
                defs['minStep'] = 1.0
            for k in defs:
                if k in opts:
                    defs[k] = opts[k]
            if 'limits' in opts:
                defs['bounds'] = opts['limits']
            w = SpinBoxCustom()
            w.setOpts(**defs)
            w.sigChanged = w.sigValueChanged
            w.sigChanging = w.sigValueChanging
        elif t == 'bool':
            w = QtWidgets.QCheckBox()
            w.sigChanged = w.toggled
            w.value = w.isChecked
            w.setValue = w.setChecked
            w.setEnabled(not opts.get('readonly', False))
            self.hideWidget = False
        elif t == 'bool_push':
            w = QtWidgets.QPushButton()
            if 'title' in opts:
                w.setText(opts['title'])
            else:
                w.setText(opts['name'])
            w.setMaximumWidth(50)
            w.setCheckable(True)
            w.sigChanged = w.toggled
            w.value = w.isChecked
            w.setValue = w.setChecked
            w.setEnabled(not opts.get('readonly', False))
            self.hideWidget = False
        elif t == 'str':
            w = QtWidgets.QLineEdit()
            w.sigChanged = w.editingFinished
            w.value = lambda: str(w.text())
            w.setValue = lambda v: w.setText(str(v))
            w.sigChanging = w.textChanged
        elif t == 'color':
            w = ColorButton.ColorButton()
            w.sigChanged = w.sigColorChanged
            w.sigChanging = w.sigColorChanging
            w.value = w.color
            w.setValue = w.setColor
            self.hideWidget = False
            w.setFlat(True)
            w.setEnabled(not opts.get('readonly', False))
        elif t == 'colormap':
            from pyqtgraph.widgets.GradientWidget import GradientWidget ## need this here to avoid import loop
            w = GradientWidget(orientation='bottom')
            w.sigChanged = w.sigGradientChangeFinished
            w.sigChanging = w.sigGradientChanged
            w.value = w.colorMap
            w.setValue = w.setColorMap
            self.hideWidget = False
        elif t== 'date_time':
            w=QtWidgets.QDateTimeEdit(QDateTime(QDate.currentDate(),QTime.currentTime()))
            w.setCalendarPopup(True)
            w.setDisplayFormat('dd/MM/yyyy hh:mm')
            w.sigChanged=w.dateTimeChanged
            w.value = w.dateTime
            w.setValue= w.setDateTime
        elif t== 'date':
            w=QtWidgets.QDateEdit(QDate(QDate.currentDate()))
            w.setCalendarPopup(True)
            w.setDisplayFormat('dd/MM/yyyy')
            w.sigChanged=w.dateChanged
            w.value = w.date
            w.setValue= w.setDate
            
        elif t== 'time':
            w=QTimeCustom(QTime(QTime.currentTime()))
            if 'minutes_increment' in opts:
                w.setMinuteIncrement(opts['minutes_increment'])
            w.setDisplayFormat('hh:mm')
            w.sigChanged=w.timeChanged
            w.value = w.time
            w.setValue= w.setTime


        elif t=='pixmap':
            w=QtWidgets.QLabel()
            w.sigChanged=None
            w.value = w.pixmap
            w.setValue= w.setPixmap
        elif t=='pixmap_check':
            w=Pixmap_check()
            w.sigChanged=w.checkbox.toggled
            w.value = w.value
            w.setValue= w.setValue
        elif t=='slide':

            defs = {
                'value': 0, 'min': 0., 'max': 1000.,
                'step': 1.0, 'dec': False,
                'siPrefix': False, 'suffix': '', 'decimals': 12,
            }
            for k in defs:
                if k in opts:
                    defs[k] = opts[k]
            if 'limits' in opts:
                defs['bounds'] = opts['limits']

            w = SliderSpinBox(bounds=(0.,1000.))
            w.setOpts(**defs)
            w.sigChanged = w.spinbox.sigValueChanged
            w.sigChanging = w.spinbox.sigValueChanging

        else:
            raise Exception("Unknown type '%s'" % str(t))
        return w

    def showEditor(self):
        """
            Show the widget attribute.
        """
        self.widget.show()
        self.displayLabel.hide()
        self.widget.setFocus(Qt.OtherFocusReason)
        if isinstance(self.widget, SpinBox.SpinBox):
            self.widget.selectNumber()  # select the numerical portion of the text for quick editing

    def hideEditor(self):
        """
            Hide the widget attribute.
        """
        if not (self.param.opts['type']=='led' or self.param.opts['type']=='pixmap' or self.param.opts['type']=='pixmap_check'):
            self.widget.hide()
            self.displayLabel.show()

    def optsChanged(self, param, opts):
        """
            | Called when any options are changed that are not name, value, default, or limits.
            |
            | If widget is a SpinBox, pass options straight through.
            | So that only the display label is shown when visible option is toggled.

            =============== ================================== ==============================
            **Parameters**    **Type**                           **Description**
            *param*           instance of pyqtgraph parameter    the parameter to check
            *opts*            string list                        the associated options list
            =============== ================================== ==============================

            See Also
            --------
            optsChanged
        """
        #print "opts changed:", opts
        ParameterItem.optsChanged(self, param, opts)

        if 'readonly' in opts:
            self.updateDefaultBtn()
            if isinstance(self.widget, (QtWidgets.QCheckBox,ColorButton.ColorButton)):
                self.widget.setEnabled(not opts['readonly'])

        if 'minutes_increment' in opts:
            self.widget.setMinuteIncrement(opts['minutes_increment'])

        ## If widget is a SpinBox, pass options straight through
        if isinstance(self.widget, SpinBoxCustom):
            if 'visible' in opts:
                opts.pop('visible')
                self.widget.hide() # so that only the display label is shown when visible option is toggled
            if 'units' in opts and 'suffix' not in opts:
                opts['suffix'] = opts['units']
            self.widget.setOpts(**opts)
            self.updateDisplayLabel()

    def valueChanged(self, param, val, force=False):
        ## called when the parameter's value has changed
        ParameterItem.valueChanged(self, param, val)
        if self.widget.sigChanged is not None:
            self.widget.sigChanged.disconnect(self.widgetValueChanged)

        try:
            if force or val != self.widget.value():
                self.widget.setValue(val)
            self.updateDisplayLabel(val)  ## always make sure label is updated, even if values match!
        finally:
            if self.widget.sigChanged is not None:
                self.widget.sigChanged.connect(self.widgetValueChanged)
        self.updateDefaultBtn()

class SimpleParameterCustom(pTypes.SimpleParameter):
    itemClass = WidgetParameterItemcustom

    def __init__(self, *args, **kargs):
        pTypes.SimpleParameter.__init__(self, *args, **kargs)

    # def _interpretValue(self, v):
    #     fn = {
    #         'int': int,
    #         'float': float,
    #         'bool': bool,
    #         'str': str,
    #         'color': self._interpColor,
    #         'colormap': self._interpColormap,
    #         'date_time': QDateTime,
    #         'date': QDate,
    #         'time': QTime,
    #         'led': QLED,
    #         'pixmap': QtWidgets.QLabel,
    #         'pixmap_check': Pixmap_check,
    #         'slide': float
    #     }[self.opts['type']]
    #     return fn(v)


registerParameterType('int',SimpleParameterCustom, override=True)
registerParameterType('float', SimpleParameterCustom , override=True)
registerParameterType('bool',SimpleParameterCustom, override=True)
registerParameterType('bool_push',SimpleParameterCustom, override=True)
registerParameterType('date_time', SimpleParameterCustom , override=True)
registerParameterType('date', SimpleParameterCustom , override=True)
registerParameterType('time', SimpleParameterCustom , override=True)
registerParameterType('pixmap', SimpleParameterCustom , override=True)
registerParameterType('pixmap_check', SimpleParameterCustom , override=True)
registerParameterType('slide', SimpleParameterCustom , override=True)

class ListParameterItem_custom(pTypes.ListParameterItem):
    """
        WidgetParameterItem subclass providing comboBox that lets the user select from a list of options.

    """
    def __init__(self, param, depth):
        super(ListParameterItem_custom,self).__init__(param, depth)


    def makeWidget(self):
        """
            Make a widget from self parameter options, connected to the buttonClicked function.

            Returns
            -------
            w:widget
                the initialized widget

            See Also
            --------
            buttonClicked, limitsChanged, custom_parameter_tree.ItemSelect.setValue
        """
        opts = self.param.opts
        t = opts['type']
        w = Combo_pb()
        w.add_pb.clicked.connect(self.buttonClicked)
        w.setMaximumHeight(20)  ## set to match height of spin box and line edit
        if 'show_pb' in opts:
            w.add_pb.setVisible(opts['show_pb'])
        else:
            w.add_pb.setVisible(False)
        w.sigChanged = w.combo.currentIndexChanged
        w.value = self.value
        w.setValue = self.setValue
        self.widget = w  ## needs to be set before limits are changed
        self.limitsChanged(self.param, self.param.opts['limits'])
        if len(self.forward) > 0:
            self.setValue(self.param.value())
        return w

    def value(self):
        key = str(self.widget.combo.currentText())
        return self.forward.get(key, None)

    def setValue(self, val):
        self.targetValue = val
        if val not in self.reverse[0]:
            self.widget.combo.setCurrentIndex(0)
        else:
            key = self.reverse[1][self.reverse[0].index(val)]
            ind = self.widget.combo.findText(key)
            self.widget.combo.setCurrentIndex(ind)

    def limitsChanged(self, param, limits):
        """
            Set up forward / reverse mappings for {name:value} limits dictionnary.

            =============== ================================== ========================================
            **Parameters**    **Type**                          **Description**
            *param*           instance of pyqtgraph parameter    Not used
            *limits*          dictionnary                        the limits dictionnary to be mapped
            =============== ================================== ========================================

        """

        if len(limits) == 0:
            limits = ['']  ## Can never have an empty list--there is always at least a singhe blank item.

        self.forward, self.reverse = ListParameter_custom.mapping(limits)
        try:
            self.widget.blockSignals(True)
            val = self.targetValue  #asUnicode(self.widget.currentText())

            self.widget.combo.clear()
            for k in self.forward:
                self.widget.combo.addItem(k)
                if k == val:
                    self.widget.combo.setCurrentIndex(self.widget.count()-1)
                    self.updateDisplayLabel()
        finally:
            self.widget.blockSignals(False)

    def buttonClicked(self):
        """
            |
            | Append the self limits attributes an added parameter with string value.
            | Update parameter and call the limitschanged method to map the added parameter.

            See Also
            --------
            limitsChanged, custom_parameter_tree.ItemSelect.setValue
        """
        if type(self.param.opts['limits']) == list:
            text,ok = QtWidgets.QInputDialog.getText(None,"Enter a value to add to the parameter",
                                             "String value:", QtWidgets.QLineEdit.Normal);
            if ok and not (text==""):
                self.param.opts['limits'].append(text)
                self.limitsChanged(self.param,self.param.opts['limits'])
                self.param.setValue(text)

    def optsChanged(self, param, opts):
        """
            Called when any options are changed that are not name, value, default, or limits.

            =============== ================================== =======================================
            **Parameters**    **Type**                           **Description**
            *param*           instance of pyqtgraph parameter    The parameter to be checked
            *opts*            string list                        The option dictionnary to be checked
            =============== ================================== =======================================

            See Also
            --------
            optsChanged
        """
        #print "opts changed:", opts
        ParameterItem.optsChanged(self, param, opts)

        if 'show_pb' in opts:
            self.widget.add_pb.setVisible(opts['show_pb'])


class ListParameter_custom(pTypes.ListParameter):
    """
        =============== =======================================
        **Attributes**    **Type**
        *itemClass*       instance of ListParameterItem_custom
        *sigActivated*    instance of pyqt Signal
        =============== =======================================
    """
    itemClass = ListParameterItem_custom
    sigActivated = pyqtSignal(object)
    def __init__(self, **opts):
        super(ListParameter_custom,self).__init__( **opts)


    def activate(self):
        """
            Emit the Activated signal.
        """
        self.sigActivated.emit(self)
        self.emitStateChanged('activated', None)


registerParameterType('list', ListParameter_custom, override=True)





class Combo_pb(QtWidgets.QWidget):

    def __init__(self,items=[]):
        QLocale.setDefault(QLocale(QLocale.English, QLocale.UnitedStates))
        super(Combo_pb,self).__init__()
        self.items=items
        self.initUI()
        self.count=self.combo.count

    def initUI(self):
        """
            Init the User Interface.
        """


        self.hor_layout=QtWidgets.QHBoxLayout()
        self.combo=QtWidgets.QComboBox()
        self.combo.addItems(self.items)
        self.add_pb=QtWidgets.QPushButton()
        self.add_pb.setText("")
        icon3 = QtGui.QIcon()
        icon3.addPixmap(QtGui.QPixmap(":/Labview_icons/Icon_Library/Add2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.add_pb.setIcon(icon3)
        self.hor_layout.addWidget(self.combo)
        self.hor_layout.addWidget(self.add_pb)
        self.hor_layout.setSpacing(0)
        self.hor_layout.setContentsMargins(0,0,0,0);
        self.add_pb.setMaximumWidth(25)
        self.setLayout(self.hor_layout)


class TableParameterItem(pTypes.WidgetParameterItem):

    def __init__(self, param, depth):
        pTypes.WidgetParameterItem.__init__(self, param, depth)
        self.hideWidget = False
        self.subItem = QtGui.QTreeWidgetItem()
        self.addChild(self.subItem)

    def treeWidgetChanged(self):
        """
            Check for changement in the Widget tree.
        """
        ## TODO: fix so that superclass method can be called
        ## (WidgetParameter should just natively support this style)
        #WidgetParameterItem.treeWidgetChanged(self)
        self.treeWidget().setFirstItemColumnSpanned(self.subItem, True)
        self.treeWidget().setItemWidget(self.subItem, 0, self.widget)

        # for now, these are copied from ParameterItem.treeWidgetChanged
        self.setHidden(not self.param.opts.get('visible', True))
        self.setExpanded(self.param.opts.get('expanded', True))

    def makeWidget(self):
        """
            Make and initialize an instance of Table_custom.

            Returns
            -------
            table : instance of Table_custom.
                The initialized table.

            See Also
            --------
            Table_custom
        """
        table = Table_custom()
        table.setColumnCount(2)
        if 'header' in self.param.opts.keys():
            table.setHorizontalHeaderLabels(self.param.opts['header'])
        table.setMaximumHeight(200)
        #self.table.setReadOnly(self.param.opts.get('readonly', False))
        table.value = table.get_table_value
        table.setValue = table.set_table_value
        table.sigChanged =table.valuechanged
        self.widget = table.currentItemChanged
        return table


    def valueChanged(self, param, val, force=False):
        """
            Set a new value to the self widget.

            =============== ================================== ======================================
            **Parameters**    **Type**                           **Description**
            *param*           instance of pyqtgraph parameter    Not used
            *val*             data dictionnary                   The dictionnary to add at the table
            *force*           boolean                            Not used
            =============== ================================== ======================================

            See Also
            --------
            custom_parameter_tree.Table_custom.set_table_value
        """
        self.widget.set_table_value(val)

class Table_custom(QtWidgets.QTableWidget):
    """
        ============== ===========================
        *Attributes**    **Type**
        *valuechanged*   instance of pyqt Signal
        *QtWidgets*      instance of QTableWidget
        ============== ===========================
    """
    valuechanged=pyqtSignal(OrderedDict)
    def __init__(self):
        QtWidgets.QTableWidget.__init__(self)



    def get_table_value(self):
        """
            Get the contents of the self coursed table.

            Returns
            -------
            data : ordered dictionnary
                The getted values dictionnary.
        """
        data=OrderedDict([])
        for ind in range(self.rowCount()):
            item0=self.item(ind,0)
            item1=self.item(ind,1)
            if item0 is not None and item1 is not None:
                try:
                    data[item0.text()]=float(item1.text())
                except:
                    data[item0.text()]=item1.text()
        return data

    def set_table_value(self,data_dict):
        """
            Set the data values dictionnary to the custom table.

            =============== ====================== ================================================
            **Parameters**    **Type**               **Description**
            *data_dict*       ordered dictionnary    the contents to be stored in the custom table
            =============== ====================== ================================================
        """
        try:
            self.setRowCount(len(data_dict))
            self.setColumnCount(2)
            for ind,(key, value) in enumerate(data_dict.items()):
                item0=QtWidgets.QTableWidgetItem(key)
                item0.setFlags(item0.flags() ^ Qt.ItemIsEditable)
                item1=QtWidgets.QTableWidgetItem(str(value))
                item1.setFlags(item1.flags() ^ Qt.ItemIsEditable)
                self.setItem(ind,0,item0)
                self.setItem(ind,1,item1)
            self.valuechanged.emit(data_dict)
        except Exception as e:
            pass

class TableParameter(Parameter):
    """
        =============== =================================
        **Attributes**    **Type**
        *itemClass*       instance of TableParameterItem
        *Parameter*       instance of pyqtgraph parameter
        =============== =================================
    """
    itemClass = TableParameterItem
    """Editable string; displayed as large text box in the tree."""
    def __init__(self, *args, **kargs):
        Parameter.__init__(self, *args, **kargs)
       # self.sigValueChanged.connect(self.itemClass.valueChanged)
    #def setValue(self,val):
    #    self.itemClass.setValue(val)

registerParameterType('table', TableParameter, override=True)




class ItemSelectParameterItem(pTypes.WidgetParameterItem):

    def __init__(self, param, depth):
        pTypes.WidgetParameterItem.__init__(self, param, depth)
        self.hideWidget = False
        self.subItem = QtWidgets.QTreeWidgetItem()
        self.addChild(self.subItem)

    def treeWidgetChanged(self):
        """

        """
        ## TODO: fix so that superclass method can be called
        ## (WidgetParameter should just natively support this style)
        #WidgetParameterItem.treeWidgetChanged(self)
        self.treeWidget().setFirstItemColumnSpanned(self.subItem, True)
        self.treeWidget().setItemWidget(self.subItem, 0, self.widget)

        # for now, these are copied from ParameterItem.treeWidgetChanged
        self.setHidden(not self.param.opts.get('visible', True))
        self.setExpanded(self.param.opts.get('expanded', True))

    def makeWidget(self):
        """
            | Make and initialize an instance of ItemSelect_pb with itemselect value.
            | Connect the created object with the buttonClicked function.

        """
        opts = self.param.opts
        w = ItemSelect_pb()
        w.itemselect.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
        w.itemselect.setMaximumHeight(100)
        #w.setReadOnly(self.param.opts.get('readonly', False))
        if 'show_pb' in opts:
            w.add_pb.setVisible(opts['show_pb'])
        else:
            w.add_pb.setVisible(False)
        w.value = w.itemselect.get_value
        w.setValue = w.itemselect.set_value
        w.sigChanged = w.itemselect.itemSelectionChanged
        w.add_pb.clicked.connect(self.buttonClicked)
        return w

    def buttonClicked(self):
        """
           Append to the param attribute the dictionnary obtained from the QtWidget add parameter procedure.

           See Also
           --------
           custom_parameter_tree.value, custom_parameter_tree.ItemSelect.setValue
        """

        text,ok = QtWidgets.QInputDialog.getText(None,"Enter a value to add to the parameter",
                                            "String value:", QtWidgets.QLineEdit.Normal);
        if ok and not (text==""):
            all=self.param.value()['all_items']
            all.append(text)
            sel=self.param.value()['selected']
            sel.append(text)
            val=dict(all_items=all,selected=sel)
            self.param.setValue(val)
            self.param.sigValueChanged.emit(self.param, val)

    def optsChanged(self, param, opts):
        """
            Called when any options are changed that are not name, value, default, or limits.

            See Also
            --------
            optsChanged
        """
        #print "opts changed:", opts
        ParameterItem.optsChanged(self, param, opts)

        if 'show_pb' in opts:
            self.widget.add_pb.setVisible(opts['show_pb'])


class ItemSelect_pb(QtWidgets.QWidget):
    def __init__(self):
        QLocale.setDefault(QLocale(QLocale.English, QLocale.UnitedStates))
        super(ItemSelect_pb,self).__init__()
        self.initUI()

    def initUI(self):
        self.hor_layout=QtWidgets.QHBoxLayout()
        self.itemselect=ItemSelect()
        self.add_pb=QtWidgets.QPushButton()
        self.add_pb.setText("")
        icon3 = QtGui.QIcon()
        icon3.addPixmap(QtGui.QPixmap(":/Labview_icons/Icon_Library/Add2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.add_pb.setIcon(icon3)
        self.hor_layout.addWidget(self.itemselect)
        self.hor_layout.addWidget(self.add_pb)
        self.hor_layout.setSpacing(0)

        self.setLayout(self.hor_layout)


class ItemSelect(QtWidgets.QListWidget):
    def __init__(self):
        QtWidgets.QListWidget.__init__(self)

    def get_value(self):
        """
            Get the dictionnary of values contained in the QtWidget attribute.

            Returns
            -------
            dictionnary
                The dictionnary of all_items compared to the slelectedItems.
        """
        selitems=[item.text() for item in self.selectedItems()]
        allitems=[item.text() for item in self.all_items()]
        return dict(all_items=allitems,selected=selitems)

    def all_items(self):
        """
            Get the all_items list from the self QtWidget attribute.

            Returns
            -------
            list
                The item list.
        """
        return [self.item(ind) for ind in range(self.count())]

    def set_value(self,values):
        """
            Set values to the all_items attributes filtering values by the 'selected' key.

            =============== ============== =======================================
            **Parameters**    **Type**       **Description**
            *values*          dictionnary    the values dictionnary to be setted.
            =============== ============== =======================================
        """
        allitems=[item.text() for item in self.all_items()]
        if allitems !=values['all_items']:
            self.clear()
            self.addItems(values['all_items'])
        for item in self.all_items():
            if item.text() in values['selected']:
                item.setSelected(True)

class ItemSelectParameter(Parameter):
    """
        Editable string; displayed as large text box in the tree.

        =============== ======================================
        **Attributes**    **Type**
        *itemClass*       instance of ItemSelectParameterItem
        *sigActivated*    instance of pyqt Signal
        =============== ======================================
    """
    itemClass = ItemSelectParameterItem
    sigActivated = pyqtSignal(object)

    def activate(self):
        """
            Activate the "Activated" signal attribute0
        """
        self.sigActivated.emit(self)
        self.emitStateChanged('activated', None)

registerParameterType('itemselect', ItemSelectParameter, override=True)

class file_browserParameterItem(pTypes.WidgetParameterItem):

    def __init__(self, param, depth):
        self.filetype=False
        pTypes.WidgetParameterItem.__init__(self, param, depth)
        self.hideWidget = False
        self.subItem = QtWidgets.QTreeWidgetItem()
        self.addChild(self.subItem)
        

    def treeWidgetChanged(self):
        ## TODO: fix so that superclass method can be called
        ## (WidgetParameter should just natively support this style)
        #WidgetParameterItem.treeWidgetChanged(self)
        self.treeWidget().setFirstItemColumnSpanned(self.subItem, True)
        self.treeWidget().setItemWidget(self.subItem, 0, self.w)

        # for now, these are copied from ParameterItem.treeWidgetChanged
        self.setHidden(not self.param.opts.get('visible', True))
        self.setExpanded(self.param.opts.get('expanded', True))

    def makeWidget(self):
        """
            Make an initialized file_browser object with parameter options dictionnary ('readonly' key)0

            Returns
            -------
            w : filebrowser
                The initialized file browser.

            See Also
            --------
            file_browser
        """
        if 'filetype' in self.param.opts:
            self.filetype = self.param.opts['filetype']
        else:
            self.filetype = True

        self.w = file_browser(self.param.value(),file_type=self.filetype)
        #self.file_browser.setMaximumHeight(100)
        self.w.base_path_edit.setReadOnly(self.param.opts.get('readonly', False))
        self.w.value = self.w.get_value
        self.w.setValue = self.w.set_path
        self.w.sigChanged = self.w.value_changed
        return self.w

class file_browser(QtWidgets.QWidget):
    """
        ================ =========================
        **Attributes**    **Type**
        *value_changed*   instance of pyqt Signal
        *path*            string
        ================ =========================

        See Also
        --------
        browse_path
    """
    value_changed=pyqtSignal(str)
    def __init__(self,init_path='D:/Data',file_type=False):
        QLocale.setDefault(QLocale(QLocale.English, QLocale.UnitedStates))
        super(file_browser,self).__init__()
        self.filetype=file_type
        self.path=init_path
        self.initUI()

        self.base_path_browse_pb.clicked.connect(self.browse_path)


    def browse_path(self):
        """
            Browse the path attribute if exist.

            See Also
            --------
            set_path
        """
        if self.filetype is True:
            folder_name = QtWidgets.QFileDialog.getOpenFileName(None,'Choose File',self.path)[0]
        elif self.filetype is False:
            folder_name = QtWidgets.QFileDialog.getExistingDirectory(None,'Choose Folder',self.path)

        elif self.filetype == "save":
            folder_name = QtWidgets.QFileDialog.getSaveFileName(None,'Enter a Filename', self.path)[0]

        if not( not(folder_name)): #execute if the user didn't cancel the file selection
             self.set_path(folder_name)
             self.value_changed.emit(folder_name)

    def set_path(self,path_file):
        """
            Set the base path attribute with the given path_file.

            =============== =========== ===========================
            **Parameters**    **Type**    **Description**
            *path_file*       string      the pathname of the file
            =============== =========== ===========================
        """
        self.base_path_edit.setPlainText(path_file)

    def get_value(self):
        """
            Get the value of the base_path_edit attribute.

            Returns
            -------
            string
                the path name
        """
        return self.base_path_edit.toPlainText()


    def initUI(self):
        """
            Init the User Interface.
        """

        self.hor_layout=QtWidgets.QHBoxLayout()
        self.base_path_edit=QtWidgets.QPlainTextEdit(self.path)
        self.base_path_edit.setMaximumHeight(50)
        self.base_path_edit.setReadOnly(True)
        self.base_path_browse_pb=QtWidgets.QPushButton()
        self.base_path_browse_pb.setText("")
        icon3 = QtGui.QIcon()
        icon3.addPixmap(QtGui.QPixmap(":/Labview_icons/Icon_Library/Browse_Dir_Path.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.base_path_browse_pb.setIcon(icon3)
        self.hor_layout.addWidget(self.base_path_edit)

        verlayout=QtWidgets.QVBoxLayout()
        verlayout.addWidget(self.base_path_browse_pb)
        verlayout.addStretch()
        self.hor_layout.addLayout(verlayout)
        self.hor_layout.setSpacing(0)

        self.setLayout(self.hor_layout)

class file_browserParameter(Parameter):
    """
        Editable string; displayed as large text box in the tree.
        
        See Also
        --------
        file_browserParameterItem
    """
    itemClass = file_browserParameterItem

registerParameterType('browsepath', file_browserParameter, override=True)

class Plain_text_pbParameterItem(pTypes.WidgetParameterItem):

    def __init__(self, param, depth):
        pTypes.WidgetParameterItem.__init__(self, param, depth)
        self.hideWidget = False
        self.subItem = QtWidgets.QTreeWidgetItem()
        self.addChild(self.subItem)

    def treeWidgetChanged(self):
        ## TODO: fix so that superclass method can be called
        ## (WidgetParameter should just natively support this style)
        #WidgetParameterItem.treeWidgetChanged(self)
        self.treeWidget().setFirstItemColumnSpanned(self.subItem, True)
        self.treeWidget().setItemWidget(self.subItem, 0, self.w)

        # for now, these are copied from ParameterItem.treeWidgetChanged
        self.setHidden(not self.param.opts.get('visible', True))
        self.setExpanded(self.param.opts.get('expanded', True))

    def makeWidget(self):
        """
            Make and initialize an instance of Plain_text_pb object from parameter options dictionnary (using 'readonly' key).

            Returns
            -------
            Plain_text_pb object
                The initialized object.

            See Also
            --------
            Plain_text_pb, buttonClicked
        """
        self.w = Plain_text_pb()
        self.w.text_edit.setReadOnly(self.param.opts.get('readonly', False))
        self.w.value = self.w.get_value
        self.w.setValue = self.w.set_value
        self.w.sigChanged = self.w.value_changed
        self.w.add_pb.clicked.connect(self.buttonClicked)
        return self.w

    def buttonClicked(self):
        """
            Activate the parameter attribute.

            See Also
            --------
            custom_parameter_tree.ItemSelectParameter.activate
        """
        self.param.activate()

class Plain_text_pb(QtWidgets.QWidget):
    """
        ================ ========================
        **Attributes**    **Type**
        *value_changed*   instance of pyqt Signal
        ================ ========================

        See Also
        --------
        initUI, emitsignal
    """
    value_changed=pyqtSignal(str)
    def __init__(self):
        QLocale.setDefault(QLocale(QLocale.English, QLocale.UnitedStates))
        super(Plain_text_pb,self).__init__()

        self.initUI()
        self.text_edit.textChanged.connect(self.emitsignal)

    def emitsignal(self):
        """
            Emit the value changed signal from the text_edit attribute.
        """
        text=self.text_edit.toPlainText()
        self.value_changed.emit(text)

    def set_value(self,txt):
        """
            Set the value of the text_edit attribute.

            =============== =========== ================================
            **Parameters**    **Type**    **Description**
            *txt*             string      the string value to be setted
            =============== =========== ================================
        """
        self.text_edit.setPlainText(txt)

    def get_value(self):
        """
            Get the value of the text_edit attribute.

            Returns
            -------
            string
                The string value of text_edit.
        """
        return self.text_edit.toPlainText()


    def initUI(self):
        """
            Init the User Interface.
        """

        self.hor_layout=QtWidgets.QHBoxLayout()
        self.text_edit=QtWidgets.QPlainTextEdit()
        self.text_edit.setReadOnly(True)
        self.text_edit.setMaximumHeight(50)

        self.add_pb=QtWidgets.QPushButton()
        self.add_pb.setText("")
        icon3 = QtGui.QIcon()
        icon3.addPixmap(QtGui.QPixmap(":/Labview_icons/Icon_Library/Add2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.add_pb.setIcon(icon3)
        self.hor_layout.addWidget(self.text_edit)


        verlayout=QtWidgets.QVBoxLayout()
        verlayout.addWidget(self.add_pb)
        verlayout.addStretch()
        self.hor_layout.addLayout(verlayout)
        self.hor_layout.setSpacing(0)
        self.setLayout(self.hor_layout)
class Plain_text_pbParameter(Parameter):
    """Editable string; displayed as large text box in the tree."""
    itemClass = Plain_text_pbParameterItem
    sigActivated = pyqtSignal(object)

    def activate(self):
        """
            Send the Activated signal.
        """
        self.sigActivated.emit(self)
        self.emitStateChanged('activated', None)
registerParameterType('text_pb', Plain_text_pbParameter, override=True)







if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv);
    ex=QTimeCustom()
    ex.setMinuteIncrement(30)
    ex.show()
    sys.exit(app.exec_())