# -*- coding: utf-8 -*-
from functools import partial
import os
import math
from io import StringIO
from datetime import datetime
from collections import OrderedDict
from functools import partial
import re
import glob

import xml.dom.minidom as dom  # @UnresolvedImport
import wx.lib.buttons as buttons
import wx.lib.mixins.inspection
import wx.lib.mixins.listctrl as listmix
from wx.lib.mixins.listctrl import CheckListCtrlMixin  # @UnusedImport
import wx.grid
import wx.lib.agw.foldpanelbar as fpb
import wx.lib.scrolledpanel as scrolled
import wx.lib.gridmovers as gridmovers
import wx.lib.popupctl as pop
import p2cpython as cad
from p2cpython import getPath, getCurrentDoc, getMessageW, mm, UNITS_TYPE, BEHAVIOUR, FORMAT  # @UnusedImport
from p2c.utils import removeTrailingZeros, IsMethod, CheckIfMethodOK, ConvertCheckFloat, ConvertCheckInt, ConvertCheckStr, GetOptimalValueBack, ConvertCheckUnicode  # @UnusedImport
from p2c.utils import logger, _DEBUG # Debug
optLogger = cad.BasePy()

# Add a doc, to get doc's py object pointer!
# on doc  GetPyObj
# on base GetPyObj

DIALOG_TYPE_STRING  = "pythonDialog"
MESSAGE_TYPE_STRING = "PYTHON"
DIALOG_TITLE_STRING = "Optionen"

# !!! This module knows nothing about our special stuff like turntool or postprocessors
# !!!   therefore it's important NOT TO IMPORT any modules/attributes from any special stuff

# Display and Scale

FontScaleFactor   = 1.0
ScreenScaleFactor = 1.0

# cad.DebLogA('window.py 0!')

"""

Thus, the first thing do when preparing your application for high DPI support is to stop using raw pixel values. 
Actually, using any pixel values is not recommended and replacing them with the values based on the text metrics, 
i.e. obtained using wx.Window.GetTextExtent, 
or expressing them in dialog units (see wx.Window.ConvertDialogToPixels) is preferable. 
However the simplest change is to just replace the pixel values with the values in DIP: 
for this, just use wx.Window.FromDIP to convert from one to the other.

For example, if you have the existing code:
myFrame.SetClientSize(wx.Size(400, 300))

you can just replace it with:

myFrame.SetClientSize(myFrame.FromDIP(wx.Size(400, 300)))


bmp = wx.Bitmap(self.FromDIP(32, 32))

"""

# Do not scale bmp, icon, png files, system does it for us!
# 03/28/2025
ScreenScaleFactorNeeded = 1.0

def GetDPIScaleFactor():
    if optLogger is not None:
        global ScreenScaleFactorNeeded
        if hasattr(optLogger, "GetDPIScaleFactor"):
            ScreenScaleFactorNeeded = optLogger.GetDPIScaleFactor(None)

def ComputeScreenScale():
    """
    Compute the screen scale.
    A global variable to hold the scaling from pixel size to point size.
    Handles different screen resolutions (usually we have ScreenScaleFactor=1.0 and 96 DPI)
    
    scale = wx.GetApp().GetTopWindow().GetContentScaleFactor()    # this doesn't work in current version , is always 1.0 -> should work in Version > 4.07

    """
    global ScreenScaleFactor
    dc = wx.ScreenDC()
    xPPI, yPPI = dc.GetPPI()
    scaleX = xPPI / 96  # @UnusedVariable
    scaleY = yPPI / 96
    ScreenScaleFactor = scaleY      # normally x and y scales are equal, but if not, I think the y scaling is more important
    # Set back to 1.0 it doesn't match exactly!
    # But it looks better.
    ScreenScaleFactor = 1.0
    del dc

def ComputeFontScale():
    """
    Compute the font scale.
    A global variable to hold the scaling from pixel size to point size.
    """
    global FontScaleFactor
    dc = wx.ScreenDC()
    dc.SetFont(wx.Font(16, wx.FONTFAMILY_ROMAN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
    E = dc.GetTextExtent("X")
    FontScaleFactor = 16/E[1]
    # Set it back to 1.0 it doesn't match exactly!
    # But it looks better.
    FontScaleFactor = 1.0
    del dc

GetDPIScaleFactor()
ComputeScreenScale()
#ComputeFontScale()        # not used atm. but it's working fine if we will need this in the future

# Layout-things for the dialog stuff
NOBORDER     = 0
MINIBORDER   = int(2  * ScreenScaleFactor)
SMALLBORDER  = int(5  * ScreenScaleFactor)
BORDER       = int(10 * ScreenScaleFactor)
MEDIUMBORDER = int(20 * ScreenScaleFactor)
BIGBORDER    = int(30 * ScreenScaleFactor)
SPACER = (BORDER, BORDER)   # provides a little space when widgets are placed in sizers

TOOLTIP_DELAYTIME = 1000   # ToolTip delay time (ms)
TOOLTIP_HOLDTIME  = 5000   # ToolTip showing time (ms) - None means forever

DEFAULT_SCROLL_BEHAVIOUR = True     # turn default scroll behaviour on/off

# there is a good color-demo in: wxPython DEMO - Miscellaneous - ColorDB
GREEN  = "#64F538"      # set #2
MINTGREEN  = "#C3F538"  # set #2
LIGHTYELLOW = wx.Colour(252, 254, 214, 255)
COLOUR_SELECTED = 'yellow'
PINK = wx.Colour('PINK')
COLOR_INVALID_INPUT = '#FFE7BA' # 'WHEAT1'
# we can also get SYSTEM_COLOURS (-> wxPython DEMO - Miscellaneous - SystemSettings)
HIGHLIGHT     = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT)    # Item(s) selected in a control.
HIGHLIGHTTEXT = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)    # Text of item(s) selected in a control.
INFOTEXT      = wx.SystemSettings.GetColour(wx.SYS_COLOUR_INFOTEXT) # Text colour for tooltip controls.
INFOBK        = wx.SystemSettings.GetColour(wx.SYS_COLOUR_INFOBK)   # Background colour for tooltip controls.
COLOUR_WINDOW = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)   # System default window colour.
COLOUR_SCROLLBAR = wx.SystemSettings.GetColour(wx.SYS_COLOUR_SCROLLBAR)   # System default scrollbar colour.
COLOUR_ACTIVEBORDER = wx.SystemSettings.GetColour(wx.SYS_COLOUR_ACTIVEBORDER)   # System default ... colour.

SYSTEM_FONT    = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT)         # some SystemFonts
ICONTITLE_FONT = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT)         # SYS_ICONTITLE_FONT

# ICON_X = 20   # icon size C++ ??
# ICON_Y = 24
ICON_X = wx.SystemSettings.GetMetric(wx.SYS_ICON_X)     # system icon size
ICON_Y = wx.SystemSettings.GetMetric(wx.SYS_ICON_Y)

# Setting up pathes
messagePath = os.path.normpath( getPath("message") ) + '\\'   # u'c:\\Program Files\\SolidWorks Corp\\SolidWorks\\opticam\\Wire\\messages'
#binPath     = os.path.normpath( getPath(u"bin") )       # u'c:\\Program Files\\SolidWorks Corp\\SolidWorks\\opticam\\bin'
#dataPath    = os.path.normpath( getPath(u"data") )      # u'C:\\Projekte\\Opticam\\svn_v0\\ProgramData\\trunk\\opticam'
#iconsDir    = os.path.normpath( getPath(u"icons") )      # not implemented yet
postPath    = os.path.normpath( getPath("post") ) + '\\'      # u'C:\\Projekte\\Opticam\\svn_v0\\ProgramData\\trunk\\opticam\\Posts'
iconsDir    = os.path.normpath( getPath("bin") ) + '\\python3\\p2c\\Icons\\'
# for us developers usually the env var %OC_COMMON_SCRIPT_PATH% is set. (in versions older than 2013 it's %OPTICAM_SCRIPT_PATH%)
if "OC_COMMON_SCRIPT_PATH" in os.environ:   # e.g. 'C:/Projekte/Opticam/svn_v0/release/trunk/opticam/bin/Python'
    iconsDir    = os.path.normpath( os.environ['OC_COMMON_SCRIPT_PATH'] ) + '\\p2c\\Icons\\'
elif "OPTICAM_SCRIPT_PATH" in os.environ:   # ...look at the older variable too
    iconsDir    = os.path.normpath( os.environ['OPTICAM_SCRIPT_PATH'] ) + '\\p2c\\Icons\\'

#+++++++++++ TRANSLATION +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# pp-related stuff is in   <messagePath>/POST(<language>).xml   (get with cad.getMessageW("def", "cad.POST_MESSAGES, index)
# comon stuff is in        <messagePath>/PYTHON(<language>).xml (get with cad.getMessageW("def", "cad.PYTHON_MESSAGES, index)
translatedText = None   # if a translation-xml file was found, here I store the translated texts

# Wenn es ein ModalDialog werden soll, dann brauchen wir den App-Handle um
# Wenn es ein ModlessDialog werden soll, dann langt der Doc-Handle ohne Manipulation
# Am besten Ohne X oben rechts
#  style=wx.DEFAULT_DIALOG_STYLE|wx.THICK_FRAME|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL
# style=wx.CAPTION|wx.THICK_FRAME|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL
PINBUTTON_DOCKED   = 'pinup.ico'      # needle down
PINBUTTON_UNDOCKED = 'pindown.ico'    # needle horizontal
OPEN_FILE_ICON     = 'OpenFile_transparent.ico'
OPEN_FILE_DISABLED_ICON = 'OpenFile_transparent.ico'
#OPEN_FILE_ICON     = "Tab als Ordner 1.png"
#OPEN_FILE_ICON     = "3_Load Default_Liste.ico"

#*** Use these to or to an opticam.MessageBoxWExt() enum, such as opticam.WINDOW_OK, to add the icon you want. This
#*** message box is only really needed for messages that pop up without a parent dialog, so that the 
#*** box is centred about the app window. Otherwise, wx.MessageBox works fine:
MSG_ICON_Critical = 16
MSG_ICON_Question = 32 
MSG_ICON_Exclamation = 48
MSG_ICON_Information = 64
LOG_TAG = "p2c.window   "


__author__ = 'Thompson'
__maintainer__  = [c for c in '$Author: NimkeL $' if c not in list("$")]
__url__ = 'http://www.camtek.de/'
__version__ = '0.2'
__revision__ = list(filter(str.isdigit, "$Revision: 16487 $")) # for PEPS V8.1
__status__ = 'Beta'
__date__ = '2014-12-16'
__updated__ = '2022-10-05'

"""
The following samples assume the default key sequence (*ctrl-alt-i*) to start
the WIT, additional information can be found on the following wiki page.

http://wiki.wxpython.org/Widget_Inspection_Tool

You can also structure your application so that the inspection tool is activated via a hot-key,
and it will also preselect the item under the mouse cursor when the tool is shown.
This is accomplished by adding a mixin class to your own application class.
The default hot-key when you use the inspection tool mixin like this is Ctrl-Alt-I, or Cmd-Alt-I on Mac, but that can be changed by passing non-default parameters to the Init method.
The default position and size can also be changed. 
For example: 
"""
class MyApp(wx.App, wx.lib.mixins.inspection.InspectionMixin):
    def OnInit(self):
        wx.lib.mixins.inspection.InspectionMixin.Init(self)
        wx.lib.mixins.inspection.InspectionMixin.ShowInspectionTool(self)
        return True

def existsAndIsReadable(filename):
    return os.access(filename, os.F_OK) and os.access(filename, os.R_OK)

def standardPaths():
    wx.GetApp().SetAppName("AppName")
    sp = wx.StandardPaths.Get()
    sp.GetUserDataDir()         # u'J:\\Dokumente und Einstellungen\\Gerold\\Anwendungsdaten\\AppName'
    sp.GetUserLocalDataDir()    # u'J:\\Dokumente und Einstellungen\\Gerold\\Lokale Einstellungen\\Anwendungsdaten\\AppName'

def ShowDialogFromList(name, *args, **kwargs):
    return BaseDialog.ShowDialogFromList(name, *args, **kwargs)
def ShowDialogFromListEx(name, *args, **kwargs):
    return BaseDialog.ShowDialogFromListEx(name, *args, **kwargs)
def SetTooltipHoldingTime(time):
    global TOOLTIP_HOLDTIME
    TOOLTIP_HOLDTIME = time
def ResetTooltipHoldingTime():
    global TOOLTIP_HOLDTIME
    TOOLTIP_HOLDTIME = 5000
def GetTooltipHoldingTime():
    return TOOLTIP_HOLDTIME
    
class BaseDialog(wx.Dialog):
    #---------- Seems important for initializing graphical objects !! -----------
    # The stock objects are no longer created when the wx._core_ module is
    # imported, but only after the app object has been created. (The
    # wxPy_ReinitS function will be called 3 times to pass the stock
    # objects though various stages of evolution)
    # -> Normally the following method is called from _core.App.OnPreInit() when the
    # wx.App object is created (but we must do it ourself).
    wx.StockGDI._initStockObjects()
    #
    # CLASS VARIABLES
    instanceList = []       # for checking for already running instances (NOW PROBABLY OBSOLETE -> COULD BE DELETED , BUT FOR SAFETY REASONS NOT NOW)
    #
    # activate this in main system with <shift-ctrl-F9>
    ResetFlag = False       # could be used to restore saved dialog settings to default
    #
    # Reset arguments buffers (new : 2023/07/25)
    argsBuffer = ()
    kwargsBuffer = {}
    #----------------------------------------------------------------------------
    # style=wx.CAPTION|wx.THICK_FRAME|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL,

    def __init__(self,
                 parent=None,
                 title='OPTICAM',
                 modal=False,
                 size=wx.DefaultSize,
                 pos=wx.DefaultPosition,
                 name="DLG_MAIN",
                 haveOpticam=True,
                 style=wx.CAPTION|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL,
                 dialogWin=None,
                 dialogButtonStyle="OPTICAM_STYLE_IS_NICE_BUTTONS",
                 statusbar=None,
                 AllowOnlyOneInstance=False, #Allow Entirely only one BAseDialog instance @UnusedVariable
                 AllowOnlyOneInstanceType=False, #Allow only one instance of this Dialog (DEPRECATED -> DELETE IN THE FUTURE) @UnusedVariable
                 scrollable=DEFAULT_SCROLL_BEHAVIOUR,       # set ability for scrolling
                 docked=False,                              # set initial docking state
                 iconMFCStyle=True,
                 iconShowSave = False,
                 messageFileName = None,
                 tabbed = False
                 ):
        #
        self.childDialogs = []                  # list for storing child dialogs: to guarantee correct order for creation and destroying
        #
        if isinstance(parent, BaseDialog):
            parent.childDialogs.append(self)  # put dialog in a list and activate later (after the parent is activated -> so we guarantee the correct order for destroying at the end)
        #logger.info(LOG_TAG + "%s.%s :  parent.__class__.__name__=%s  parent.Name=%s  parent.Children=%d" % (self.__class__.__name__, "__init__()", parent.__class__.__name__, parent.Name, parent.Children.__len__()))
        #
        #*** Styles for buttons, really the only one checked is the first one (otherwise, OK and CANCEL):
        #***    OPTICAM_STYLE_IS_NICE_BUTTONS 
        #***    OPTICAM_STYLE_IS_PEPS_OK_CANCEL_TYPE_BUTTONS 
        #***    OPTICAM_STYLE_IS_LOOK_LIKE_MACHINE_CONTROL 
        #
        self.modal = modal
        self.statusbar = statusbar              # (optional Statusbar in lower window area)
        self.scrollable = scrollable            # initial scroll behaviour (true/false)
        self.docked = docked                    # state at the beginning
        self.haveOpticam = haveOpticam
        self.initialized = False
        self.active = False
        self.iconMFCStyle=iconMFCStyle          # The so-called mfc style is OK, Cancel buttons are aligned to the left rand, and Doc button is aligned to the right.
        self.iconShowSave = iconShowSave
        self.dialogName = name      #self.__class__.__name__       # at the moment I take the class-name as dialog name (TranslationFile) and configfile-name
        self.preCreateMode = False              # is set to True when dialog-window is added to modeless-list (then this dialog is only shown or hided)
        self.tabbed = tabbed                     # Dialog is using the notebook widget to create tabs for each group page
        #
        optLogger.LogA("[Python] BaseDialog.Init (%s)" % self.dialogName)
        #
        self.size = size
        self.position = pos
        self.style = style
        self.dockStyle = wx.TAB_TRAVERSAL       # the prefered style for docked mode
        #
        # Put everything in a VERTICAL wxBoxSizer       (Mainsizer)
        self.vbxV1 = wx.BoxSizer( wx.VERTICAL )
        # Add Horizontal Sizer for the NiceButtons      (Subsizer; child of Mainsizer)
        if self.iconMFCStyle:
            self.vbxH1 = wx.GridBagSizer(1,)
            self.vbxH1.Add((0, 0), (0, 6), (1, 1), wx.EXPAND)
            self.vbxH1.AddGrowableRow(0)
            self.vbxH1.AddGrowableCol(6)
        else:
            self.vbxH1 = wx.BoxSizer( wx.HORIZONTAL )
        #
        self.doc = getCurrentDoc()
        # Now we can use objects directly from p2cpython if there is no document! (extension for opticam-free run-environment)
        if self.doc is None:
            if not hasattr(cad, "GetPyObj"):
                raise ReferenceError('BaseDialog: no document!')
            self.obj = cad.GetPyObj()
        else:
            self.obj = self.doc.GetPyObj()
        #        
        info = cad.BasePy().GetInfoEx()
        yearName = info.get('OC_YEAR', 'TRUNK')
        cadName  = info.get('CAD_NAME', 'XCAD')
        if self.doc.GetMachine():
            if hasattr(self.doc.GetMachine(), 'Name'):
                machName = self.doc.GetMachine().Name.getPyString()
            else:
                machName = 'unknown-machine'
        else:
            machName = 'unknown-machine'
        self._IsShown = False      # state of window in previous session (is read from config-file)
        
        if self.dialogName != 'XXX':
            if False:    # True: save dialog-setting in file / else in registry
                self._configFile = os.path.join(cad.getThisPostPath(), self.dialogName + ".ini")     # 'D:\\develop\\opticam\\oc_release\\scripts\\public\\branches\\version_2019_01\\opticam\\posts3\\ACCUT\\ACCutPostOptionsDialog'       
            else:                                                            # 'C:\ProgramData\opticam\2019.1\hcnt\wire\posts3\accut\
                self._configFile = None     # use registry
            
            # using wx.Config instead of writing wx.FileConfig or wx.RegConfig enhances portability of the code
            if self._configFile:    # and existsAndIsReadable(self._configFile):
                self.cfg = wx.FileConfig(localFilename=self._configFile)
                self._configReg  = "WINDOW"     # self.dialogName
            else:
                self.cfg = wx.Config("Camtek")
                self._configReg  = "/OPTICAM/{0}/{1}/posts3/{2}/{3}".format(yearName, cadName, machName, self.dialogName)
                # for example: 'Computer\HKEY_CURRENT_USER\Software\Camtek\OPTICAM\2023.1\NG_PEPS\posts3\standard\PostOptionsDialog'
            #
            self.LoadDialogSettings(self.cfg)       # look for eventually saved dialog settings
        #
        # First we read the appropriate language xml-file (if one exists)
        global translatedText
        self.messageFileName = messageFileName or self.__class__.__name__
        translatedText = readDialogFile(messagePath, self.messageFileName)
        self.currentLanguage = cad.getLanguageW()
        #
        self._resourcelabel = title
        self.title = title = getText(title, name)
        #
        if not dialogWin:
            #
            wx.Dialog.__init__(self, parent, wx.ID_ANY, title,
                               size=self.size,
                               pos=self.position,
                               style=self.style,
                               name=name)
            logger.debug("%s%s%s" % (self.__class__.__name__ , ".__init__ -> PLUM", self.GetParent().__class__.__name__))
            if _DEBUG & 0x4: self.SetBackgroundColour('PLUM')

            # this Panel serves as Parent of all widgets we will create (if needed it can get a title)
            if scrollable and not self.tabbed:
                self.panel = ScrolledBasePanel(self, wx.ID_ANY, label="")
            else:   
                self.panel = BasePanel(self, wx.ID_ANY, label="")
            
            self.titleBar = wx.StaticText(self.panel, wx.ID_ANY, "OPTICAM    " + title, name="_" + "panelTitle")
            self.titleBar.SetBackgroundColour(COLOUR_SCROLLBAR)
            self.vbxV1.Add(self.titleBar, 0, wx.EXPAND)
            self.vbxV1.Show(self.titleBar, self.docked)

            self.vbxV1.Add(self.vbxH1, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, BORDER)
            # 08/15/2025 That doesn't work as expected!
            self.btnOK = NiceButton(self.panel, wx.ID_OK, 'okup.ico', 'okdown.ico', 'okup_grey.ico', name="BTN_OK", scale = False)
            self.btnOK.SetToolTipString("OK")
            self.btnOK.Bind(wx.EVT_BUTTON, self.OnOK)
            if not self.iconMFCStyle:
                self.vbxH1.Add(self.btnOK, 1)
            else:
                self.vbxH1.Add(self.btnOK, (0, 0), flag=wx.LEFT, border=BORDER)
            
            # 08/15/2025 That doesn't work as expected!
            self.btnESC = NiceButton(self.panel, wx.ID_CANCEL, 'cancelup.ico', 'canceldown.ico', 'cancelup_grey.ico', name="BTN_CANCEL", scale = False)
            self.btnESC.SetToolTipString("Cancel")
            self.btnESC.Bind(wx.EVT_BUTTON, self.OnESC)
            if not self.iconMFCStyle:
                self.vbxH1.Add(self.btnESC, 1)
            else:
                self.vbxH1.Add(self.btnESC, (0, 1))

            # 08/15/2025 That doesn't work as expected!
            self.btnHelp = NiceButton(self.panel, wx.ID_HELP, 'helpup.ico', 'helpdown.ico', 'helpup_grey.ico', name="BTN_HELP", scale = False)
            self.btnHelp.SetToolTipString("Help")
            self.btnHelp.Bind(wx.EVT_BUTTON, self.OnHelp)
            if not self.iconMFCStyle:
                self.vbxH1.Add(self.btnHelp, 1)
            else:
                self.vbxH1.Add(self.btnHelp, (0, 2))
                
            # Create the Dialog
            if self.iconShowSave:
                if _DEBUG & 0x4:
                    self.btnSave = NiceButton(self.panel, wx.ID_SAVE, 'savedefault.ico', 'Warning.ico', name="BTN_SAVESETTINGS")
                else:
                    self.btnSave = NiceButton(self.panel, wx.ID_SAVE, 'savedefault.ico', 'savedefault_OK.ico', name="BTN_SAVESETTINGS", pressed=True)
                self.btnSave.SetToolTipString("Save settings")
                self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
                if not self.iconMFCStyle:
                    self.vbxH1.Add(self.btnSave, 1)
                else:
                    self.vbxH1.Add(self.btnSave, (0, 3))
            else:
                self.vbxH1.Add((BORDER, 1), (0, 3))

            if os.environ.get('OPTICAM_CREATE_WIDGETS_LIST', '').upper() == 'TRUE':
                self.btnWList = NormalButton( self.panel, wx.ID_ANY, "Widgetslist", name='_BTN_WIDGETS_LIST' )
                self.btnWList.SetToolTipString("Make a list containig all widgets of this dialog.")
                self.btnWList.Bind(wx.EVT_BUTTON, self.OnCreateWidgesList)
                if not self.iconMFCStyle:
                    self.vbxH1.Add(self.btnWList, 1)
                else:
                    self.vbxH1.Add(self.btnWList, (0, 4), border=BORDER)
            else:
                self.vbxH1.Add((BORDER, 1), (0, 4))
                
            if os.environ.get('OPTICAM_START_WIDGETS_INSPECTOR', '').upper() == 'TRUE':
                self.btnWInsp = NormalButton( self.panel, wx.ID_ANY, "Widgetsinspector", name='_BTN_WIDGETS_INSPECTOR' )
                self.btnWInsp.SetToolTipString("Start the widgets inspection tool.")
                self.btnWInsp.Bind(wx.EVT_BUTTON, self.OnStartWidgesInspector)
                if not self.iconMFCStyle:
                    self.vbxH1.Add(self.btnWInsp, 1)
                else:
                    self.vbxH1.Add(self.btnWInsp, (0, 5), border=BORDER)
                # Display changed
                self.title = title
                #self.SetTitle( self.title + " (Scale=%.0f%%)" % (ScreenScaleFactor * 100) )
                self.SetTitle( self.title )
                self.Bind(wx.EVT_DISPLAY_CHANGED, self.OnDisplayChanged)     # atm. we do nothing with this event (it seems new resolution in not updated immediately)
            else:
                self.vbxH1.Add((BORDER, 1), (0, 5))
                
            if os.environ.get('OPTICAM_LANGUAGE_TRANSLATOR', '').upper() == 'TRUE':
                self.btnTRA = NiceButton(self.panel, wx.ID_ANY, 'translator.ico', name="BTN_TRANSLATOR")
                self.btnTRA.SetToolTipString("Translation")
                self.btnTRA.Bind(wx.EVT_BUTTON, self.OnTranslate)
                if not self.iconMFCStyle:
                    self.vbxH1.Add(self.btnTRA, 1)
                else:
                    self.vbxH1.Add(self.btnTRA, (0, 7))
            else:
                self.vbxH1.Add((BORDER, 1), (0, 7))

            self.btnDOC = NiceButton(self.panel, wx.ID_ANY, PINBUTTON_UNDOCKED, name="BTN_PIN")
            #self.btnDOC = NiceToggleButton(self.panel, wx.ID_ANY, PINBUTTON_UNDOCKED, name="BTN_PIN")
            
            self.btnDOC.SetToolTipString("Pin")
            self.btnDOC.Bind(wx.EVT_BUTTON, self.OnDock)
            if not self.iconMFCStyle:
                self.vbxH1.Add(self.btnDOC, 1)
            else:
                self.vbxH1.Add(self.btnDOC, (0, 8), flag=wx.RIGHT, border=BORDER)
            
            #
        else:
            # This is a new Method to show all Dialogs in True Modal Mode (User input outside the python dialog is locked)
            # No longer experimental, is used in tdb.py. And it works.
            self.preCreateMode = True
            #
            logger.debug("%s%s" % (self.__class__.__name__ , ".__init__"))
            # Instead of calling wx.Dialog.__init__ we precreate the dialog
            # so we can set an extra style that must be set before
            # creation, and then we create the GUI object using the Create
            # method.
            wx.Dialog.__init__(self, parent, wx.ID_ANY, title,
                               size=size,
                               pos=pos,
                               style=style,
                               name=name)
            logger.debug("%s%s%s" % (self.__class__.__name__ , ".__init__ -> PLUM", self.GetParent().__class__.__name__))
            if _DEBUG & 0x4: self.SetBackgroundColour('PLUM')

            # this Panel serves as Parent of all widgets we will create (if needed it can get a title)
            if scrollable and not self.tabbed:
                self.panel = ScrolledBasePanel(self, wx.ID_ANY, label="")
            else:
                self.panel = BasePanel(self, wx.ID_ANY, label="")

            self.vbxV1.Add(self.vbxH1, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, BORDER)

            if dialogButtonStyle.__contains__( "OPTICAM_STYLE_IS_NICE_BUTTONS"):

                self.btnOK = NiceButton(self.panel, wx.ID_OK, 'okup.ico', 'okdown.ico', 'okup_grey.ico', name="BTN_OK")
                self.btnOK.SetToolTipString("OK")
                self.btnOK.Bind(wx.EVT_BUTTON, self.OnOK)
                if not self.iconMFCStyle:
                    self.vbxH1.Add(self.btnOK, 1)
                else:
                    self.vbxH1.Add(self.btnOK, (0, 0), flag=wx.LEFT, border=BORDER)

                self.btnESC = NiceButton(self.panel, wx.ID_CANCEL, 'cancelup.ico', 'canceldown.ico', 'cancelup_grey.ico', name="BTN_CANCEL")
                self.btnESC.SetToolTipString("Cancel")
                self.btnESC.Bind(wx.EVT_BUTTON, self.OnESC)
                if not self.iconMFCStyle:
                    self.vbxH1.Add(self.btnESC, 1)
                else:
                    self.vbxH1.Add(self.btnESC, (0, 1))

                self.btnHelp = NiceButton(self.panel, wx.ID_HELP, 'helpup.ico', 'helpdown.ico', 'helpup_grey.ico', name="BTN_HELP")
                self.btnHelp.SetToolTipString("Help")
                self.btnHelp.Bind(wx.EVT_BUTTON, self.OnHelp)
                if not self.iconMFCStyle:
                    self.vbxH1.Add(self.btnHelp, 1)
                else:
                    self.vbxH1.Add(self.btnHelp, (0, 2))
                
                # Create the Dialog
                if self.iconShowSave:
                    if _DEBUG:
                        self.btnSave = NiceButton(self.panel, wx.ID_SAVE, 'savedefault.ico', 'Warning.ico', name="BTN_SAVESETTINGS")
                    else:
                        self.btnSave = NiceButton(self.panel, wx.ID_SAVE, 'savedefault.ico', name="BTN_SAVESETTINGS")
                    self.btnSave.SetToolTipString("Save settings")
                    self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
                    if not self.iconMFCStyle:
                        self.vbxH1.Add(self.btnSave, 1)
                    else:
                        self.vbxH1.Add(self.btnSave, (0, 3))
                else:
                    self.vbxH1.Add((BORDER, 1), (0, 3))

                self.vbxH1.Add((BORDER, 1), (0, 4))     # Widgetslist
                self.vbxH1.Add((BORDER, 1), (0, 5))     # Widgetsinspect

                self.btnTRA = NiceButton(self.panel, wx.ID_ANY, 'translator.ico', name="BTN_TRANSLATOR")
                self.btnTRA.SetToolTipString("Translation")
                self.btnTRA.Bind(wx.EVT_BUTTON, self.OnTranslate)
                if not self.iconMFCStyle:
                    self.vbxH1.Add(self.btnTRA, 1)
                else:
                    self.vbxH1.Add(self.btnTRA, (0, 7))
                if os.environ.get('OPTICAM_LANGUAGE_TRANSLATOR', '').upper() == 'TRUE':
                    self.btnTRA.Show(True)
                else:
                    self.btnTRA.Show(False)

                self.btnDOC = NiceButton(self.panel, wx.ID_ANY, PINBUTTON_UNDOCKED, name="BTN_PIN")
                #self.btnDOC = NiceToggleButton(self.panel, wx.ID_ANY, PINBUTTON_UNDOCKED, name="BTN_PIN")
                self.btnDOC.SetToolTipString("Pin")
                self.btnDOC.Bind(wx.EVT_BUTTON, self.OnDock)
                if not self.iconMFCStyle:
                    self.vbxH1.Add(self.btnDOC, 1)
                else:
                    self.vbxH1.Add(self.btnDOC, (0, 8))
            #
            # set focus to ensure that the dialog window to stay in the foreground
            self.SetFocus()
        #                    
        self.panel.SetSizer( self.vbxV1 )
        #
        if "PYTHON_DEBUG_MODE" not in os.environ and "PYTHON_DEBUG_LEVEL" not in os.environ:
            if self.obj is not None and hasattr(self.obj, 'OnHideConsole'):
                logger.info( LOG_TAG + 'In user mode, so try to hide the python console dialog' )
                self.obj.OnHideConsole()
            else:
                logger.info( LOG_TAG + 'In user mode, not python console found')
        elif "PYTHON_DEBUG_MODE" not in os.environ and "PYTHON_DEBUG_LEVEL" in os.environ:
            if self.obj is not None and hasattr(self.obj, 'OnHideConsole'):
                logger.info( LOG_TAG + 'In debug mode with env python_debug_level, so try to hide the python console dialog' )
                self.obj.OnHideConsole()
            else:
                logger.info( LOG_TAG + 'In debug mode with env python_debug_level, not python console found')
        else:
            logger.info( LOG_TAG + 'In normal debug mode and do not hide python console found')
        #
        # Handle the wx.EVT_ACTIVATE event to get an action
        # THIS SEEMS VERY IMPORTANT TO GET A IMMEDIATELY REACTION FOR MOUSECLICKS !!!
        self.Bind(wx.EVT_ACTIVATE, self.OnBaseDialogActivate) 
        
#     def __del__(self):
#         logger.info("%s%s" % ("BaseDialog" , ".__del__"))
#         #wx.Dialog.__del__(self)
    
    def GetResourceLabel(self):
        return getattr(self, "_resourcelabel", "")

    def UpDateDlgData(self, *arg, **kwargs):
        """ 
        Needed to stop searching attributes (methods) in base dialog class
        """
        pass

    def GetCurrentOpticamUserUnit(self):
        """
        return string, 'mm' or "inch"
        """
        if cad.getCurrentDoc().program.GetInputUnits() == cad.UNITS_TYPE.MM:
            return "mm"
        else:
            return "inch"

    @staticmethod
    def ShowDialogFromList(name, *args, **kwargs):
        # to show modeless dialogs from within python:
        BaseDialog.argsBuffer = args
        BaseDialog.kwargsBuffer = kwargs
        pyobj = cad.getCurrentDoc().GetPyObj()
        #pyobj = cad.GetPyObj()
        if pyobj:
            pyobj.ShowModlessListObjectDlg(name)    # Use here the NAME of the dialog (not class name)

    @staticmethod
    def ShowDialogFromListEx(name, *args, **kwargs):
        # to show modeless dialogs from within python:
        BaseDialog.argsBuffer = args
        BaseDialog.kwargsBuffer = kwargs
        pyobj = cad.getCurrentDoc().GetPyObj()
        #pyobj = cad.GetPyObj()
        if pyobj:
            pyobj.ShowModlessListObjectDlgModal(name, True)        # Use here the NAME of the dialog (not class name)    -> MEASURE MAIN DIALOG

    def OnDisplayChanged(self, evt):
        obj = evt.GetEventObject()
        logger.info("%s.%s (%s)" % (self.__class__.__name__, "OnDisplayChanged", obj.Name))
        old = ScreenScaleFactor
        GetDPIScaleFactor()
        ComputeScreenScale()    ### IT SEEMS THE NEW RESOLUTION IS NOT GIVEN IMMEDIATELY HERE
        no_of_displays = wx.Display.GetCount()
        logger.info("Changed guiscalefactor from %f to %f (%d displays)" % (old, ScreenScaleFactor, no_of_displays))
        #self.SetTitle( self.title + " (Scale=%.0f%%* %d displays)" % (ScreenScaleFactor * 100, no_of_displays) )
        self.SetTitle( self.title )
        #evt.Skip()

    def OnStartWidgesInspector(self, event=None):  # @UnusedVariable
        if not globals().get('WIDGETS_INSPECTOR_RUNNING'):
            globals()['WIDGETS_INSPECTOR_RUNNING'] = True
            #
            app = MyApp()
            app.SetAppName("OpticamWidgetsInspector")
            #app.MainLoop() # DO THIS NOT IN OUR SPECIAL ENVIRONMENT !!!
        
    def OnBaseDialogActivate(self, evt):
        """ seems to be needed in the xxx_tdb_post_dlg modules """
        obj = evt.GetEventObject()
        logger.info("%s.%s (%s)" % (self.__class__.__name__, "OnBaseDialogActivate", obj.Name))
#         evt.Skip()        # seems skip is not good in this case !?!

    def CheckSolidCutDialogSetting(self):
        """
        peps.ReadGlobalI('i_centre_dialogs')
        """
        if hasattr(self, 'passedParams'):
            if 'opticamCallTypeAndReturnInfo' in self.passedParams:
                if self.passedParams['opticamCallTypeAndReturnInfo']['type'] == 'PEPSVDM':
                    import peps  # @NoMove @UnresolvedImport
                    irts = peps.ReadGlobalI('i_centre_dialogs')  # @UndefinedVariable
                    return irts == 1
        return True
    
    def CheckIfRuntimeInSolidCutDialog(self):
        """
        peps.ReadGlobalI('i_centre_dialogs')
        """
        if hasattr(self, 'passedParams'):
            if 'opticamCallTypeAndReturnInfo' in self.passedParams:
                if self.passedParams['opticamCallTypeAndReturnInfo']['type'] == 'PEPSVDM':
                    return True
        return False
                
    def LoadDialogSettings(self, config):
        """
        Load dialog configuration data (.ini file) and sets:
        self.size
        self.position
        self.style
        self.docked
        self._IsIconized, self._IsMaximized, self._IsShown
        """
        try:
            oldPath = config.GetPath()
            config.SetPath(self._configReg)
            #
            if config.Exists(self._configReg):
                w = h = None
                posx = posy = None
                logger.info("%s.%s (%s exists)" % ("BaseDialog" , "LoadDialogSettings", self._configReg))
                for i in range( config.GetNumberOfEntries() ):
                    dummy_flag, name, dummy_val = config.GetNextEntry(i)
    
                    if name == 'Width':
                        w = config.ReadInt(name)
                    elif name == 'Height':
                        h = config.ReadInt(name)
                    elif name == 'PosX':
                        posx = config.ReadInt(name)
                    elif name == 'PosY':
                        posy = config.ReadInt(name)
                    elif name == 'Style':
                        self.style = config.ReadInt(name)
                    elif name == 'IsDocked':
                        self.docked = config.ReadBool(name)
                    elif name == 'IsIconized':
                        self._IsIconized = config.ReadBool(name)
                    elif name == 'IsMaximized':
                        self._IsMaximized = config.ReadBool(name)
                    elif name == 'IsActive':
                        self._IsActive = config.ReadBool(name)
                    elif name == 'IsShown':
                        self._IsShown = config.ReadBool(name)
                    elif name == 'version':
                        v = config.Read(name)  # @UnusedVariable
                    elif name == 'date':
                        d = config.Read(name)  # @UnusedVariable
                    else:
                        self.StoreAttribute(name, config.Read(name))
                #
                if w and h:
                    self.size = wx.Size(w, h)
                if posx and posy:
                    self.position  = wx.Point(posx, posy)
                config.SetPath(oldPath)
            else:
                logger.info("%s.%s (%s not existing)" % ("BaseDialog" , "LoadDialogSettings", self._configReg))
        except:
            pass

    def SaveDialogSettings(self, config):
        """
        Save dialog configuration data
        """
        try:
            oldPath = config.GetPath()
            config.SetPath(self._configReg)
            
            if BaseDialog.ResetFlag == True:        # activate this in main system with <shift-ctrl-F9>
                config.DeleteGroup(self._configReg)
            else:
                if not self.IsIconized() and not self.IsMaximized():
                    w, h = self.GetSize()
                    config.WriteInt('Width', w)
                    config.WriteInt('Height', h)
        
                    px, py = self.GetPosition()
                    config.WriteInt('PosX', px)
                    config.WriteInt('PosY', py)
                    
                config.WriteInt('Style', self.GetWindowStyle())
                config.WriteBool('IsDocked', self.GetDockState())
                config.WriteBool('IsIconized', self.IsIconized())
                config.WriteBool('IsMaximized', self.IsMaximized())
                config.WriteBool('IsActive', self.IsActive())
                config.WriteBool('IsShown', self.IsShown())
                #
                if hasattr(self, '_save_attributes'):
                    for key, value in list(self._save_attributes.items()):
                        config.Write( key, "{}".format(value) )
                config.Write('version', '0.9')      # not sure if useful ?
                strDatetime = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                config.Write('date', strDatetime)
            #
            config.Flush()
            config.SetPath(oldPath)
        except:
            pass

    def ReadAttribute(self, name, default=None):
        #return getattr(self, name, default)
        if hasattr(self, '_save_attributes'):
            return self._save_attributes.get(name, default)
        else:
            return default
    
    def StoreAttribute(self, name, value):
        #setattr(self, name, value)
        if not hasattr(self, '_save_attributes'):
            self._save_attributes = {}
        self._save_attributes[name] = value
    
    def SetDockState(self, state): 
        if state == True:
            self.docked = True
            self.btnDOC.SetBitmap( getOpticamIcon(PINBUTTON_DOCKED) )
        else:
            self.docked = False
            self.btnDOC.SetBitmap( getOpticamIcon(PINBUTTON_UNDOCKED) )

    def GetDockState(self):
        return self.docked  
   
#     def OnBaseDialogFit(self, event):  # @UnusedVariable
#         logger.info("%s%s" % ("BaseDialog" , ".OnBaseDialogFit"))
#         self.vbxV1.Fit( self )
        
    def CreateControls(self, child=None):  # @UnusedVariable
        logger.info("%s%s" % ("BaseDialog" , ".CreateControls"))
        # if Statusbar
        if self.statusbar:
            self.stabar = CustomStatusBar(self.panel, self.statusbar)
            self.vbxV1.Add(self.stabar, 0, wx.EXPAND)
            #self.vbxV1.Show(self.stabar, False)

        # Resize the dialog after adding Controls in derived classes.
        self.vbxV1.Fit( self )
        #
        if getattr(self, "position", wx.DefaultPosition) == wx.DefaultPosition:
            self.CenterOnScreen()

        self.initialized = True
        
    def SetStatusBarText(self, texts=[], colors=[]):
        if hasattr(self, "stabar"):
            txt2 = txt1 = ""
            col2 = col1 = None
            if len(texts) > 0: txt1 = texts[0]
            if len(texts) > 1: txt2 = texts[1]
            if len(colors) > 0: col1 = colors[0]
            if len(colors) > 1: col2 = colors[1]
            self.stabar.SetText1(txt1, col1)
            self.stabar.SetText2(txt2, col2)
        else:
            logger.info("SetStatusBarText: No statusbar created for this window!")

    #----------------------------------------------------------------------
    def ShowStatusbar(self):
        if hasattr(self, "stabar"):
            self.vbxV1.Show(self.stabar, True)
            self.vbxV1.Fit( self )
 
    #----------------------------------------------------------------------
    def HideStatusbar(self):
        if hasattr(self, "stabar"):
            self.vbxV1.Show(self.stabar, False)
            self.vbxV1.Fit( self )

    def Destroy(self):
        # Remove from Doc-List-Of-Windows
        logger.info("%s%s (%s)" % ("BaseDialog" , ".Destroy", self.dialogName))
        optLogger.LogA("[Python] %s%s (%s)" % ("BaseDialog" , ".Destroy", self.dialogName))
        optLogger.DebLogA("[Python] %s%s (%s)" % ("BaseDialog" , ".Destroy", self.dialogName))
        # Have to be carefull with the document.
        #
        # OptiCAMHelper.remwindowfromlist(self)
        # self.obj.RemWindowFromDocList(self)
        if hasattr(self.GetParent(), "childDialogs") and self in self.GetParent().childDialogs:
            self.GetParent().childDialogs.remove(self)
        return wx.Dialog.Destroy(self)

    def ShowModal(self):
        # Add to Doc-List-Of-Windows
        logger.info("%s%s%s" % ("BaseDialog" , ".ShowModal (BEGIN): modal=", self.modal))
        optLogger.LogA("[Python] BaseDialog.ShowModal (BEGIN) -> call: self.GetParent().Enable(True) (%s)" % self.dialogName)
        optLogger.DebLogA("[Python] BaseDialog.ShowModal (BEGIN) -> call: self.GetParent().Enable(True) (%s)" % self.dialogName)
        #  optLogger.DebLogA("[Python] BaseDialog.Show (%s)" % self.dialogName)
        # Bind to Application
        # 10/15/2024
        # We crash the system or we go into deadlock!
        # jorgk todo with info base!
        # peps is okay, gc deadlock, sw crash!
        # Tell base system to do not react on selections!
        self.obj.SetPseudoModal(True)
        self.SetStandardCursor()
        ret = wx.Dialog.ShowModal(self)     # Program is blocked
        if self.GetParent(): self.GetParent().Enable(True)
        self.obj.SetPseudoModal(False)
        # Reset it now, no deadlock/crash will be made!
        # 10/15/2024
        logger.info("%s%s%s" % ("BaseDialog" , ".ShowModal (END): ret=", ret))
        optLogger.LogA("[Python] BaseDialog.ShowModal (END) (%s)" % self.dialogName)
        optLogger.DebLogA("[Python] BaseDialog.ShowModal (END) (%s)" % self.dialogName)
        return ret
        # Release from Application

    def Show(self, show=True):
        # More like DockedDialog
        logger.info("BaseDialog.Show (%s)" % self.dialogName)
        optLogger.LogA("[Python] BaseDialog.Show (%s)" % self.dialogName)
        optLogger.DebLogA("[Python] BaseDialog.Show (%s)" % self.dialogName)
        if self.active == True:
            optLogger.DebLogA("[Python] wx.Dialog.Show (%s)" % self.dialogName)
            return wx.Dialog.Show(self, show)   # Program is not blocked

    def Hide(self):
        #
        logger.info("BaseDialog.Hide (%s)" % self.dialogName)
        optLogger.LogA("[Python] BaseDialog.Hide (%s)" % self.dialogName)
        # tell main-system that we are closed
        self.obj.HideModlessListObject(self)
        return wx.Dialog.Hide(self)

    def EndModal(self, mode=wx.ID_OK):
        # Is called when a ModalDialog will be closed.
        # 
        try:
            #####################
            logger.info("BaseDialog.EndModal called with mode={} in class {}".format(mode, self.__class__.__name__))
            optLogger.LogA("BaseDialog.EndModal called with mode={} in class {}".format(mode, self.__class__.__name__))
            optLogger.DebLogA("BaseDialog.EndModal called with mode={} in class {}".format(mode, self.__class__.__name__))
            #####################
    
            if hasattr(self, "cfg"):        # check if there is config object (..is used to store window properties in the registry)
                SaveDialogSettings = getattr(self, "SaveDialogSettings", None)
                if SaveDialogSettings and callable(SaveDialogSettings):             # ...if there is, we store the expanded/collapsed state of the foldpanelpages
                    if hasattr(self, "fpnl"):   # check also if this dialog contains a Group(Fold)-panel object
                        GetExpandedPages = getattr(self.fpnl, "GetExpandedPages", None)
                        if GetExpandedPages and callable(GetExpandedPages):             # ...if there is, we store the expanded/collapsed state of the foldpanelpages
                            self.StoreAttribute('openPages', GetExpandedPages())        
                    #        
                    SaveDialogSettings(self.cfg)
            #
            if self.modal:
                logger.info("BaseDialog.EndModal (%s)" % self.dialogName)
                optLogger.LogA("[Python] BaseDialog.EndModal (%s)" % self.dialogName)
                optLogger.DebLogA("[Python] BaseDialog.EndModal (%s)" % self.dialogName)
                if self.IsModal():
                    wx.Dialog.EndModal(self, mode)
                if self.GetParent() != None:
                    self.GetParent().Enable(True)
            else:
                logger.info("%s%s (%s)" % ("BaseDialog" , ".EndModal", "modeless dialog"))
                optLogger.LogA("[Python] %s%s (%s)" % ("BaseDialog" , ".EndModal", "modeless dialog"))
                optLogger.DebLogA("[Python] %s%s (%s)" % ("BaseDialog" , ".EndModal", "modeless dialog"))
                self.active = False
                #wx.Dialog.Close()
    
                if self.preCreateMode:
                    self.preCreateMode = False
                    # Don't call when force to remove it.
                    if mode != 123456:
                        self.obj.RemWindowFromDocModlessList(self)
    
            self.initialized = False
            logger.info("%s%s (%s)" % ("BaseDialog" , ".EndModal", "self.Destroy"))
            optLogger.LogA("[Python] %s%s (%s)" % ("BaseDialog" , ".EndModal", "self.Destroy"))
            optLogger.DebLogA("[Python] %s%s (%s)" % ("BaseDialog" , ".EndModal", "self.Destroy"))
            return self.Destroy()
        except:
            logger.info("BaseDialog.EndModal running in exception !!!")
            optLogger.LogA("BaseDialog.EndModal running in exception !!!")

    def ActivateHidden(self):
        """ This method replaces the normal Activate method when we pre create the dialog (no show).
        -> after doing this we set the preCreateMode-flag      
        """
        logger.info("%s%s (%s)" % ("BaseDialog" , ".ActivateHidden", self.dialogName))
        optLogger.LogA("[Python] %s%s (%s)" % ("BaseDialog" , ".ActivateHidden", self.dialogName))
        # if self.modal:
        #     pass
        # else:
        # Reason: register both kinds of dialog -> so both could be shown from main system or special python call
        if self.preCreateMode:
            pass
        else:   # register only once in the list
                ret = self.obj.AddWindowToDocModlessList(self)  # @UnusedVariable
                self.preCreateMode = True
                #
                # check for dialog children and add them too (recursive call)
                for childDialog in self.childDialogs:
                    childDialog.ActivateHidden()

    def Activate(self):
        # Handle docking here in baseclass (is common to all python dialogs)
        if self.docked:
            self.SetDockState(self.docked)
            self.DoDocking()

        # # Reset arguments buffers (new : 2023/07/25)
        # BaseDialog.argsBuffer = ()
        # BaseDialog.kwargsBuffer = {}
        #
        # Start to handle both modal and modless.
        # We start to have only modless dialogs, because of a exception when I
        # use the CADHandle and steal the HWND.
        logger.info("%s%s (%s)" % ("BaseDialog" , ".Activate", self.dialogName))
        optLogger.LogA("[Python] %s%s (%s)" % ("BaseDialog" , ".Activate", self.dialogName))
        if self.modal:
            return self.ShowModal()
        else:
            if cad.getLanguageW() != self.currentLanguage:
                self.ChangeLanguage()   # check if the language has changed
            if not self.active:
                self.active  = True
                wx.CallAfter(self.Show)
            return wx.ID_OK

    def ActivateEx(self):
        logger.info("%s%s (%s)" % ("BaseDialog" , ".ActivateEx", self.dialogName))
        optLogger.LogA("[Python] %s%s (%s)" % ("BaseDialog" , ".ActivateEx", self.dialogName))
        return self.ShowModal()

    def OnClose(self, event):  # @UnusedVariable
        # do not delete (used in base_tdb.py)
        logger.info("%s%s (%s)" % ("BaseDialog" , ".OnClose", self.dialogName))
        optLogger.LogA("[Python] %s%s (%s)" % ("BaseDialog" , ".OnClose", self.dialogName))
        self.active  = False
        self.killPopUps(self)
        if self.preCreateMode:
            self.Hide()
        else:
            self.EndModal(wx.ID_CANCEL)

    def OnOK(self, event):  # @UnusedVariable
        # Handle green OK
        logger.info("%s%s (%s)" % ("BaseDialog" , ".OnOK", self.dialogName))
        optLogger.LogA("[Python] %s%s (%s)" % ("BaseDialog" , ".OnOK", self.dialogName))
        self.active  = False
        self.killPopUps(self)
        if self.preCreateMode:
            self.Hide()
        else:
            self.EndModal(wx.ID_OK)

    def OnESC(self, event):  # @UnusedVariable
        # Handle red ESC
        logger.info("%s%s (%s)" % ("BaseDialog" , ".OnESC", self.dialogName))
        optLogger.LogA("[Python] %s%s (%s)" % ("BaseDialog" , ".OnESC", self.dialogName))
        self.active  = False
        self.killPopUps(self)
        if self.preCreateMode:
            self.Hide()
        else:
            self.EndModal(wx.ID_CANCEL)

    def OnSave(self, event):  # @UnusedVariable
        # Base class method: overwrite if neccessary
        pass

    def killPopUps(self, root):  # @UnusedVariable
        for w in wx.GetTopLevelWindows():
            if isinstance(w, PopupWindow):
                w.DestroyChildren()
                w.Destroy()

    def OnHelp(self, event):  # @UnusedVariable
        #
        logger.info("%s%s" % ("BaseDialog" , ".OnHelp"))
        # s0 = self.dialogName
        # logger.info("%s" % s0)
        s1 = cad.getHelpPath()
        s1 += '\\OPTICAM-Wire-EDM('
        s2 = cad.getLanguageW()
        # No spaces in name
        s2 = s2.replace(' ','_')
        s1 += s2
        s1 += ').chm'
        s3 = cad.String('WxPython')
        s4 = cad.String(self.dialogName)
        id_ = cad.getHelpID(s3,s4)  # @UnusedVariable
        s5 = cad.String(s1)
        re_ = cad.showHelp(s5,id_)  # @UnusedVariable

    def OnCreateWidgesList(self, event=None, name=None):  # @UnusedVariable
        """ Prints information about widgets structure """

        name  = name or "(WidgetsList)"

        fullPath = os.path.join(messagePath, self.__class__.__name__ + name + ".txt")
        fp = open(fullPath, "w", encoding='utf-8')
        printAllWidgets(self, indent=0, filePointer=fp)
        fp.close()
        dlg = wx.MessageDialog(self.GetParent(), '...the widgets list is successfully created in:\n\n' + fullPath,
                               'Widgets List',
                               wx.OK | wx.ICON_INFORMATION
                               )
        dlg.ShowModal()
        dlg.Destroy()

    def OnTranslate(self, event):  # @UnusedVariable
        #
        from p2c.dialogtranslations import TranslationDialog
        # Handle the Translation of the controls captions
        logger.info("%s%s" % ("BaseDialog" , ".OnTranslate"))
        #
        language = cad.getLanguageW()
        messageFileName = getattr(self, "messageFileName", self.__class__.__name__)
        #title = getMessageW("Translation for Dialog", cad.PYTHON_MESSAGES,20) + " " + self.__class__.__name__ + "(" + language + ")" + ".xml"
        title = getMessageW("Translation for Dialog", cad.PYTHON_MESSAGES,20) + " " + messageFileName + "(" + language + ")" + ".xml"
        # Now we can use objects directly from p2cpython if there is no document! (extension for opticam-free run-environment)
        if self.doc is None:
            if not hasattr(cad, "ApplicationWindow"):
                raise ReferenceError('BaseDialog: no ApplicationWindow!')
            win = cad.ApplicationWindow()      # does really blocking the system
        else:
            win = self.doc.ApplicationWindow()      # does really blocking the system

        if win is not None:
            try:
                dlg = TranslationDialog(win, self, wx.ID_ANY, title,
                                style=wx.CAPTION|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL,
                                messageFileName=messageFileName,
                                )
                win.Enable(True)
                dlg.Destroy()
            except:
                win.Enable(True)
    
    def OnDock(self, event):  # @UnusedVariable
        logger.info("%s%s" % (self.__class__.__name__, ".OnDock"))
        
        self.SetDockState(not self.docked)      # toggle the state
        self.DoDocking()

    def DoDocking(self):
        if self.docked:
            self.size =     self.GetSize()
            self.position = self.GetPosition()
            self.SetWindowStyle(self.dockStyle)
        else:
            self.SetWindowStyle(self.style)
        #
        self.vbxV1.Show(self.titleBar, self.docked)
        # ...to do in main-system
        dockFunction = getattr(self.obj, "DockEx", None)
        if dockFunction and callable(dockFunction):
            ret = dockFunction( self )  # @UnusedVariable
        #
        if self.docked:
            if hasattr(self, 'fpnl'):
                self.fpnl.Layout()
        else:
            self.SetPosition(self.position)
            self.SetSize(self.size)
            if hasattr(self, 'fpnl'):
                self.fpnl.Layout()      # <optionsdlg.GroupPanel object>
            #self.panel.Layout()     # <p2c.window.ScrolledBasePanel object>

    def NewSelection(self):
        pass

    # treat this strings as a title
    def GetLabel(self):
        return wx.Dialog.GetTitle(self)

    def SetLabel(self, labelString):
        wx.Dialog.SetTitle(self, labelString)

    def ChangeLanguage(self):
        """Can be called to update the controls after language changes."""
        self.currentLanguage = cad.getLanguageW()
        messageFileName = getattr(self, "messageFileName", self.__class__.__name__)
        logger.info("%s%s changed to %s" % ("BaseDialog" , ".ChangeLanguage", self.currentLanguage))

        allPagesList = getAllWidgets(self)     # put all widgets/controls in this list

        global translatedText
        translatedText = None

        completeList = []
        ###for (pageName, wdgList, show, fileName, sepFile, dirty) in allLists:
        for pageList in allPagesList:
            completeList.extend(pageList.wdgList)

        readDialogFile(messagePath, messageFileName, _wdgList=completeList)

    def SetWaitCursor(self):
        cursor = wx.StockCursor(wx.CURSOR_WAIT)
        self.SetCursor(cursor)

    def SetStandardCursor(self):
        self.SetCursor(wx.NullCursor)
        """
        #Example for Activating Cursor without BaseDialog:
        import wx
        win = opticam.getCurrentDoc().ApplicationWindow()
        cursor = wx.StockCursor(wx.CURSOR_WAIT)
        win.SetCursor(cursor)
        """
#------------------------- End of class BaseDialog ----------------------------

class LoadingDialog(wx.Dialog):
    def __init__(self, parent=None, title='OPTICAM', modal=False, size=wx.DefaultSize, pos=wx.DefaultPosition, name="DLG_LOAD",  # @UnusedVariable
                 haveOpticam=True, style=wx.CAPTION|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL, Range=100, dialogWin=None, ObjForTimer=None):  # @UnusedVariable
        # This is a new Method to show all Dialogs in True Modal Mode (User input outside the python dialog is locked)
        self.haveOpticam = haveOpticam
        self.initialized = False
        self.active = False
        #
        self.dialogName = self.__class__.__name__   # at the moment I take the class-name as dialog name (TranslationFile)
        #
        # First we read the appropriate language xml-file (if one exists)
        global translatedText
        translatedText = readDialogFile(messagePath, self.dialogName)
        self.currentLanguage = cad.getLanguageW()
        #
        title = getText(title, name)
        logger.debug("%s%s" % (self.__class__.__name__ , ".__init__"))
        # Instead of calling wx.Dialog.__init__ we precreate the dialog
        # so we can set an extra style that must be set before
        # creation, and then we create the GUI object using the Create
        # method.
        wx.Dialog.__init__(self, parent, wx.ID_ANY, title,
                               size=size,
                               pos=pos,
                               style=style,
                               name=name)
        logger.debug("%s%s%s" % (self.__class__.__name__ , ".__init__ -> PLUM", self.GetParent().__class__.__name__))
        if _DEBUG & 0x4: self.SetBackgroundColour('PLUM')

        self.doc = getCurrentDoc()
        # Now we can use objects directly from p2cpython if there is no document! (extension for opticam-free run-environment)
        if self.doc is None:
            if not hasattr(cad, "GetPyObj"):
                raise ReferenceError('BaseDialog: no GetPyObj!')
            self.obj = cad.GetPyObj()
        else:
            self.obj = self.doc.GetPyObj()

        # this Panel serves as Parent of all widgets we will create (if needed it can get a title)
        self.panel = BasePanel(self, wx.ID_ANY, label="")

        self.hBxH1 = wx.BoxSizer( wx.HORIZONTAL )
        self.vbxV1 = wx.BoxSizer( wx.VERTICAL )

        self.LoadText = TextField( self.panel, wx.ID_ANY, "Loading...", pos = wx.DefaultPosition, size = wx.DefaultSize, style = 0, name = 'LoadText' )
        self.LoadText.Wrap( -1 )
        self.vbxV1.Add( self.LoadText, 0, wx.ALIGN_CENTER|wx.ALL, BORDER )

        # self.vbxV1.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )
        self.vbxV1.AddSpacer( 5 )

        self.Progressbar = wx.Gauge( self.panel, wx.ID_ANY, Range, wx.DefaultPosition, wx.Size( 150,-1 ), wx.GA_HORIZONTAL )
        self.vbxV1.Add( self.Progressbar, 0, wx.ALIGN_CENTER|wx.ALL, BORDER )

        self.hBxH1.Add( self.vbxV1, 1, wx.EXPAND, 5 )

        #self.SetSizer( self.hBxH1 )
        #self.Layout()

        # self.SetSizer(sizer)
        self.panel.SetSizerAndFit( self.vbxV1 )

        #val = self.ShowModal()

        ID_TIMER = wx.ID_ANY  # @UnusedVariable
        self.count = 0
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.TimerHandler, self.timer)

    def __del__(self):
        self.StopAutoPulse()

    def StartAutoPulse(self):
        #self.count = 0
        #self.timer = wx.Timer(self)
        #self.Bind(wx.EVT_TIMER, self.TimerHandler, self.timer)
        self.timer.Start(1)
        self.Progressbar.Pulse()

    def TimerHandler(self, event):  # @UnusedVariable
        self.count = self.count + 1

        if self.count >= 99:
            self.count = 0

        self.Progressbar.Pulse()

    #def Pulse(self, ObjForTimer=None):
    #    ObjForTimer.Progressbar.Pulse()

    def SetValue(self, value):
        self.Progressbar.SetValue(value)

    def StopAutoPulse(self):
        self.timer.Stop()


#------------------------- Here comes the text translation stuff for widgets and messages
def getText(txt, key, dummy=0, classnameofparent=None):
    """ Returns the translated caption-text if possible. """
    if classnameofparent is not None:
        #only for measurecycle widgets
        if translatedText is None:
            return txt
        if classnameofparent in translatedText:
            try:
                return translatedText[classnameofparent][key][0]
            except Exception as e:
                logger.debug("In window/getText: "+str(e))
                return txt
        return txt
    else:
        if translatedText is None:
            return txt
        if key in translatedText:
            return translatedText[key][0]
        return txt

def getColumnRowText(txt, ParentIdn, Type, Index):
    key = '%s__%s__%s' % (ParentIdn, Type, Index)
    if translatedText is None:
        return txt
    if key in translatedText:
        txt = translatedText[key][0]
    return txt

def getToolTip(txt, key, dummy=0, classnameofparent=None):
    """ Returns the translated tooltip-text if possible. """
    # for us a little additional information about the widget
    if _DEBUG & 0x4 and False:
        wdgInfo = " <%s>" % key
    else:
        wdgInfo = ""
    if translatedText is None:
        return txt + wdgInfo
    if classnameofparent is not None:
        #only for measurecycle widgets
        if classnameofparent in translatedText:
            try:
                return translatedText[classnameofparent][key][1]+ wdgInfo
            except Exception as e:
                logger.debug("In window/getToolTip: "+str(e))
                return txt
    else:
        if key in translatedText:
            return translatedText[key][1] + wdgInfo
        else:
            return txt

def getWdgString(wdg):
    """ Reads out the type, name, id, resourcelabel, label and tooltip from a widget. """
    TYPE = wx.EmptyString
    NAME = wx.EmptyString
    IDN = 0
    RESOURCE_TEXT = wx.EmptyString
    LANGUAGE_TEXT = wx.EmptyString
    TOOLTIP_TEXT  = wx.EmptyString
    
    if wdg != None:
#         try:
            TYPE = wdg.__class__.__name__
            if hasattr(wdg,"GetName"):
                NAME = wdg.GetName() or wx.EmptyString
            if hasattr(wdg,"GetId"):    # AN INTEGER
                IDN = wdg.GetId()
    #         if hasattr(wdg,"GetResourceLabel"):
    #             RESOURCE_TEXT = wdg.GetResourceLabel() or wx.EmptyString
            if hasattr(wdg,"GetLabel"):
                LANGUAGE_TEXT = wdg.GetLabel() or wx.EmptyString
            if hasattr(wdg,"GetResourceLabel"):
                RESOURCE_TEXT = wdg.GetResourceLabel() or wx.EmptyString
            else:
                RESOURCE_TEXT = LANGUAGE_TEXT
            if hasattr(wdg,"GetToolTipString"):
                TOOLTIP_TEXT = wdg.GetToolTipString() or wx.EmptyString
            if TYPE == "CaptionBar":    # SONDERFALL FOLDPANEL BAR
                RESOURCE_TEXT = wdg._resourcelabel or wx.EmptyString
                LANGUAGE_TEXT = wdg._caption or wx.EmptyString
#         except RuntimeError:
#             pass

    return (TYPE, NAME, IDN, RESOURCE_TEXT, LANGUAGE_TEXT, TOOLTIP_TEXT)

# Here are the defines for filenames of the common (outsourced) pages
# an underscore means that this is not shown in selection dialog (and therefore never outsourced)
outSourcedFilesDict = {"Header": "HEADER_PostOptionsDialog",
                       "General": "GENERAL_PostOptionsDialog",
                       "NC output": "_NCOUTPUT_PostOptionsDialog",
                       "Simulation": "SIMULATION_PostOptionsDialog",
                       "Simulation & Further Options": "SIMULATION_PostOptionsDialog",
                       "Setupsheet": "SHEET_PostOptionsDialog",
                       "CMD": "_CMD_PostOptionsDialog",
                       "xyz": "XYZ_Dialog",
                       }


class WidgesList(object):
    def __init__(self, pageName="", wdgList=None, show=True, fileName="", sepFile=False, dirty=False, wdgUnassigned=None):
        self.pageName = pageName
        self.wdgList = wdgList
        self.show = show
        self.fileName = fileName
        self.sepFile = sepFile
        self.dirty = dirty
        self.wdgUnassigned = wdgUnassigned
        
    def __str__(self, *args, **kwargs):
        len1 = len(self.wdgList) if self.wdgList is not None else 0
        len2 = len(self.wdgUnassigned) if self.wdgUnassigned is not None else 0
        return " pageName={} wdg_cnt={} show={} filename={} sepFile={} dirty={} unassigned={}".format(self.pageName, len1, self.show, self.fileName, self.sepFile, self.dirty, len2)

def getAllWidgets(root, allLists=None, includedPages=[], wList=None):
    """
    Fills a list with references to all children of a container widget (root).

    !!! I have modified this function to have the ability to put the widgets in different lists:
    first is for the common part and second for the rest -> only in case of 'PostOptionsDialog'
    returns: (pageName, wdgList, show, fileName, sepFile)
    """

    if isinstance(root, BaseDialog):
        if allLists is None:        # root must be a BaseDialog Type to start sampling widgets
            allLists = []
            wList = [root]      # begin new list (this first list is a very short list with only one widget)
            NAME = root.GetName() or wx.EmptyString # e.g. 'PostOptionsDialog'
            #FILENAME = outSourcedFilesDict.get(NAME, NAME)
            FILENAME = root.__class__.__name__      # better: store name of dialog e.g. 'StandardPostOptionsDialog'
            sepFile = False
            ###allLists.append( (NAME, wList, True, FILENAME, sepFile, False) )
            allLists.append( WidgesList(NAME, wList, True, FILENAME, sepFile, False) )
            #
            wList = []          # begin new list (for the next page)
            NAME = "Header"
            FILENAME = outSourcedFilesDict.get(NAME, NAME)
            sepFile = FILENAME in includedPages        # page is stored in a separate (common) file
            ###allLists.append( (NAME, wList, True, FILENAME, sepFile, False) )
            allLists.append( WidgesList(NAME, wList, True, FILENAME, sepFile, False) )
        else:
            pass
    elif isinstance(root, fpb.FoldPanelItem) and allLists is not None:    # SPECIAL CASE FOLDPANEL ITEM -> MARKS BEGINNING OF NEW PAGE !!!
        RESOURCE_TEXT = root._resourcelabel or wx.EmptyString
        if RESOURCE_TEXT:
            wList = []      # begin new list (for the next page)
            FILENAME = outSourcedFilesDict.get(RESOURCE_TEXT, RESOURCE_TEXT)
            sepFile = FILENAME in includedPages        # page is stored in a separate (common) file
            ###allLists.append( (RESOURCE_TEXT, wList, True, FILENAME, sepFile, False) )
            allLists.append( WidgesList(RESOURCE_TEXT, wList, True, FILENAME, sepFile, False) )
    elif isinstance(root, ScrolledBasePanel) and allLists is not None:    # SPECIAL CASE TABPANEL ITEM -> MARKS BEGINNING OF NEW PAGE !!!
        RESOURCE_TEXT = root._resourcelabel or wx.EmptyString
        if RESOURCE_TEXT:
            wList = []      # begin new list (for the next page)
            FILENAME = outSourcedFilesDict.get(RESOURCE_TEXT, RESOURCE_TEXT)
            sepFile = FILENAME in includedPages        # page is stored in a separate (common) file
            ###allLists.append( (RESOURCE_TEXT, wList, True, FILENAME, sepFile, False) )
            allLists.append( WidgesList(RESOURCE_TEXT, wList, True, FILENAME, sepFile, False) )
            wList.append(root)
    elif isinstance(root, PopupWindow):     #  filter out popups for translation
        pass            #
    elif root.GetName().startswith("_"):    # Agreement: name start with underscore means blended out for translations
        pass
    elif wList is not None:
        wList.append(root)
    #
    for child in root.GetChildren():
        getAllWidgets(child, allLists, includedPages, wList)
    #
    return allLists

def printWidget(root, indent=0, filePointer=None):
    """ Fills a (recursive) list with references to all children of a container widget (root). """
    (TYPE, NAME, ID, RESOURCESTRING, LABEL, TOOLTIPSTRING) = getWdgString(root)  # @UnusedVariable
    POSSTRING = root.GetPosition().__str__()
    SIZESTRING = root.GetSize().__str__()
    #filePointer.write(u"%s%s ID=%d NAME=%s LABEL=%s TT=%s Size=%s\n" % ((indent * '-'), TYPE, ID, NAME, LABEL, TOOLTIPSTRING, SIZESTRING))
    filePointer.write("%s%s ID=%d NAME=%s LABEL=%s Pos=%s Size=%s\n" % ((indent * '-'), TYPE, ID, NAME, LABEL, POSSTRING, SIZESTRING))

def printAllWidgets(root, indent=0, filePointer=None):
    """ Fills a (recursive) list with references to all children of a container widget (root). """
    (TYPE, NAME, ID, RESOURCESTRING, LABEL, TOOLTIPSTRING) = getWdgString(root)  # @UnusedVariable
    POSSTRING = root.GetPosition().__str__()
    SIZESTRING = root.GetSize().__str__()
    #filePointer.write(u"%s%s ID=%d NAME=%s LABEL=%s TT=%s Size=%s\n" % ((indent * '-'), TYPE, ID, NAME, LABEL, TOOLTIPSTRING, SIZESTRING))
    filePointer.write("%s%s ID=%d NAME=%s LABEL=%s Pos=%s Size=%s\n" % ((indent * '-'), TYPE, ID, NAME, LABEL, POSSTRING, SIZESTRING))
    indent += 2

    for child in root.GetChildren():
        printAllWidgets(child, indent, filePointer)

def readDialogFile(Dir, dialogName, _txtDict=None, _wdgList=None, _callStack=None):
    """ manage the texts in our wxPython dialogs.
    reads text from xml-file and put it in a dictionary (txtDict)
    
    example without additional labels:
        <CONTROL TYPE="StaticText" TOOLTIP="" TEXT="Untere D�se" IDN="STT_LOWERNOZZLE"/>
    
    or with labels
        <CONTROL TYPE="OptiRadioBox" TOOLTIP="" TEXT="Bildformat" IDN="radioBoxPicture">
            <LABEL TYPE="LabelText" TOOLTIP="" TEXT="Farbe" IDN="_radioBoxPicture_0"/>
            <LABEL TYPE="LabelText" TOOLTIP="" TEXT="Schwarz-Wei�" IDN="_radioBoxPicture_1"/>
        </CONTROL>

    or with putting the strings directly into the widgets (param _wdgList)
    
    or with include mechanism: (since June 2021) e.g.
        <INCLUDE IDN="GENERAL_PostOptionsDialog" TYPE="FileInclude"/>
    """

    language = cad.getLanguageW()
    msg_xml_file = os.path.join(Dir, dialogName + "(" + language + ")" + ".xml")

    # s = u'<CONTROL TYPE="%s" IDN="%s" TEXT="%s" TOOLTIP="%s"/>' % (TYPE, IDN, RESOURCE_TEXT, TOOLTIP_TEXT)

    if os.path.exists(msg_xml_file):        # Datei existiert
        try:
            logger.info("%s: %s %s" % (".readDialogFile", msg_xml_file, "exists"))
            baum = dom.parse(msg_xml_file)     # throws IOError
        except Exception as e:
            logger.error("%s: %s %s" % (".readDialogFile", msg_xml_file, str(e)))
            _txtDict = OrderedDict()
            return _txtDict

        if _txtDict is None and _wdgList is None:
            _txtDict = OrderedDict()        # initialize new dictionary
        if _callStack is None:
            _callStack = { dialogName }     # initialize new set

        for node in baum.childNodes:
            if node.nodeType == node.ELEMENT_NODE and node.localName == DIALOG_TYPE_STRING:
                for entry in node.childNodes:
                    ##### new mechanism to allow a kind of nesting with including other files #####
                    if entry.nodeType == entry.ELEMENT_NODE and entry.localName == "INCLUDE":
                        TYPE = entry.getAttribute("TYPE")  # @UnusedVariable
                        IDN = entry.getAttribute("IDN")
                        if TYPE == "FileInclude": 
                            if IDN not in _callStack:
                                _callStack.add(IDN)
                                readDialogFile(Dir, IDN, _txtDict, _wdgList, _callStack)   # do a recursive call, avoid loops of death !!
                                _callStack.discard(IDN)
                    ###############################################################################
                    if entry.nodeType == entry.ELEMENT_NODE and entry.localName == "CONTROL":
                        #Behaviour for normal widget Translation
                        TYPE = entry.getAttribute("TYPE")
                        IDN = entry.getAttribute("IDN")
                        LANGUAGE_TEXT = entry.getAttribute("TEXT")
                        TOOLTIP_TEXT  = entry.getAttribute("TOOLTIP")
                        if IDN != "":
                            if _wdgList is not None:
                                # now write this strings somehow to the widgets ...
                                for wdg in _wdgList:
                                    if wdg is not None:
                                        # we identify a widget with it's name (not ID)
                                        if hasattr(wdg,"GetName"):
                                            if wdg.GetName() == IDN:
                                                if hasattr(wdg,"SetLabel"):
                                                    wdg.SetLabel(LANGUAGE_TEXT)
                                                if hasattr(wdg,"SetToolTipString"):
                                                    wdg.SetToolTipString(TOOLTIP_TEXT)
                                                if TYPE == "CaptionBar":    # SONDERFALL FOLDPANEL BAR
                                                    wdg._caption = LANGUAGE_TEXT
                                            
                                                # this new section allows to read strings for multi-labeled widgets
                                                n = 0   # TODO Extract number from IDN-string (e.g. IDN="radioBoxPicture_0")
                                                for subentry in entry.childNodes:
                                                    if subentry.nodeType == subentry.ELEMENT_NODE and subentry.localName == "LABEL":
                                                        TYPE = subentry.getAttribute("TYPE")
                                                        IDN = subentry.getAttribute("IDN")
                                                        TEXT = subentry.getAttribute("TEXT")
                                                        TOOLTIP_TEXT  = subentry.getAttribute("TOOLTIP")
                                                        # now write the strings to the widget-lables ...
                                                        if hasattr(wdg,"SetItemLabel"):
                                                            wdg.SetItemLabel(n, TEXT)
                                                        if hasattr(wdg,"SetItemTooltip"):
                                                            wdg.SetItemTooltip(n, TOOLTIP_TEXT)
                                                        n += 1
                                                break
                            if _txtDict is not None:
                                # now write the strings to the dict ...
                                # ...and eliminate '\\' and make escpae sequenz '\'
                                _txtDict[IDN] = (LANGUAGE_TEXT.replace('\\n', '\n'), TOOLTIP_TEXT.replace('\\n', '\n'))
    
                                # this new section allows to read strings for multi-labeled widgets
                                for subentry in entry.childNodes:
                                    if subentry.nodeType == subentry.ELEMENT_NODE and subentry.localName == "LABEL":
                                        TYPE = subentry.getAttribute("TYPE")  # @UnusedVariable
                                        IDN = subentry.getAttribute("IDN")
                                        LANGUAGE_TEXT = subentry.getAttribute("TEXT")
                                        TOOLTIP_TEXT  = subentry.getAttribute("TOOLTIP")
                                        if IDN != "":
                                            # now write the strings to the dict ...
                                            # ...and eliminate '\\' and make escpae sequenz '\'
                                            _txtDict[IDN] = (LANGUAGE_TEXT.replace('\\n', '\n'), TOOLTIP_TEXT.replace('\\n', '\n'))

                    elif entry.nodeType == entry.ELEMENT_NODE and entry.localName == "LABEL":
                        #Behaviour for ListControls / Grids
                        TYPE = entry.getAttribute("TYPE") #Row / Column
                        IDN = entry.getAttribute("IDN")   #Index of Row / Column (count from 0)
                        TEXT = entry.getAttribute("TEXT")
                        TOOLTIP_TEXT = entry.getAttribute("TOOLTIP")
                        if IDN != "" and _wdgList is not None:
                            # now write this strings somehow to the widgets ...
                            for wdg in _wdgList:
                                if wdg is not None:
                                    # we identify a widget with it's name (not ID)
                                    if hasattr(wdg,"GetName"):
#                                         if wdg.GetName() == PARENT_IDN:
                                        if True:        # TODO
                                            if TYPE == 'COLUMN':
                                                if hasattr(wdg,"SetColumnLabel"):
                                                    wdg.SetColumnLabel(int(IDN), TEXT)
                                            if TYPE == 'ROW':
                                                if hasattr(wdg,"SetRowLabel"):
                                                    wdg.SetRowLabel(int(IDN), TEXT)
                                                    
                    elif entry.nodeType == entry.ELEMENT_NODE and entry.localName == "MAIN":
                        #Behaviour for measurecylcle widget translation
                        TYPE_measure = entry.getAttribute("TYPE")
                        IDN_measure = entry.getAttribute("IDN")
                        LANGUAGE_TEXT = entry.getAttribute("TEXT")
                        TOOLTIP_TEXT  = entry.getAttribute("TOOLTIP")
                        _measuretxtdict={}
                        if TYPE_measure != "":                                                                                  
                            if _txtDict is not None:
                                for subentry in entry.childNodes:
                                    if subentry.nodeType == subentry.ELEMENT_NODE and subentry.localName == "CONTROL":
                                        TYPE = subentry.getAttribute("TYPE")  # @UnusedVariable
                                        IDN = subentry.getAttribute("IDN")
                                        LANGUAGE_TEXT = subentry.getAttribute("TEXT")
                                        TOOLTIP_TEXT  = subentry.getAttribute("TOOLTIP")
                                        if IDN != "":
                                            _measuretxtdict[IDN] = (LANGUAGE_TEXT.replace('\\n', '\n'), TOOLTIP_TEXT.replace('\\n', '\n'))
                                    for subsubentry in subentry.childNodes:
                                        if subsubentry.nodeType == subsubentry.ELEMENT_NODE and subsubentry.localName == "LABEL":
                                            TYPE = subsubentry.getAttribute("TYPE")  # @UnusedVariable
                                            IDN = subsubentry.getAttribute("IDN")
                                            LANGUAGE_TEXT = subsubentry.getAttribute("TEXT")
                                            TOOLTIP_TEXT  = subsubentry.getAttribute("TOOLTIP")
                                            if IDN != "":
                                                _measuretxtdict[IDN] = (LANGUAGE_TEXT.replace('\\n', '\n'), TOOLTIP_TEXT.replace('\\n', '\n'))
                    
                        _txtDict[TYPE_measure]=_measuretxtdict
                                                    
        #
        del baum
        return _txtDict
    else:
        logger.info("%s: %s %s" % (".readDialogFile", msg_xml_file, "doesn't exist"))


#----------------------------------------------------------------------------------------------
class BasePanel(wx.Panel):
    """ A wrapper for wx.Panel. """
    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.TAB_TRAVERSAL|wx.NO_BORDER, name="_PNL_BASE", label=wx.EmptyString, scrollable=False):  # @ReservedAssignment
        self._resourcelabel = label
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
        else:
            label = getText(label, name)
 
#        wx.Panel.__init__(self, parent, id, pos, size, style, name)    # STRANGE: the name param sets Name AND Label (expected only the Name)
        wx.Panel.__init__(self, parent, id, pos, size, style, wx.EmptyString)
        wx.Panel.SetName(self, name)                                              #   in this way we set only the widget-name (not the label)
        wx.Panel.SetLabel(self, label)
 
        logger.info("%s.__init__ -> SKY BLUE %s" % (self.__class__.__name__ , self.GetParent().__class__.__name__))
        if _DEBUG & 0x4: wx.Panel.SetBackgroundColour(self, 'SKY BLUE')
 
#        if label != wx.EmptyString:
#            self.lbl = wx.StaticText(self, wx.ID_ANY, label, style=wx.ALIGN_CENTER, name="_" + name)

    def GetResourceLabel(self):
        return getattr(self, "_resourcelabel", "")

    def OnInnerSizeChanged(self):
        pass

class ScrolledBasePanel(scrolled.ScrolledPanel):
    """ A wrapper for scrolled.ScrolledPanel.
        New version: derived from ScrolledPanel. """
    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,  # @ReservedAssignment
                  style=wx.TAB_TRAVERSAL, name="_SCR_PNL_BASE", label=wx.EmptyString, scrollable=False):  #  @UnusedVariable
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
        else:
            label = getText(label, name)
        self._resourcelabel = label
        #
        style |= wx.VSCROLL
        scrolled.ScrolledPanel.__init__(self, parent, id, pos, size, style, wx.EmptyString)
        scrolled.ScrolledPanel.SetName(self, name)                                              #   in this way we set only the widget-name (not the label)
        scrolled.ScrolledPanel.SetLabel(self, label)
        
        logger.info("%s.__init__ -> SKY BLUE %s" % (self.__class__.__name__ , self.GetParent().__class__.__name__))
        if _DEBUG & 0x4: scrolled.ScrolledPanel.SetBackgroundColour(self, 'SKY BLUE')

#        if label != wx.EmptyString:
#            self.lbl = wx.StaticText(self, wx.ID_ANY, label, style=wx.ALIGN_CENTER, name="_" + name)
        #
        #self.SetAutoLayout(True)
        self.SetupScrolling(scrollToTop=False)
        
    def GetResourceLabel(self):
        return getattr(self, "_resourcelabel", "")

    def OnInnerSizeChanged(self):
        """
        this is necessary for
        updating scrollbars after a wx.ScrolledWindow content size change (here expanding/collapsing a foldpanel page)
        ('Programmatic size change from https://wiki.wxpython.org/ScrolledWindows')
        """
        minSize = self.GetSizer().GetMinSize()
        logger.info("{0}.OnInnerSizeChanged from {1} to {2}".format(self.__class__.__name__ , self.GetVirtualSize(), minSize))
        self.SetVirtualSize(minSize)
        
    def ScrollChildIntoView(self, child):
        """
        Scroll the panel so that the specified child window is in view.

        :param wx.Window `child`: any :class:`wx.Window` - derived control.

        .. note:: This method looks redundant if `evt.Skip()` is
           called as well - the base :class:`ScrolledWindow` widget now seems
           to be doing the same thing anyway.

        """

        sppu_x, sppu_y = self.GetScrollPixelsPerUnit()
        vs_x, vs_y   = self.GetViewStart()
        cr = child.GetRect()
        clntsz = self.GetClientSize()
        new_vs_x, new_vs_y = -1, -1

        # is it before the left edge?
        if cr.x < 0 and sppu_x > 0:
            new_vs_x = vs_x + (cr.x // sppu_x)

        # is it above the top?
        if cr.y < 0 and sppu_y > 0:
            new_vs_y = vs_y + (cr.y // sppu_y)

        # For the right and bottom edges, scroll enough to show the
        # whole control if possible, but if not just scroll such that
        # the top/left edges are still visible

        # is it past the right edge ?
        if cr.right > clntsz.width and sppu_x > 0:
            diff = math.ceil(1.0 * (cr.right - clntsz.width + 1) / sppu_x)
            if cr.x - diff * sppu_x > 0:
                new_vs_x = vs_x + diff
            else:
                new_vs_x = vs_x + (cr.x // sppu_x)

        # is it below the bottom ?
        if cr.bottom > clntsz.height and sppu_y > 0:
            diff = math.ceil(1.0 * (cr.bottom - clntsz.height + 1) / sppu_y)
            if cr.y - diff * sppu_y > 0:
                new_vs_y = vs_y + diff
            else:
                new_vs_y = vs_y + (cr.y // sppu_y)

        # if we need to adjust
        if new_vs_x != -1 or new_vs_y != -1:
            #print("%s: (%s, %s)" % (self.GetName(), new_vs_x, new_vs_y))
            self.Scroll(new_vs_x, new_vs_y)


#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# a class for our inputs like the similiar C++ class p4cEdit
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
class EditField(wx.TextCtrl):
    '''Represents an alphanumerical input field.'''       # can be accessed via __doc__
    def __init__(self, parent, id=wx.ID_ANY, value=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, min=-100.0, max=100.0, behaviour=BEHAVIOUR.ALPHANUMERIC, flRequired=True, toolTipString=wx.EmptyString, name='EditField', style = 0, ContextMenu=False, emptyInputAllowed=False):  # @ReservedAssignment
        self.behaviour = behaviour
        # ++++++
        self.value = value
        self.strInitValue = wx.EmptyString  # content before editing box -> set when getting focus
        # range
        self.dMinValue = min
        self.dMaxValue = max
        self.flRequired = flRequired    # field must have a value
        # error-flag
        self.error = False
        self.errMsg = " INVALID INPUT"   # default error message
        self.emptyInputAllowed = emptyInputAllowed

        self.wd = cad.VarDoubleTemplate("MyDouble", cad.POST_VAR_TYPES.VAR_TYPE_REAL, 0.0)      # double wrapper object
#        self.parser = cad.ExpressionParser()            # parser object (get everytime when used a new instance)
        self.doc = getCurrentDoc()
        # Now we can use objects directly from p2cpython if there is no document! (extension for opticam-free run-environment)
        if self.doc is None:
            if not hasattr(cad, "GetInputUnits"):
                raise ReferenceError('BaseDialog: no GetInputUnits!')
            self.InputUnits =  cad.GetInputUnits()
        else:
            self.InputUnits =  self.doc.program.GetInputUnits()

        self.sys = cad.System()
        # content before editing box
        if value != wx.EmptyString and self.behaviour & BEHAVIOUR.NUMERIC:
            value = self._setWindowText(value)

        wx.TextCtrl.__init__(self, parent, id=id,
                             value = value,
                             pos = pos,
                             size = size,
                             style = style,  # wx.HSCROLL
                             validator = wx.DefaultValidator,
                             name = name)

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False

        # the following events have to be observed
        self.Bind(wx.EVT_SET_FOCUS,  self.OnSetFocus)       # we enter the field
        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)      # we leave the field
        if self.behaviour & BEHAVIOUR.NUMERIC:
            self.Bind(wx.EVT_TEXT, self.OnTextChanged)      # text changed event (not necessary for text)
        ###self.Bind(wx.EVT_CHAR, self.OnEscape)               # escape key
        self.Bind(wx.EVT_CHAR_HOOK, self.OnEscape)               # escape key # experimental: put back prev. value and then leave...(2023/02/13)
        
        #Check if we have a custom Popup Menu
        if ContextMenu != False:
            if IsMethod(ContextMenu) == True:
                self.ContextMenu = ContextMenu
                self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)

    def OnContextMenu(self, event):
        ''' Wrapper method for calling the custom menu method '''
        self.ContextMenu(event, self)
        
    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)

        wx.TextCtrl.Enable(self, enable)        # Important: call base-class method
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)
                
    def Disable(self):
        wx.TextCtrl.Disable(self)               # Important: call base-class method
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)
            
    def SetError(self, err):
        """
        Only here the error status can be set or reset
        """
        logger.info("%s%s%s%s%s%s" % (self.__class__.__name__ , ".SetError", "\told : ", self.error, "\tnew : ", err))
        if self.error != err:   # changed error status
            self.error = err
            if self.error:
                self.SetBackgroundColour(COLOR_INVALID_INPUT)
                self.SetFocus()     # don't loose focus if invalid
                self.showErrorPop()
            else:
                self.SetBackgroundColour(COLOUR_SELECTED)
                self.killPop()

            self.Refresh()
        elif self.error and self.popUpWin is not None:         # same error status
            if self.popUpWin.getPopupText() != self.errMsg:    # -> check if the text has changed
                self.killPop()
                self.showErrorPop()

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)
                
    def showErrorPop(self):
        if self.popUpWin is None:
            (w, h) = self.GetClientSize()  # @UnusedVariable
            pos = self.ClientToScreen((w / 2, -30))    # it looks better with the button position
            self.popUpWin = PopupWindow(self, pos, self.errMsg, backColour='ORANGE')

    def killPop(self):
        if self.popUpWin is not None:  # only when we have one, we can kill it
            self.popUpWin.Kill()
            self.popUpWin = None

    # when the mouse enters the control -> the tooltip should be shown
    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        self.shouldPOP = True
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    # when the mouse leaves the control -> the tooltip should be killed
    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        self.shouldPOP = False
        self.killPop()

    def GetError(self):
        return self.error

    # getter / setter for behaviour
    def SetBehaviour(self, behaviour):
        self.behaviour |= behaviour
    
    def GetBehaviour(self):
        return self.behaviour

    # getter / setter for range (numeric behaviour)
    def SetRange(self, dMin, dMax):
        self.dMinValue = dMin
        self.dMaxValue = dMax
        
    def GetMinValue(self):
        return self.dMinValue
    
    def GetMaxValue(self):
        return self.dMaxValue
    
    def Validate(self):
        logger.info("%s%s" % (self.__class__.__name__ , ".Validate"))

    def OnTextChanged(self, event):
        logger.info("%s%s%s" % (self.__class__.__name__ , ".OnTextChanged", event))
        flValid = True
        self.errMsg = " INVALID INPUT"
#        if self.flRequired and val == '':
#            flValid = False
        if flValid:
            flValid = self.GetWindowValue()
#        if flValid and self.formatter:
#            flValid = self.formatter.validate(val)
#        if self.validationCB:
#            self.validationCB(self.dataValue, val, self.flRequired, flValid)
        self.SetError(not flValid)
        return flValid

    # returned values
    def GetWindowValue(self, dVal=None):
        # Read text string and create exp object and DoubleTemplate
        # Only when numeric
        txt = format("%s%s" % (self.__class__.__name__ , ".GetWindowValue"))
        # Get and update the current document input units
        if self.doc is None:
            if not hasattr(cad, "GetInputUnits"):
                raise ReferenceError('BaseDialog: no GetInputUnits!')
            self.InputUnits =  cad.GetInputUnits()
        else:
            self.InputUnits =  self.doc.program.GetInputUnits()

        if self.behaviour & BEHAVIOUR.NUMERIC:
            explicit_units = UNITS_TYPE.METRES      # invalid

            exp = cad.String(self.GetWindowText())
            exp.ToLower()
            exp.Trim_Right()
            logger.info("%s expr (from field) : <%s>" % (txt, exp.getPyString()))

            if self.behaviour & BEHAVIOUR.SCALE_DISTANCE:
                if self.sys.FindUnitsString(exp, cad.String("mm"))  : explicit_units = UNITS_TYPE.MM
                elif self.sys.FindUnitsString(exp, cad.String("in")): explicit_units = UNITS_TYPE.INCHES
            elif self.behaviour & BEHAVIOUR.ANGLE_VALUE:
                self.sys.FindUnitsString(exp, cad.String("°"))   # strip off if in string
            elif self.behaviour & BEHAVIOUR.PERCENTAGE_VALUE:
                self.sys.FindUnitsString(exp, cad.String("%"))   # strip off if in string
            elif self.behaviour & BEHAVIOUR.SCALE_SPEED:
                if self.sys.FindUnitsString(exp, cad.String("mm/min"))  : explicit_units = UNITS_TYPE.MM
                elif self.sys.FindUnitsString(exp, cad.String("in/min")): explicit_units = UNITS_TYPE.INCHES
            logger.info("     (after FindUnitsString) : <%s>" % (exp.getPyString()))

            if exp.Trim_Right().Length() > 0:
                parser = cad.ExpressionParser()            # parser object
                if self.behaviour & BEHAVIOUR.INTEGER:
                    #ok = exp.IsInteger()        # doesn't work correctly for exp='-1' -> ret = False
                    try:
                        dVal = int(exp.getPyString())
                        ok = True
                    except:
                        ok = False
                else:
                    ok = parser.ParseAndEvaluateT(self.wd, exp)       # parser method for parsing and evaluating
                    dVal = self.wd.GetValue()    # and we have a value in user-units
                logger.info("     (after ParseAndEvaluateT) : <%s>\t%s\t%f" % (exp, ok, self.wd.GetValue()))
                if ok:          # the expression is o.k. ...
                    # scale distance values to m
                    if self.behaviour & BEHAVIOUR.SCALE_DISTANCE or self.behaviour & BEHAVIOUR.SCALE_SPEED:
                        if explicit_units != UNITS_TYPE.METRES and explicit_units != self.InputUnits:
                            if explicit_units == UNITS_TYPE.INCHES: dVal *= 25.4
                            else: dVal /= 25.4
                        dVal = self.sys.FromUserUnitstoCAD(dVal) # Change value from User- to CAD-System Units
                        logger.info("     (after fromUserUnitstoCAD) : %f" % (dVal))
                    if dVal < self.dMinValue:        # the given limits are expected im meters
                        strans  = getMessageW(" The value entered is too small.",cad.PYTHON_MESSAGES,7)
                        strans2 = getMessageW(" For this Control, the Minimum Value is",cad.PYTHON_MESSAGES,8)
                        dmin = self.dMinValue
                        self.errMsg = "%s\n%s %s" % (strans, strans2, self.sys.FormatValue(dmin,self.behaviour).getPyString())
                        return False
                    if dVal > self.dMaxValue:
                        strans  = getMessageW(" The value entered is too large.",cad.PYTHON_MESSAGES,9)
                        strans2 = getMessageW(" For this Control, the Maximum Value is",cad.PYTHON_MESSAGES,10)
                        dmax = self.dMaxValue
                        self.errMsg = "%s\n%s %s" % (strans, strans2, self.sys.FormatValue(dmax,self.behaviour).getPyString())
                        return False
                    
                    self.value = dVal
                    return ok
            else:
                if self.emptyInputAllowed:
                    self.value = ''
                    return True
                self.value = 0.
        return False
    
    def GetWindowDouble(self):                  # returns double
        try:
            return float(self.value)
        except (ValueError,TypeError) as e:
            logger.info("%s%s" % (self.__class__.__name__, e.args[0]))
            
    def GetWindowText(self):
        return wx.TextCtrl.GetValue(self)       # returns string direct from control
    
    def GetWindowInt(self):                     # returns int
        try:
            v = int(self.value)
            if v > 0:
                return int(v + 0.5)
            elif v < 0:
                return int(v - 0.5)
            else:
                return 0
        except (ValueError,TypeError) as e:
            logger.info("%s%s" % (self.__class__.__name__, e.args[0]))

    def GetValue(self):
        if self.GetBackgroundColour() == PINK:
            return None
        if self.behaviour & BEHAVIOUR.NUMERIC:
            if self.behaviour & BEHAVIOUR.INTEGER:
                return self.GetWindowInt()
            else:
                return self.GetWindowDouble()
            """
            if self.behaviour & BEHAVIOUR.SCALE_DISTANCE or \
               self.behaviour & BEHAVIOUR.ANGLE_VALUE or \
               self.behaviour & BEHAVIOUR.PERCENTAGE_VALUE or \
               self.behaviour & BEHAVIOUR.SCALE_SPEED:
                return self.GetWindowDouble()
            else:
                return self.GetWindowInt()
            """
        else:
            return self.GetWindowText()

    def SetValue(self, value):
        if value is None:
            self.SetWindowText(wx.EmptyString)
            self.SetBackgroundColour(PINK)        # show the not initialized state
        else:
            self.SetWindowText(value)
            self.SetBackgroundColour(wx.NullColour)

    def _setWindowText(self, dVal):
        """
        receives double in cad-units and returns a string in user-units
        """
        self.value = dVal
        if self.behaviour & BEHAVIOUR.SCALE_DISTANCE:
            if type(self.value) != 'float' : self.value = float(self.value)
            dVal = self.sys.FromCADUnitstoUser(self.value)
            s = self.sys.FormatUserUnits(dVal, FORMAT.DISTANCE).getPyString()
        elif self.behaviour & BEHAVIOUR.SCALE_SPEED:
            if type(self.value) != 'float' : self.value = float(self.value)
            dVal = self.sys.FromCADUnitstoUser(self.value)
            s = self.sys.FormatUserUnits(dVal, FORMAT.SPEED).getPyString()
        elif self.behaviour & BEHAVIOUR.ANGLE_VALUE:
            if type(self.value) != 'float' : self.value = float(self.value)
            s = self.sys.FormatAngleDegrees(self.value).getPyString()
        elif self.behaviour & BEHAVIOUR.PERCENTAGE_VALUE:
            s = str( self.value )
            s = removeTrailingZeros(s) + "%"
        else:
            s = str( self.value )
            s = removeTrailingZeros(s)
        return s

    def SetWindowText(self, value):             # receives presumably a double
        #logger.debug("%s.SetWindowText (receives) : %s" % (self.__class__.__name__, str(value)))
        if self.behaviour & BEHAVIOUR.NUMERIC and value != wx.EmptyString:
            value = self._setWindowText(value)
        else:
            self.value = value
        self.setText(value)

    def getText(self):
        return wx.TextCtrl.GetValue(self)
    
    def setText(self, val):
        """
        update the TextCtrl without triggering its callbacks.
        """
        oldSetting = self.GetEvtHandlerEnabled()
        self.SetEvtHandlerEnabled(False)    # for programmatic changes we don't want an event
        try:
            if not isinstance(val, str):
                val = str(val)
            wx.TextCtrl.SetValue(self, val)
        except NameError:
            val = str(val)
            wx.TextCtrl.SetValue(self, val)
        finally:                            # so the old setting is safely restored
            self.SetEvtHandlerEnabled(oldSetting)

    def setNormalText(self, val):   # displays the text and resets any settings-changes
        self.SetBackgroundColour(wx.NullColour)
        self.SetForegroundColour(wx.NullColour)
        self.setText(val)
        
    def setHighlightText(self, val):    # displays the text and sets the colors like selected-text
        self.SetBackgroundColour(HIGHLIGHT)
        self.SetForegroundColour(HIGHLIGHTTEXT)
        self.setText(val)
        
    def setWarningText(self, val):      # displays the text and sets the colors in a warning-color
        self.SetBackgroundColour('ORANGE')
        self.SetForegroundColour(HIGHLIGHTTEXT)
        self.setText(val)

    # puts back old value
    def Discard(self):
#        self.setText(self.strInitValue)
        wx.TextCtrl.SetValue(self, self.strInitValue)   # in this case validating should be done

    # def OnEnSetFocus(UINT nID):
    def OnSetFocus(self, event):
        if not self.error:
            self.strInitValue = wx.TextCtrl.GetValue(self)    # get actual text from the control
            self.SetBackgroundColour(COLOUR_SELECTED)   # yellow
            self.SetForegroundColour(wx.NullColour)
        event.Skip()
        logger.info("%s%s %d" % (self.__class__.__name__ , ".OnSetFocus", self.GetId()))

    # def OnEnKillFocus(UINT nID):
    def OnKillFocus(self, event):
        if self.error:
            logger.info("%s%s %d %s" % (self.__class__.__name__ , ".OnKillFocus", self.GetId(), "not allowed!"))
            self.SetFocus()     # with errors leaving is not allowed
            return

        logger.info("%s%s %d" % (self.__class__.__name__ , ".OnKillFocus", self.GetId()))
        self.SetBackgroundColour(wx.NullColour)
        self.SetForegroundColour(wx.NullColour)
        if self.behaviour & BEHAVIOUR.NUMERIC and self.value != wx.EmptyString:
            self.SetWindowText(self.value)
        event.Skip()

    def OnEscape(self, event):
        keycode = event.GetKeyCode()
        if keycode == wx.WXK_ESCAPE:
            if self.HasFocus():
                logger.info("%s%s%s%d" % (self.__class__.__name__ , ".OnEscape", event, keycode))
                self.Discard()      # puts back old value
                #return    # experimental: put back prev. value and then leave...
        event.Skip()

    def SetLabel(self, labelText):
        pass
    

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #wx.TextCtrl.SetToolTipString(self, toolTipString)   # pass the translated string to baseclass-method
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)


# Experimental (not used yet, skeleton to create own widgets)
class MyWidget(wx.PyPanel):
    """ experimental - custom controls """
    def __init__(self, parent, id):  # @ReservedAssignment
        wx.PyPanel.__init__(self, parent, id, size=(-1, 30), style=wx.SUNKEN_BORDER)
        self.font = wx.Font(9, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL,
                            wx.FONTWEIGHT_NORMAL, False, 'Courier 10 Pitch')


        self.Bind(wx.EVT_PAINT, self.OnPaint)       # necessary, otherwise the control is never painted
        self.Bind(wx.EVT_SIZE, self.OnSize)

    def OnPaint(self, event):  # @UnusedVariable
        logger.info("%s%s" % (self.__class__.__name__ , ".OnPaint"))
        num = list(range(75, 700, 75))
        dc = wx.PaintDC(self)
        dc.SetFont(self.font)
        w, h = self.GetSize()  # @UnusedVariable
        self.cw = self.GetParent().cw
        step = int(round(w / 10.0))
        j = 0
        till = (w / 750.0) * self.cw
        full = (w / 750.0) * 700

        if self.cw >= 700:
            dc.SetPen(wx.Pen('#FFFFB8'))
            dc.SetBrush(wx.Brush('#FFFFB8'))
            dc.DrawRectangle(0, 0, full, 30)
            dc.SetPen(wx.Pen('#ffafaf'))
            dc.SetBrush(wx.Brush('#ffafaf'))
            dc.DrawRectangle(full, 0, till-full, 30)
        else:
            dc.SetPen(wx.Pen('#FFFFB8'))
            dc.SetBrush(wx.Brush('#FFFFB8'))
            dc.DrawRectangle(0, 0, till, 30)


        dc.SetPen(wx.Pen('#5C5142'))
        for i in range(step, 10*step, step):
            dc.DrawLine(i, 0, i, 6)
            width, height = dc.GetTextExtent(str(num[j]))  # @UnusedVariable
            dc.DrawText(str(num[j]), i-width/2, 8)
            j = j + 1

    def OnSize(self, event):
        logger.info("%s%s" % ( self.__class__.__name__ , ".OnSize"))
        self.Refresh()
        event.Skip()

    def DoGetBestSize(self):
        """
        Overridden base class virtual.  Determines the best size of the control
        based on the label size, the bitmap size and the current font.
        """
        logger.info("%s%s" % ( self.__class__.__name__ , ".DoGetBestSize"))

        # Retrieve our properties: the text label, the font and the check
        # bitmap
        label = self.GetLabel()  # @UnusedVariable
        font  = self.GetFont()   # @UnusedVariable

        best = super(self.__class__, self).DoGetBestSize()
        return best


class LabeledEditField(BasePanel):
    '''Represents a label field with an alphanumerical input field.'''       # can be accessed via __doc__
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, value=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, min=-100.0, max=100.0, behaviour=BEHAVIOUR.ALPHANUMERIC, flRequired=True, toolTipString=wx.EmptyString, name='labeledEditField', panelStyle=None, style=wx.TAB_TRAVERSAL|wx.NO_BORDER, ContextMenu = False, editSize=wx.DefaultSize, Callback=False, minSizeEdit=(100, -1), minSizeLabel=(100, -1), emptyInputAllowed=False, propChoice=0, layoutChoice=wx.HORIZONTAL):  # @ReservedAssignment
        self.resourcelabel = label
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)
        # Give option to have a different style for the panel and the edit field
        if panelStyle != None:
            BasePanel.__init__(self, parent, id, pos=pos, size=size, style=panelStyle, name=name)          
        else:
            BasePanel.__init__(self, parent, id, pos=pos, size=size, style=style, name=name)
        if _DEBUG & 0x4:
            BasePanel.SetBackgroundColour(self, LIGHTYELLOW)

        self.hvbox = wx.BoxSizer(layoutChoice)

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False

        # an optional bitmap (not used, just to see how artprovider works)
        """
        bmp = wx.ArtProvider.GetBitmap(wx.ART_TIP, wx.ART_OTHER, (16, 16))
        ico = wx.StaticBitmap(parent, wx.ID_ANY, bmp)
        self.hvbox.Add(ico, 0, wx.ALL|wx.ALIGN_CENTER, SMALLBORDER)
        """
        self.lbl = wx.StaticText(self, wx.ID_ANY, label, style=wx.ALIGN_LEFT, name="_" + name)
        self.lbl.SetInitialSize(minSizeLabel)
        if _DEBUG & 0x4:
            self.lbl.SetBackgroundColour('YELLOW')
            
        if layoutChoice == wx.VERTICAL: # wx.ALIGN_CENTER_VERTICAL is only allowed in HORIZONTAL Sizers
            self.hvbox.Add(self.lbl, 1, wx.LEFT|wx.RIGHT|wx.TOP|wx.BOTTOM, SMALLBORDER)
        else:
            self.hvbox.Add(self.lbl, 1, wx.LEFT|wx.RIGHT|wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL, SMALLBORDER)

        self.edit = EditField(self, wx.ID_ANY, value, pos=pos, size=editSize, min=min, max=max, behaviour=behaviour, flRequired=flRequired, name="__" + name, style=style, emptyInputAllowed=emptyInputAllowed)
        self.edit.SetInitialSize(minSizeEdit)
        self.hvbox.Add(self.edit, propChoice, wx.TOP|wx.BOTTOM|wx.LEFT|wx.RIGHT|wx.EXPAND, SMALLBORDER)

        self.SetSizerAndFit(self.hvbox)
        
        #Check if we have a custom Popup Menu
        if ContextMenu != False:
            if IsMethod(ContextMenu) == True:
                self.ContextMenu = ContextMenu
                self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
        # allow a callback function to inform the calling code if this widget is focused
        if Callback:
            self.Bind(wx.EVT_CHILD_FOCUS, self.OnCildFocus) 
        self.Callback = Callback
                
    def GetResourceLabel(self):
        return getattr(self, "resourcelabel", "")

    def OnContextMenu(self, event):
        ''' Wrapper method for calling the custom menu method '''
        self.ContextMenu(event, self)
        
    def OnCildFocus(self, event):
        if callable(self.Callback):
            event.SetEventObject(self)
            self.Callback(event)
        
    def WriteText(self, *args, **kwargs):
        ''' Inserts a given text into the Editfield at the carret position '''
        self.edit.WriteText(*args, **kwargs)
        
    def GetBackgroundColour(self):
        return self.edit.GetBackgroundColour()
    
    def SetBackgroundColour(self, *args, **kwargs):
        return self.edit.SetBackgroundColour(*args, **kwargs)
    
    def GetValue(self):
        return self.edit.GetValue()
    
    def SetValue(self, *args, **kwargs):
        self.edit.SetValue(*args, **kwargs)

    def ChangeValue(self, *args, **kwargs):
        self.edit.ChangeValue(*args, **kwargs)

    def GetText(self):
        return self.edit.getText()

    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)
        self.lbl.Enable(enable)
        self.edit.Enable(enable)
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)

    def Disable(self):
        self.lbl.Disable()
        self.edit.Disable()
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def IsEnabled(self):
        return self.edit.IsEnabled()
    
    def Show(self, *args, **kwargs):
        self.lbl.Show(*args, **kwargs)
        self.edit.Show(*args, **kwargs)

    def __del__(self):
        # destroy the popup window
        self.killPop()

    def OnEnterWindow(self, event):
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        rect = self.GetScreenRect()
        if rect.Contains(wx.GetMousePosition()):
            self.shouldPOP = True
            (w, h) = self.GetClientSize()
            pos = self.ClientToScreen((w / 2, h))
            wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)
            if callable(self.Callback):
                self.Callback(event)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        rect = self.GetScreenRect()
#        (x, y) = wx.GetMousePosition()
        # in this case we get also a leave event when the mouse moves over the label or edit field
        # -> so we have to check whether we are really outside our LabeledEditField-panel
#        if rect.InsideXY(x, y) == False:
        if not rect.Contains(wx.GetMousePosition()):
            self.shouldPOP = False
            self.killPop()

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:
            self.popUpWin.Kill()
            self.popUpWin = None

    def GetLabel(self):
        if hasattr(self,"lbl"):
            return self.lbl.GetLabel()
        else:
            return wx.EmptyString

    def SetLabel(self, labelString):
        if hasattr(self,"lbl"):
            if labelString.find('\\n') >= 1:
                labelString = labelString.replace('\\n','\n')
            self.lbl.SetLabel(labelString)

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #BasePanel.SetToolTipString(self, toolTipString)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def SetEditable(self, *args, **kwargs):
        self.edit.SetEditable(*args, **kwargs)
       
#     def SetCanFocus(self, *args, **kwargs):
#         self.edit.SetCanFocus(*args, **kwargs)
       
    def SetRange(self, *args, **kwargs):
        self.edit.SetRange(*args, **kwargs) 
        
    def GetMinValue(self):
        return self.edit.GetMinValue()
    
    def GetMaxValue(self):
        return self.edit.GetMaxValue()


class DoubleLabeledEditField(BasePanel):
    '''Represents a twolabel fields with alphanumerical input fields.'''       # can be accessed via __doc__
    def __init__(self, parent, id=wx.ID_ANY, label1=wx.EmptyString, value1=wx.EmptyString, label2=wx.EmptyString, value2=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, min=-100.0, max=100.0, behaviour=BEHAVIOUR.ALPHANUMERIC, flRequired=True, toolTipString=wx.EmptyString, name='labeledEditField', sizeEdit=(50,-1)):  # @ReservedAssignment
        txtfieldname1 = "_%s_%d" % (name, 1)
        txtfieldname2 = "_%s_%d" % (name, 2)

        label1 = getText(label1, txtfieldname1)
        label2 = getText(label2, txtfieldname2)

        BasePanel.__init__(self, parent, id, pos, size, wx.TAB_TRAVERSAL|wx.NO_BORDER, name)
        if _DEBUG & 0x4:
            self.SetBackgroundColour(LIGHTYELLOW)

        self.hbox = wx.BoxSizer(wx.HORIZONTAL)
        self.SetSizer(self.hbox)

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False

        # an optional bitmap (not used, just to see how artprovider works)
        """
        bmp = wx.ArtProvider.GetBitmap(wx.ART_TIP, wx.ART_OTHER, (16, 16))
        ico = wx.StaticBitmap(parent, wx.ID_ANY, bmp)
        self.hbox.Add(ico, 0, wx.ALL|wx.ALIGN_CENTER, SMALLBORDER)
        """

        #First pair of fields
        #self.hbox.Add((0,0), 0, wx.LEFT|wx.RIGHT, BORDER)     # a little space between
        self.lbl1 = wx.StaticText(self, wx.ID_ANY, label1, style=wx.ALIGN_LEFT, name=txtfieldname1)
        self.hbox.Add(self.lbl1, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, SMALLBORDER)

        if _DEBUG & 0x4:
            self.lbl1.SetBackgroundColour('YELLOW')

        size=sizeEdit
        self.edit1 = EditField(self, wx.ID_ANY, value1, pos, size , min, max, behaviour, flRequired, name="__" + name + "_1" )
        # 09/04/2024 jorgk!
        self.hbox.Add(self.edit1, 0, wx.ALL|wx.EXPAND, SMALLBORDER )
        #self.hbox.Add(self.edit1, 1, wx.ALL|wx.ALIGN_LEFT, 1)

        #self.hbox.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 )     # a little space between
        self.hbox.Add((0,0), 1, wx.LEFT|wx.RIGHT, BORDER)

        #Second pair of fields
        self.lbl2 = wx.StaticText(self, wx.ID_ANY, label2, style=wx.ALIGN_LEFT, name=txtfieldname2)
        self.hbox.Add(self.lbl2, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, SMALLBORDER)

        if _DEBUG & 0x4:
            self.lbl2.SetBackgroundColour('YELLOW')

        self.edit2 = EditField(self, wx.ID_ANY, value2, pos, size, min, max, behaviour, flRequired, name="__" + name + "_2" )
        self.hbox.Add(self.edit2, 0, wx.ALL|wx.EXPAND, SMALLBORDER )
        #self.hbox.Add(self.edit2, 1, wx.ALL|wx.ALIGN_LEFT, 1)

        self.hbox.Fit(self)

    def GetValue(self):
        return (self.edit1.GetValue(), self.edit2.GetValue())

    def SetValue(self, val):
        self.edit1.SetValue(val[0])
        self.edit2.SetValue(val[1])

    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)

        self.lbl1.Enable(enable)
        self.edit1.Enable(enable)
        self.lbl2.Enable(enable)
        self.edit2.Enable(enable)
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)

    def Disable(self):
        self.lbl1.Disable()
        self.edit1.Disable()
        self.lbl2.Disable()
        self.edit2.Disable()
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def IsEnabled(self):
        return self.edit1.IsEnabled()
    
    def Show(self, show):
        self.lbl1.Show(show)
        self.edit1.Show(show)
        self.lbl2.Show(show)
        self.edit2.Show(show)

    def __del__(self):
        # destroy the popup window
        self.killPop()

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        rect = self.GetScreenRect()
        if rect.Contains(wx.GetMousePosition()):
            self.shouldPOP = True
            (w, h) = self.GetClientSize()
            pos = self.ClientToScreen((w / 2, h))
            wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        rect = self.GetScreenRect()
#        (x, y) = wx.GetMousePosition()
        # in this case we get also a leave event when the mouse moves over the label or edit field
        # -> so we have to check whether we are really outside our LabeledEditField-panel
#        if rect.InsideXY(x, y) == False:
        if not rect.Contains(wx.GetMousePosition()):
            self.shouldPOP = False
            self.killPop()

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:
            self.popUpWin.Kill()
            self.popUpWin = None

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #BasePanel.SetToolTipString(self, toolTipString)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def SetEditable(self, editable):
        self.edit1.SetEditable(editable)
        self.edit2.SetEditable(editable)
        
    def GetSubWdg(self, NoOfWdg=1):
        subwdg = None
        if NoOfWdg == 1:
            subwdg = self.lbl1
        elif NoOfWdg == 2:
            subwdg = self.lbl2
        return subwdg
    
    def GetNumberOfLabels(self):
        return 2
    
    def GetItemName(self, labelNo=0):
        if labelNo == 0:
            return self.lbl1.Name
        if labelNo == 1:
            return self.lbl2.Name

    def GetItemResourceLabel(self, labelNo=0):
        if labelNo == 0:
            return self.lbl1.GetLabel()
        if labelNo == 1:
            return self.lbl2.GetLabel()

    def SetItemLabel(self, labelNo=0, labelStr=""):
        if labelNo == 0:
            self.lbl1.SetLabel(labelStr)
        if labelNo == 1:
            self.lbl2.SetLabel(labelStr)

    def GetItemLabel(self, labelNo=0):
        if labelNo == 0:
            return self.lbl1.GetLabel()
        if labelNo == 1:
            return self.lbl2.GetLabel()

    def GetItemTooltip(self, labelNo=0):
        if labelNo == 0:
            #return self.lbl1.GetToolTipString() or ""
            return self.lbl1.GetToolTipText() or ""
        if labelNo == 1:
            #return self.lbl2.GetToolTipString() or ""
            return self.lbl2.GetToolTipText() or ""

    def SetItemTooltip(self, labelNo=0, labelStr=""):
        if labelNo == 0:
            self.lbl1.SetToolTipString(labelStr)
        if labelNo == 1:
            self.lbl2.SetToolTipString(labelStr)

    def SetRange(self, dMin1=None, dMax1=None, dMin2=None, dMax2=None):
        if dMin1 != None and dMax1 != None:
            self.edit1.SetRange(dMin1, dMax1)  
        if dMin2 != None and dMax2 != None:
            self.edit2.SetRange(dMin2, dMax2) 
        
    def GetMinValue1(self):
        return self.edit1.GetMinValue()
    
    def GetMaxValue1(self):
        return self.edit1.GetMaxValue()
    
    def GetMinValue2(self):
        return self.edit2.GetMinValue()
    
    def GetMaxValue2(self):
        return self.edit2.GetMaxValue()  

class CheckboxEditField(BasePanel):
    '''Represents a checkbox with an alphanumerical input field.'''       # can be accessed via __doc__
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, value=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, min=-100.0, max=100.0, behaviour=BEHAVIOUR.ALPHANUMERIC, flRequired=True, toolTipString=wx.EmptyString, name='Lblcheckboxname', name2='LblEditfieldname', style=0, ContextMenu = False, editSize=wx.DefaultSize, Callback=False, minSizeEdit=(100, -1), minSizeLabel=(100, -1), emptyInputAllowed=False, propChoice=0):  # @ReservedAssignment
        self.resourcelabel = label
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)

        BasePanel.__init__(self, parent, id, pos=pos, size=size, style=wx.TAB_TRAVERSAL|wx.NO_BORDER, name='_' + name)
        if _DEBUG & 0x4:
            BasePanel.SetBackgroundColour(self, LIGHTYELLOW)

        self.hbox = wx.BoxSizer(wx.HORIZONTAL)

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False

        self.cbx = OptiCheckBox(self, wx.ID_ANY, label, style=0, name=name)

        self.cbx.SetInitialSize(minSizeLabel)
        if _DEBUG & 0x4:
            self.cbx.SetBackgroundColour('YELLOW')

        self.hbox.Add(self.cbx, 1, wx.LEFT|wx.TOP|wx.BOTTOM|wx.EXPAND, SMALLBORDER)

        self.edit = EditField(self, wx.ID_ANY, value, pos=pos, size=editSize, min=min, max=max, behaviour=behaviour, flRequired=flRequired, name=name2, style=style, emptyInputAllowed=emptyInputAllowed)
        self.edit.SetInitialSize(minSizeEdit)
        self.hbox.Add(self.edit, propChoice, wx.TOP|wx.BOTTOM|wx.RIGHT|wx.EXPAND, SMALLBORDER)
        #
        self.cbx.addSlave(name2)

        self.SetSizerAndFit(self.hbox)
        
    def GetResourceLabel(self):
        return getattr(self, "resourcelabel", "")

    def addSlave(self, *args, **kwargs):
        return self.cbx.addSlave(*args, **kwargs)

    def setSlaves(self, *args, **kwargs):
        return self.cbx.setSlaves(*args, **kwargs)

class _LabeledBaseBox(BasePanel):
    '''Represents a label field with a choice-box.'''
    # Events: wx.EVT_CHOICE, wx.EVT_COMBOBOX
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, toolTipString=wx.EmptyString, name='labeledComboBox', propChoice=0, prettyNamesDict=None, style=wx.TAB_TRAVERSAL|wx.NO_BORDER):  # @ReservedAssignment
        self.resourcelabel = label
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)

        BasePanel.__init__(self, parent, id, pos=pos, size=size, style=style, name=name)
        if _DEBUG & 0x4:
            BasePanel.SetBackgroundColour(self, LIGHTYELLOW)

        self.hbox = wx.BoxSizer(wx.HORIZONTAL)

        if toolTipString:
            self.SetToolTipString(toolTipString)

        self.popUpWin = None
        self.shouldPOP = False

        if label != wx.EmptyString:
            self.lbl = wx.StaticText(self, wx.ID_ANY, label, style=wx.ALIGN_LEFT, name="_" + name)
            #self.hbox.Add(self.lbl, 0, wx.ALL, SMALLBORDER)
            if propChoice > 0:
                proportion = 100
            else: 
                proportion = 0
            self.lbl.SetInitialSize((120, -1))
            if _DEBUG & 0x4:
                self.lbl.SetBackgroundColour('YELLOW')
            self.hbox.Add(self.lbl, proportion, wx.ALL|wx.ALIGN_CENTER_VERTICAL, SMALLBORDER)

        self.items = []
        self.prettyNamesDict = prettyNamesDict

    def GetResourceLabel(self):
        return getattr(self, "resourcelabel", "")

    def GetValue(self):
        """
        Returns the string-value of the selected item.
        """
        if self.GetBackgroundColour() == PINK:
            return None
        return self.GetStringSelection() # Returns the label of the selected item or an empty string if no item is selected.

    def SetValue(self, s):
        """
        Select the item with the specifed string
        """
        if s is None:
            self.cb.SetStringSelection(wx.EmptyString)
#            self.cb.SetBackgroundColour(PINK)        # show the not initialized state
            self.SetBackgroundColour(PINK)        # show the not initialized state
        else:
            s = str(s)
            if self.cb.FindString(s) == -1:
                self.cb.Append(s)
            self.SetStringSelection(s)

    def GetString(self, n):
        return self.cb.GetString(n)
    
    def SetString(self, n, s):
        return self.cb.SetString(n, s)

    def Append(self, s, c=""):
        """
        Adds the String to the choice list
        """
        if s is not None:
            self.cb.Append(s, c)
            
    def AppendItems(self, s=[], sort=True, reverseSort=False):  # @UnusedVariable
        """
        Adds the list to the choice box and sorts it if you want
        """
        TempList = []
        if type(s) != list:
            return False
        for entry in s:
            TempList.append(GetOptimalValueBack(entry))
        try:
            TempList.sort(reverse=reverseSort)
        except:
            pass
        for entry in TempList:
            self.cb.Append(str(entry))
        
    def AppendItemsFast(self, s=[], sort=True, reverseSort=False):
        """
        Adds the list to the choice box and sorts it if you want
        """
        if not isinstance(s, list):
            return False
        if sort:
            try:
                for it in s:
                    float(it)
                s = [str(i) for i in s]
                ss = sorted(s, key = float, reverse=reverseSort)
            except:
                ss = sorted(s, key = str, reverse=reverseSort) 
        else:
            ss = s[:]
        # use the for to insert the value is too slowly
        self.cb.SetItems(ss)

    def Clear(self):
        """
        Clears the Choice List
        """
        self.cb.Clear()

    def GetItems(self):
        if getattr(self, 'prettyNamesDict', None):
            return self.items
        else:
            return self.cb.GetItems()
    
    def SetItems(self, items):
        if getattr(self, 'prettyNamesDict', None):
            self.items = items
            _items = list(items)        # create deep copy
            for i, item in enumerate(_items):
                if item in list(self.prettyNamesDict.keys()):
                    _items[i] = self.prettyNamesDict[item]
            self.cb.SetItems(_items)
        else:
            self.cb.SetItems(items)
        
    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)

        if hasattr(self,"lbl"):
            self.lbl.Enable(enable)
        self.cb.Enable(enable)
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)
        #BasePanel.Enable(self, enable)
        
    def Disable(self):
        if hasattr(self,"lbl"):
            self.lbl.Disable()
        self.cb.Disable()
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)
        #BasePanel.Disable(self)
        
    def Show(self, show):
        if hasattr(self,"lbl"):
            self.lbl.Show(show)
        self.cb.Show(show)

    def __del__(self):
        # destroy the popup window
        self.killPop()

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        self.shouldPOP = True
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        rect   = self.GetScreenRect()
        # in this case we get also a leave event when the mouse moves over the label or edit field
        # -> so we have to check whether we are really outside our panel
        if not rect.Contains(wx.GetMousePosition()):
            self.shouldPOP = False
            self.killPop()

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:
            self.popUpWin.Kill()
            self.popUpWin = None

    def GetLabel(self):
        if hasattr(self,"lbl"):
            return self.lbl.GetLabel()
        else:
            return wx.EmptyString

    def SetLabel(self, labelString):
        if hasattr(self,"lbl"):
            self.lbl.SetLabel(labelString)

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #BasePanel.SetToolTipString(self, toolTipString)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def SetSelection(self, choice):
        try:
            self.cb.SetSelection(int(choice))
        except:
            return
    def GetSelection(self):
        return self.cb.GetSelection()
    def SetStringSelection(self, s):
        if getattr(self, 'prettyNamesDict', None):
            s = self.prettyNamesDict.get(s, s)
        return self.cb.SetStringSelection(s)
    def GetStringSelection(self):
        if isinstance(self.cb, wx.ComboBox):
            selection = self.cb.GetValue()
        else:
            selection = self.cb.GetStringSelection()
        if getattr(self, 'prettyNamesDict', None):
            for key, val in list(self.prettyNamesDict.items()):
                if selection == val:
                    return key
        return selection
    def GetCount(self):
        return self.cb.GetCount()
    def GetClientData(self, sel):
        return self.cb.GetClientData(sel)
    def IsEmpty(self):
        return self.cb.IsEmpty()
    def FindString(self, string):
        return self.cb.FindString(string)
    def Delete(self, choice):
        self.cb.Delete(choice)

# The LabeledComboBox2 is a ComboBox indeed (unfortunately the LabeledComboBox is a ChoiceBox)
class LabeledComboBox2(_LabeledBaseBox):
    '''Represents a label field with a choice-box.'''
    # Events: wx.EVT_COMBOBOX
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, choices=None, toolTipString=wx.EmptyString, name='labeledComboBox', sizeChoice=wx.DefaultSize, propChoice=0, minSizeChoice=(100, -1), prettyNamesDict=None, style=wx.TAB_TRAVERSAL|wx.NO_BORDER):  # @ReservedAssignment

        _LabeledBaseBox.__init__(self, parent, id, label, pos, size, toolTipString, name, propChoice, prettyNamesDict, style)

        self.cb = wx.ComboBox(self, wx.ID_ANY, choices=choices or [], name="__" + name, size=sizeChoice)
        if minSizeChoice != None:
            self.cb.SetInitialSize(minSizeChoice)
            if propChoice > 0:
                proportion = int(propChoice * 100)
            else: 
                proportion = 0
        # self.hbox.Add(self.cb, proportion, wx.ALL, SMALLBORDER)    # not nice
        self.hbox.Add(self.cb, proportion)

        self.SetSizerAndFit(self.hbox)
        
class LabeledChoiceBox(_LabeledBaseBox):
    '''Represents a label field with a choice-box.'''
    # Events: wx.EVT_CHOICE
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, choices=None, toolTipString=wx.EmptyString, name='labeledComboBox', sizeChoice=wx.DefaultSize, propChoice=0, minSizeChoice=(100, -1), prettyNamesDict=None, style=wx.TAB_TRAVERSAL|wx.NO_BORDER):  # @ReservedAssignment

        _LabeledBaseBox.__init__(self, parent, id, label, pos, size, toolTipString, name, propChoice, prettyNamesDict, style)
        # cad.DebLogA('window.py LabeledComboBox 1!')
        self.cb = wx.Choice(self, wx.ID_ANY, choices=choices or [], name="__" + name, size=sizeChoice, style=style)
        if minSizeChoice != None:
            self.cb.SetInitialSize(minSizeChoice)
            if propChoice > 0:
                proportion = int(propChoice * 100)
            else: 
                proportion = 0
        # self.hbox.Add(self.cb, proportion, wx.ALL, SMALLBORDER)    # not nice
        self.hbox.Add(self.cb, proportion)
        

        self.SetSizerAndFit(self.hbox)

# Our LabeledComboBox is in fact a ChoiceBox (was a mistake made in the past; if a real combobox is needed -> use LabeledComboBox2
LabeledComboBox = LabeledChoiceBox


class LabeledComboBoxWithEF(BasePanel):
    '''Represents a label field with a choice-box and edit-field.'''
    # Events: wx.EVT_CHOICE
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, choices=None, toolTipString=wx.EmptyString, name='labeledComboBox', sizeChoice=wx.DefaultSize, propChoice=0, minSizeChoice=None):  # @ReservedAssignment
        self.resourcelabel = label
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)

        BasePanel.__init__(self, parent, id, pos, size, wx.TAB_TRAVERSAL|wx.NO_BORDER, name)
        if _DEBUG & 0x4:
            self.SetBackgroundColour(LIGHTYELLOW)

        self.hbox = wx.BoxSizer(wx.HORIZONTAL)
        self.SetSizer(self.hbox)

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False

        if label != wx.EmptyString:
            self.lbl = wx.StaticText(self, wx.ID_ANY, label, style=wx.ALIGN_LEFT, name="_" + name)
            self.hbox.Add(self.lbl, 0, wx.ALL|wx.CENTER, SMALLBORDER)
            self.hbox.Add(SPACER, 1, wx.ALL, SMALLBORDER)
            if _DEBUG & 0x4:
                self.lbl.SetBackgroundColour('YELLOW')
        
        self.ef = EditField(self,
                            wx.ID_ANY,
                            value=wx.EmptyString,
                            pos=wx.DefaultPosition,
                            size=(50, -1),
                            #min=min,    # min,max is not in parameter list (would use built in function instead) !!
                            #max=max, 
                            behaviour=BEHAVIOUR.ALPHANUMERIC|BEHAVIOUR.SCALE_DISTANCE,
                            flRequired=True,
                            name="EF__",
                            style=wx.TE_READONLY)

        self.hbox.Add(self.ef, propChoice, wx.ALL, SMALLBORDER)
        if _DEBUG & 0x4:
            self.ef.SetBackgroundColour('YELLOW')
        self.cb = wx.Choice(self, wx.ID_ANY, choices=choices or [], name="__" + name, size=sizeChoice)
        if minSizeChoice != None:
            self.cb.SetMinSize(minSizeChoice)
        self.hbox.Add(self.cb, propChoice, wx.ALL, SMALLBORDER)
        if _DEBUG & 0x4:
            self.cb.SetBackgroundColour('YELLOW')

        self.hbox.Fit(self)

    def GetResourceLabel(self):
        return getattr(self, "resourcelabel", "")

    def GetValue(self):
        """
        Returns the index of the selected item or wx.NOT_FOUND if no item is selected.
        """
        if self.GetBackgroundColour() == PINK:
            return None
#        return self.cb.GetSelection()   # Returns the index of the selected item or wx.NOT_FOUND if no item is selected.
        return self.cb.GetStringSelection() # Returns the label of the selected item or an empty string if no item is selected.
#        return self.cb.GetValue()       # Returns the current value in the combobox text field.
    def SetValue(self, s):
        """
        Select the item with the specifed string
        """
        if s is None:
            self.cb.SetStringSelection(wx.EmptyString)
#            self.cb.SetBackgroundColour(PINK)        # show the not initialized state
            self.SetBackgroundColour(PINK)        # show the not initialized state
        else:
            s = str(s)
            if self.cb.FindString(s) == -1:
                self.cb.Append(s)
            self.cb.SetStringSelection(s)

    def GetString(self, n):
        return self.cb.GetString(n)
    def SetString(self, n, s):
        return self.cb.SetString(n, s)

    def Append(self, s, c=""):
        """
        Adds the String to the choice list
        """
        if s is not None:
            self.cb.Append(s, c)
            
    def AppendItems(self, s=[], sort=True, reverseSort=False):  # @UnusedVariable
        """
        Adds the list to the choice box and sorts it if you want
        """
        TempList = []
        if type(s) != list:
            return False
        for entry in s:
            TempList.append(GetOptimalValueBack(entry))
        TempList.sort(reverse=reverseSort)
        for entry in TempList:
            self.cb.Append(str(entry))
    
    def AppendItemsFast(self, s=[], sort=True, reverseSort=False):
        """
        Adds the list to the choice box and sorts it if you want
        """
        TempList = []
        if not isinstance(s, list):
            return False
        if sort:
            try:
                if s[0].isdigit():
                    for it in s:
                        float(it)
                    ss = [float(it) for it in s]
                    ss = list(set(ss))
                ss.sort(reverse=reverseSort)
            except:
                ss = s[:]
                # sort as string
                ss.sort(reverse=reverseSort)
        else:
            ss = s[:]
        for dummy, entry in enumerate(ss):
            TempList.append(str(GetOptimalValueBack(entry)))
        #for entry in TempList:
        # use the for to insert the value is too slowly
        self.cb.SetItems(TempList[:])

    def Clear(self):
        """
        Clears the Choice List
        """
        self.cb.Clear()

    def GetItems(self):
        return self.cb.GetItems()
    
    def SetItems(self, items):
        self.cb.SetItems(items)
        
    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)

        if hasattr(self,"lbl"):
            self.lbl.Enable(enable)
        self.cb.Enable(enable)
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)
        BasePanel.Enable(self, enable)

    def Disable(self):
        if hasattr(self,"lbl"):
            self.lbl.Disable()
        self.cb.Disable()
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)
        BasePanel.Disable(self)
        
    def Show(self, show):
        if hasattr(self,"lbl"):
            self.lbl.Show(show)
        self.cb.Show(show)

    def __del__(self):
        # destroy the popup window
        self.killPop()

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        self.shouldPOP = True
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        rect   = self.GetScreenRect()
        # in this case we get also a leave event when the mouse moves over the label or edit field
        # -> so we have to check whether we are really outside our panel
        if not rect.Contains(wx.GetMousePosition()):
            self.shouldPOP = False
            self.killPop()

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:
            self.popUpWin.Kill()
            self.popUpWin = None

    def GetLabel(self):
        if hasattr(self,"lbl"):
            return self.lbl.GetLabel()
        else:
            return wx.EmptyString

    def SetLabel(self, labelString):
        if hasattr(self,"lbl"):
            self.lbl.SetLabel(labelString)

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #BasePanel.SetToolTipString(self, toolTipString)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def SetSelection(self, choice):
        self.cb.SetSelection(choice)
    def GetSelection(self):
        return self.cb.GetSelection()
    def SetStringSelection(self, s):
        return self.cb.SetStringSelection(s)
    def GetStringSelection(self):
        return self.cb.GetStringSelection()
    def GetCount(self):
        return self.cb.GetCount()
    def GetClientData(self, sel):
        return self.cb.GetClientData(sel)
    def IsEmpty(self):
        return self.cb.IsEmpty()
    def FindString(self, string):
        return self.cb.FindString(string)
    def Delete(self, choice):
        self.cb.Delete(choice)


class OptiListBox(wx.ListBox):
    '''Represents a ListBox.'''
    # Process a wx.EVT_COMMAND_LISTBOX_SELECTED event, when an item on the list is selected.
    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, choices=[], style=wx.LB_SINGLE, validator=wx.DefaultValidator, toolTipString=wx.EmptyString, name='OptiListBox'):  # @ReservedAssignment

        wx.ListBox.__init__(self, parent, id, pos, size, choices, style, validator, name)

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False

    def __del__(self):
        # destroy the popup window
        self.killPop()

    def GetValue(self):
        """
        Returns the index of the selected item or wx.NOT_FOUND if no item is selected.
        """
        if self.GetBackgroundColour() == PINK:
            return None
        return self.GetSelection()

    def SetValue(self, s):
        """
        Select the item with the specifed string
        """
        if s is None:
            self.SetStringSelection(wx.EmptyString)
            self.SetBackgroundColour(PINK)        # show the not initialized state
        else:
            self.SetStringSelection(str(s))
            self.SetBackgroundColour(wx.NullColour)

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #wx.ListBox.SetToolTipString(self, toolTipString)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        self.shouldPOP = True
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        rect   = self.GetScreenRect()
        if not rect.Contains(wx.GetMousePosition()):
            self.shouldPOP = False
            self.killPop()

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:
            self.popUpWin.Kill()
            self.popUpWin = None

class OptiMultiCheckBox(BasePanel):
    """ this user widget provides an array of checkboxes
    the 'checked' state of each box is set by a bitmask argument (or SetValue)
    """
    def __init__(self, parent, id=wx.ID_ANY, lblList=[wx.EmptyString], toolTipList=[wx.EmptyString],  # @ReservedAssignment
                  checkStatus=0x0, abilityMask=None, pos=wx.DefaultPosition, size=wx.DefaultSize,
                   style=wx.RA_SPECIFY_ROWS, validator=wx.DefaultValidator, name='OptiMultiCheckBox'):  # @ReservedAssignment @UnusedVariable
        #
        # The 'lblList' specifies the number of checkboxes; means this list must exist and don't have to be empty!
        if not lblList or len(lblList) < 1:
            raise ReferenceError('OptiMultiCheckBox: must be instantiated with a non empty lblList-argument!')
         
        BasePanel.__init__(self, parent, id, pos, size, wx.TAB_TRAVERSAL|wx.NO_BORDER, name)
        #
        if style == wx.RA_SPECIFY_ROWS:
            xStart = MEDIUMBORDER
            yStart = 0
            xInc   = 0
            yInc   = MEDIUMBORDER
        else:
            xStart = 0
            yStart = MEDIUMBORDER
            xInc   = MEDIUMBORDER
            yInc   = 0
        #
        self.abilityMask = abilityMask
        self.checkBoxes = []
        #
        cBit = 0x1
        cnt = 0
        for i, eachLabel in enumerate(lblList):
            cbName = "_%s_%d" % (name, cnt)
            #measurecycle widgets are treated differently
            if hasattr(parent,"isMainPanel"):
                if parent.isMainPanel==True:
                    classnameofparent=type(parent).__name__
                    label = getText(eachLabel, cbName, classnameofparent=classnameofparent)
                else:
                    label = getText(eachLabel, cbName)
            else:
                label = getText(eachLabel, cbName)
            #label = getText(eachLabel, cbName)
            checked = (checkStatus & cBit) != False
            #size = wx.Size(int(180 * ScreenScaleFactor), int(15 * ScreenScaleFactor))
            size = wx.Size(int(300 * ScreenScaleFactor), int(15 * ScreenScaleFactor))
            cb = OptiCheckBox( self, wx.ID_ANY, label, pos=(xStart, yStart), size=size )
            if toolTipList and i < len(toolTipList):
                eachTooltip = toolTipList[i]
                tooltip = getToolTip(eachTooltip, cbName)
                cb.SetToolTipString(tooltip or eachTooltip)
            
            self.checkBoxes.append( cb )
            cb.SetValue(checked)
            if self.abilityMask is not None and (self.abilityMask & cBit) != True:
                cb.Enable(False)
            cb.Name = cbName
            cb._resourcelabel = eachLabel
            xStart += xInc
            yStart += yInc
            cBit = cBit << 1
            cnt += 1

    def GetValue(self):
        retVal = 0x0
        cBit = 0x1
        for cb in self.checkBoxes:
            if cb.GetBackgroundColour() == PINK:
                continue
            else:
                if cb.GetValue(): 
                    retVal |= cBit
            cBit = cBit << 1
        return retVal

    def SetValue(self, value):
        cBit = 0x1
        for cb in self.checkBoxes:
            if value is None:
                cb.SetValue(False)
                cb.SetBackgroundColour(PINK)        # show the not initialized state
            elif self.abilityMask is None or (self.abilityMask & cBit) != False:
                checked = (value & cBit) != False
                cb.SetValue(checked)
                cb.SetBackgroundColour(wx.NullColour)
            cBit = cBit << 1

    def Enable(self, *args, **kwargs):
        cBit = 0x1
        BasePanel.Enable(self, *args, **kwargs)
        for cb in self.checkBoxes:
            if self.abilityMask is None or (self.abilityMask & cBit) != False:
                cb.Enable(*args, **kwargs)
            else:
                cb.Enable(False)
            cBit = cBit << 1
            
    def SetAbilities(self, abilityMask=None):
        cBit = 0x1
        self.abilityMask = abilityMask
        for cb in self.checkBoxes:
            if self.abilityMask is None or (self.abilityMask & cBit) != False:
                cb.Enable(True)
                #cb.SetValue(True)
            else:
                cb.Enable(False)
                cb.SetValue(False)
            cBit = cBit << 1
    
    def GetAbilities(self):
        return self.abilityMask

    def Disable(self, *args, **kwargs):
        BasePanel.Disable(self, *args, **kwargs)
        for cb in self.checkBoxes:
            cb.Disable(*args, **kwargs)

    def GetNumberOfLabels(self):
        return len(self.checkBoxes)

    def SetItemLabel(self, labelNo=0, labelStr=""):
        if labelNo > -1 and labelNo < len(self.checkBoxes):
            self.checkBoxes[labelNo].SetLabel(labelStr)

    def GetItemName(self, labelNo=0):
        if labelNo > -1 and labelNo < len(self.checkBoxes):
            return self.checkBoxes[labelNo].Name

    def GetItemResourceLabel(self, labelNo=0):
        if labelNo > -1 and labelNo < len(self.checkBoxes):
            return self.checkBoxes[labelNo]._resourcelabel

    def GetItemLabel(self, labelNo=0):
        if labelNo > -1 and labelNo < len(self.checkBoxes):
            return self.checkBoxes[labelNo].GetLabel()

    def GetItemTooltip(self, labelNo=0):
        if labelNo > -1 and labelNo < len(self.checkBoxes):
            rts = self.checkBoxes[labelNo].GetToolTipString() 
            if rts:
                return rts
            else:
                return ""
        else:
            return ""

    def SetItemTooltip(self, labelNo=0, labelStr=""):
        if labelNo > -1 and labelNo < len(self.checkBoxes):
            self.checkBoxes[labelNo].SetToolTipString(labelStr)

    def SetItems(self, labelList=[]):
        for i, label in enumerate(labelList):
            self.SetItemLabel(i, label)


class OptiCheckBox(wx.CheckBox):
    '''Represents a CheckBox.'''
    # EVT_CHECKBOX  Sent when checkbox is clicked.
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, pos=wx.DefaultPosition,  # @ReservedAssignment
                  size=wx.DefaultSize, toolTipString=wx.EmptyString, style=0, 
                  validator=wx.DefaultValidator, name='OptiCheckBox', slaves=None, wrap=50):  # @ReservedAssignment @UnusedVariable
        self.resourcelabel = label
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)

        wx.CheckBox.__init__(self, parent, id, label, pos, size, style, validator, name)

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False

        self.slaveList = slaves or []     # list for widgets who's enabled state is dependend from this widget
        if len(self.slaveList) > 0:
            self.Bind(wx.EVT_CHECKBOX, self.OnChanged)

    def __del__(self):
        # destroy the popup window
        self.killPop()

    def GetResourceLabel(self):
        return getattr(self, "resourcelabel", "")

    def IsChecked(self, *args, **kwargs):
        if self.Is3State():
            return wx.CheckBox.Get3StateValue(self, *args, **kwargs)
        else:
            return wx.CheckBox.IsChecked(self, *args, **kwargs)

    def addSlave(self, slave):
        """
        A new method to put other widgets who depend on this widget in a list:
        the enabled/disabled state of the other widgets is then automatically set when this
        widget is checked or unchecked
        """
        if slave not in self.slaveList:
            oldlen = len(self.slaveList)
            self.slaveList.append(slave)
            if len(self.slaveList) > 0:
                if oldlen == 0:
                    self.Bind(wx.EVT_CHECKBOX, self.OnChanged)
            else:
                self.Unbind(wx.EVT_CHECKBOX)

    def setSlaves(self, slaves):
        """
        A new method to put other widgets who depend on this widget in a list:
        the enabled/disabled state of the other widgets is then automatically set when this
        widget is checked or unchecked
        """
        oldlen = len(self.slaveList)
        self.slaveList = slaves
        if len(self.slaveList) > 0:
            if oldlen == 0:
                self.Bind(wx.EVT_CHECKBOX, self.OnChanged)
        else:
            self.Unbind(wx.EVT_CHECKBOX)

    def getSlaves(self):
        return self.slaveList

    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)

        if wx.CheckBox.IsEnabled(self) == enable:
            return

        wx.CheckBox.Enable(self, enable)
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)

        if len(self.slaveList) > 0:
            if enable == True:
                self.Bind(wx.EVT_CHECKBOX, self.OnChanged)
            else:
                self.Unbind(wx.EVT_CHECKBOX)
            self._setSlavesState()

    def Disable(self):
        if wx.CheckBox.IsEnabled(self) == False:
            return

        wx.CheckBox.Disable(self)
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

        if len(self.slaveList) > 0:
            self.Unbind(wx.EVT_CHECKBOX)
            self._setSlavesState()

    def _setSlavesState(self):
        for slave in self.slaveList:    # enable/disable dependent widgets
            enable = self.IsEnabled() and self.IsChecked()
            if slave.startswith('NOT~'):        # REVERSING LOGICAL STATE
                slave = slave.replace('NOT~', '')
                enable = not enable
            wdg = wx.FindWindowByName(slave)
            if wdg is not None:
                wdg.Enable(enable)
                
    def OnChanged(self, event):
        self._setSlavesState()
        event.Skip()

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to pop up -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        self.shouldPOP = True
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no pop up requested -> do nothing
            return
        self.shouldPOP = False
        self.killPop()

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:
            self.popUpWin.Kill()
            self.popUpWin = None

    def SetValue(self, value):
        if value is None:
            value = False            
        if isinstance(value, str):
            value = False if value == "0" else True
            
        wx.CheckBox.SetValue(self, value)
        self.SetBackgroundColour(wx.NullColour)

        if len(self.slaveList) > 0:
            self._setSlavesState()

    def SetLabel(self, labelString):
        if labelString.find('\\n') >= 1:
            labelString = labelString.replace('\\n','\n')
            lines = labelString.split('\n')
            self.AdjustMultiLineSize(lines)
            wx.CheckBox.SetLabel(self, labelString)     # pass the translated string to baseclass-method
            wx.CheckBox.Refresh(self) # redraw needed for multiline
        else:
            wx.CheckBox.SetLabel(self, labelString)     # pass the translated string to baseclass-method

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #wx.CheckBox.SetToolTipString(self, toolTipString)   # pass the translated string to baseclass-method
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)


class OptiRadioBox(wx.RadioBox):
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, choices=[], majorDimension=0,  style=0, validator=wx.DefaultValidator, name='OptiRadioBox', toolTipString=wx.EmptyString):  # @ReservedAssignment
        self.resourcelabel = label
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)
        
        self.resourceLabels = []

        for i in range(len(choices)):
            self.resourceLabels.append( choices[i] )
            if hasattr(parent,"isMainPanel"):
                if parent.isMainPanel==True:
                    classnameofparent=type(parent).__name__
                    choices[i] = getText(choices[i], "_%s_%d" % (name, i),classnameofparent=classnameofparent)
                else:
                    choices[i] = getText(choices[i], "_%s_%d" % (name, i))
            else:
                choices[i] = getText(choices[i], "_%s_%d" % (name, i))

        wx.RadioBox.__init__(self, parent, id, label, pos, size, choices, majorDimension, style, validator, name)

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False

    def __del__(self):
        # destroy the popup window
        self.killPop()

    def GetResourceLabel(self):
        return getattr(self, "resourcelabel", "")

    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)

        wx.RadioBox.Enable(self, enable)
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)
    def Disable(self):
        wx.RadioBox.Disable(self)
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        self.shouldPOP = True
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        self.shouldPOP = False
        self.killPop()

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:
            self.popUpWin.Kill()
            self.popUpWin = None

    def GetValue(self):
        if self.GetBackgroundColour() == PINK:
            return None
        return wx.RadioBox.GetSelection(self)

    def SetValue(self, value):
        if value is None:
            wx.RadioBox.SetSelection(self, 0)
            self.SetBackgroundColour(PINK)        # show the not initialized state
        else:
            wx.RadioBox.SetSelection(self, value)
            self.SetBackgroundColour(wx.NullColour)

    def SetLabel(self, labelString):
        wx.RadioBox.SetLabel(self, labelString)

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #wx.RadioBox.SetToolTipString(self, toolTipString)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)
    
    def SetItems(self, labelList=[]):
        for i, label in enumerate(labelList):
            self.SetItemLabel(i, label)
            
    def GetItems(self):
        labelList = []
        for n in range(wx.RadioBox.GetCount(self)):
            item = wx.RadioBox.GetItemLabel(self, n)
            labelList.append(item)
        return labelList

    def GetNumberOfLabels(self):
        return wx.RadioBox.GetCount(self)

    def SetItemLabel(self, labelNo=0, labelStr=""):
        if labelNo > -1 and labelNo < wx.RadioBox.GetCount(self):
            wx.RadioBox.SetItemLabel(self, labelNo, labelStr)

    def GetItemLabel(self, labelNo=0):
        if labelNo > -1 and labelNo < wx.RadioBox.GetCount(self):
            return wx.RadioBox.GetItemLabel(self, labelNo)
    
    def GetItemResourceLabel(self, labelNo=0):
        if labelNo > -1 and labelNo < wx.RadioBox.GetCount(self):
            return self.resourceLabels[labelNo]

    def GetItemTooltip(self, labelNo=0):
        if labelNo > -1 and labelNo < wx.RadioBox.GetCount(self):
            tip = wx.RadioBox.GetItemToolTip(self, labelNo)
            if tip:
                return tip.GetTip() or ""
            else:
                return ""

    def SetItemTooltip(self, labelNo=0, labelStr=""):
        if labelNo > -1 and labelNo < wx.RadioBox.GetCount(self):
            wx.RadioBox.SetItemToolTip(self, labelNo, labelStr)
    
    def GetItemName(self, labelNo=0):
        if labelNo > -1 and labelNo < wx.RadioBox.GetCount(self):
            return "_%s_%d" % (self.Name, labelNo)
    
class OptiRadioButton(wx.RadioButton):
    '''Represents a RadioButton.'''
    # EVT_RADIOBUTTON  Sent when button is clicked.
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, pos=wx.DefaultPosition,  # @ReservedAssignment
                  size=wx.DefaultSize, style=0, validator=wx.DefaultValidator, name='OptiRadioButton', toolTipString=wx.EmptyString, slaves=None):  # @ReservedAssignment
        self.resourcelabel = label
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)

        wx.RadioButton.__init__(self, parent, id, label, pos, size, style, validator, name)

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False
        
        self.slaveList = slaves or []     # list for widgets who's enabled state is dependend from this widget
        if len(self.slaveList) > 0:
            self.Bind(wx.EVT_RADIOBUTTON, self.OnChanged)

    def __del__(self):
        # destroy the popup window
        self.killPop()

    def GetResourceLabel(self):
        return getattr(self, "resourcelabel", "")

    def IsChecked(self, *args, **kwargs):  # @UnusedVariable
        return wx.RadioButton.GetValue(self)

    def addSlave(self, slave):
        """
        A new method to put other widgets who depend on this widget in a list:
        the enabled/disabled state of the other widgets is then automatically set when this
        widget is checked or unchecked
        """
        if slave not in self.slaveList:
            oldlen = len(self.slaveList)
            self.slaveList.append(slave)
            if len(self.slaveList) > 0:
                if oldlen == 0:
                    self.Bind(wx.EVT_RADIOBUTTON, self.OnChanged)
            else:
                self.Unbind(wx.EVT_RADIOBUTTON)

    def setSlaves(self, slaves):
        """
        A new method to put other widgets who depend on this widget in a list:
        the enabled/disabled state of the other widgets is then automatically set when this
        widget is checked or unchecked
        """
        oldlen = len(self.slaveList)
        self.slaveList = slaves
        if len(self.slaveList) > 0:
            if oldlen == 0:
                self.Bind(wx.EVT_RADIOBUTTON, self.OnChanged)
        else:
            self.Unbind(wx.EVT_RADIOBUTTON)

    def getSlaves(self):
        return self.slaveList

    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)

        wx.RadioButton.Enable(self, enable)
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)

        if len(self.slaveList) > 0:
            if enable == True:
                self.Bind(wx.EVT_RADIOBUTTON, self.OnChanged)
            else:
                self.Unbind(wx.EVT_RADIOBUTTON)
            self._setSlavesState()

    def Disable(self):
        wx.RadioButton.Disable(self)
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

        if len(self.slaveList) > 0:
            self.Unbind(wx.EVT_RADIOBUTTON)
            self._setSlavesState()

    def _setSlavesState(self):
        for slave in self.slaveList:    # enable/disable dependend widgets
            enable = self.IsEnabled() and self.IsChecked()
            if slave.startswith('NOT~'):        # REVERSING LOGICAL STATE
                slave = slave.replace('NOT~', '')
                enable = not enable
            wdg = wx.FindWindowByName(slave)
            if wdg is not None:
                wdg.Enable(enable)

    def OnChanged(self, event):
        self._setSlavesState()
        event.Skip()

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        self.shouldPOP = True
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        self.shouldPOP = False
        self.killPop()

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:
            self.popUpWin.Kill()
            self.popUpWin = None

    def GetValue(self):
        if self.GetBackgroundColour() == PINK:
            return None
        return wx.RadioButton.GetValue(self)

    def SetValue(self, value):
        if value is None:
            wx.RadioButton.SetValue(self, False)
            self.SetBackgroundColour(PINK)        # show the not initialized state
        else:
            wx.RadioButton.SetValue(self, value)
            self.SetBackgroundColour(wx.NullColour)

        if len(self.slaveList) > 0:
            self._setSlavesState()

    def SetLabel(self, labelString):
        wx.RadioButton.SetLabel(self, labelString)

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #wx.RadioButton.SetToolTipString(self, toolTipString)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)
            

#+++++++++++++++++++++++++++++++++++++++++++++++++++++
# a class for toggle buttons:
#+++++++++++++++++++++++++++++++++++++++++++++++++++++
class NormalToggleButton(buttons.GenToggleButton):
    #We have to use buttons.GenToggleButton instead wx.ToggleButton, because we have to overload DrawLabel to implement a multiline functionality
    def __init__(self, parent, id=wx.ID_ANY, label='MyButton', pos=wx.DefaultPosition,  # @ReservedAssignment
                  size = wx.DefaultSize, style = wx.NO_BORDER, name='NormalButton', toolTipString=wx.EmptyString):  # @ReservedAssignment

        buttons.GenToggleButton.__init__(self, parent, id, label, pos, size, style, wx.DefaultValidator, name)

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False

    def DrawLabel(self, dc, width, height, dx=0, dy=0):  # @UnusedVariable
    #This is a advanced version of Drawlabel, it allowes multi line buttons
        dc.SetFont(self.GetFont())
        if self.IsEnabled():
            dc.SetTextForeground(self.GetForegroundColour())
        else:
            dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
        label = self.GetLabel()
        if not self.up:
            dx = dy = self.labelDelta  # @UnusedVariable

        labelList = label.split('\n')
        NoOfLines = len(labelList)
        td = 1    #Distance between lines
        listTh = [] #list of all Lineheights
        listTw = [] #list of all Linewidths

        for entry in labelList:
            entry = entry.strip()
            tw, th = dc.GetTextExtent(entry)
            listTh.append(th)
            listTw.append(tw)

        th = listTh[0] #Constant
        HeightAll = th * (NoOfLines) + td * (NoOfLines-1)
        FirstPoint = (height - HeightAll) // 2
        
        i = 0
        for entry in labelList:
            tw = listTw[i]
            x = (width-tw)//2+dx
            y = FirstPoint + ( th*i + td*i )
            dc.DrawText(entry, x, y)
            i = i + 1

        def __del__(self):
            # destroy the popup window
            self.killPop()

        def SetValue(self, value):
            pass

        def GetValue(self):
            return True

        def Enable(self, enable=True):
            if enable is None:
                return
            #Check if enable is type==list and return value for enable
            enable = ListEnableCheck(enable)

            wx.Button.Enable(self, enable)
            if self.GetToolTipString() != wx.EmptyString:
                if enable == True:
                    self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                    self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
                else:
                    self.Unbind(wx.EVT_ENTER_WINDOW)
                    self.Unbind(wx.EVT_LEAVE_WINDOW)
        def Disable(self):
            wx.Button.Disable(self)
            if self.GetToolTipString() != wx.EmptyString:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)

        def OnEnterWindow(self, event):  # @UnusedVariable
            if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
                return
            if self.GetTopLevelParent().IsActive() == False:
                return            
            self.shouldPOP = True
            logger.debug('-> EnterButton called')
            # create the popup window at the mouse position
    #        pos = wx.GetMousePosition()
            (w, h) = self.GetClientSize()
            pos = self.ClientToScreen((w / 2, h))    # it looks better with the button position
            wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

        def OnLeaveWindow(self, event):  # @UnusedVariable
            if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
                return
            self.shouldPOP = False
            logger.debug("%s%s" % ('LeaveButton called ', self.popUpWin))
            # destroy the popup window
            self.killPop()

        def showPop(self, pos):
            if self.popUpWin is None and self.shouldPOP:   # when we have already one, don't create another
                self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

        def killPop(self):
            if self.popUpWin is not None:  # only when we have one, we can kill it
                self.popUpWin.Kill()
                self.popUpWin = None

        def GetToolTipString(self):
            if hasattr(self, "toolTipString"):
                return self.toolTipString
            else:
                return wx.EmptyString

        def SetToolTipString(self, toolTipString):
            self.toolTipString = getToolTip(toolTipString, self.Name)
            if self.toolTipString != wx.EmptyString:
                #wx.Button.SetToolTipString(self, toolTipString)
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)


#+++++++++++++++++++++++++++++++++++++++++++++++++++++
# a class for very beautiful toggle buttons:
#+++++++++++++++++++++++++++++++++++++++++++++++++++++
class NiceToggleButton(buttons.GenBitmapToggleButton):
    def __init__(self, parent, id=wx.ID_ANY, buttonUpICO=None,  # @ReservedAssignment
                  buttonDownICO=None, disabledButtonICO=None, style = wx.NO_BORDER,
                   name='NiceToggleButton', toolTipString=wx.EmptyString, 
                   pos=wx.DefaultPosition, size=wx.DefaultSize, scale = False):  # @ReservedAssignment @UnusedVariable
        
        if buttonUpICO != None:
            if scale:
                bmp = getOpticamIcon2(buttonUpICO)
            else:
                bmp = getOpticamIcon(buttonUpICO)
        else:
            # c'tor saves current, The local setting of SW is special
            local = cad.LocalPy()
            local.set("C")
            # d'tor resets to saved!

            bmp = wx.ArtProvider.GetBitmap(wx.ART_MISSING_IMAGE, wx.ART_OTHER, (32, 32))
        buttons.GenBitmapToggleButton.__init__(self, parent, id, bmp, wx.DefaultPosition, size, style, wx.DefaultValidator, name) 
        #No wx.NullBitmap does not work here, use wx.missing-image as default

        # if buttonUpICO != None:
        #     self.SetBitmapLabel( getOpticamIcon(buttonUpICO) )

        if buttonDownICO != None:
            if scale:
                self.SetBitmapSelected( getOpticamIcon2(buttonDownICO) )
            else:
                self.SetBitmapSelected( getOpticamIcon(buttonDownICO) )
                
        if disabledButtonICO != None:
            if scale:
                self.SetBitmapDisabled( getOpticamIcon2(disabledButtonICO) )
            else:
                self.SetBitmapDisabled( getOpticamIcon(disabledButtonICO) )

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False
        self.scale = scale

    def __del__(self):
        # destroy the popup window
        self.killPop()

    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)

        buttons.GenBitmapToggleButton.Enable(self, enable)
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)

    def Disable(self):
        buttons.GenBitmapToggleButton.Disable(self)
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        self.shouldPOP = True
        logger.debug('-> EnterButton called')
        # create the popup window at the mouse position
#        pos = wx.GetMousePosition()
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))    # it looks better with the button position
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        self.shouldPOP = False
        logger.debug("%s%s" % ('LeaveButton called ', self.popUpWin))
        # destroy the popup window
        self.killPop()

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:   # when we have already one, don't create another
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:  # only when we have one, we can kill it
            self.popUpWin.Kill()
            self.popUpWin = None

    def setButtonUpICO(self, ico):
        if ico is not None:
            self.SetBitmapLabel( getOpticamIcon(ico) )

    def setButtonDownICO(self, ico):
        if ico is not None:
            self.SetBitmapSelected( getOpticamIcon(ico) )

    def setDisabledButtonICO(self, ico):
        if ico is not None:
            self.SetBitmapDisabled( getOpticamIcon(ico) )

    def setButtonHasFocusICO(self, ico):
        if ico is not None:
            self.SetBitmapFocus( getOpticamIcon(ico) )

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #wx.BitmapButton.SetToolTipString(self, toolTipString)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)
            
    def DrawLabel(self, dc, width, height, dx=0, dy=0):
        bmp = self.bmpLabel
        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:
            dx = dy = self.labelDelta
        hasMask = bmp.GetMask() != None
        dc.DrawBitmap(bmp, (width-bw)//2+dx, (height-bh)//2+dy, hasMask)


#+++++++++++++++++++++++++++++++++++++++++++++++++++++
# a class for very beautiful buttons:
#+++++++++++++++++++++++++++++++++++++++++++++++++++++
class NiceButton(wx.BitmapButton):
    '''Represents the nice button class (similiar to C++ part of opticam).'''
    # EVT_BUTTON    Sent when the button is clicked.
    #def __init__(self, parent, id=wx.ID_ANY, buttonUpICO=None, buttonDownICO=None, disabledButtonICO=None, style = wx.NO_BORDER, name='NiceButton', toolTipString=wx.EmptyString, pos=wx.DefaultPosition, size=wx.Size(ICON_X, ICON_Y)):  # @ReservedAssignment
    def __init__(self, parent, id=wx.ID_ANY, buttonUpICO=None,  # @ReservedAssignment
                  buttonDownICO=None, disabledButtonICO=None, style = wx.NO_BORDER, name='NiceButton',
                   toolTipString=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, bmpSize = (32, 32), scale = False, pressed=False):  # @ReservedAssignment @UnusedVariable

        wx.BitmapButton.__init__(self, parent, id, wx.NullBitmap, wx.DefaultPosition, size, style, wx.DefaultValidator, name)

        self.resourcelabel = wx.BitmapButton.GetLabel(self)
        wx.BitmapButton.SetLabel( self, getText(self.resourcelabel, name) )

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False
        self.customeSize = False
        self.scale = scale
        self.bmpSize = bmpSize
        # If we don't have the default value
        if self.bmpSize != (32, 32):
            self.customeSize = True

        self.setButtonUpICO(buttonUpICO)
        if pressed == False:
            self.setButtonDownICO(buttonDownICO)
        else:
            self.setButtonPressedICO(buttonDownICO)
        self.setDisabledButtonICO(disabledButtonICO)
        #self.setButtonHasFocusICO(buttonHasFocusICO)

    def __del__(self):
        # destroy the popup window
        self.killPop()

    def GetResourceLabel(self):
        return getattr(self, "resourcelabel", "")

    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)

        wx.BitmapButton.Enable(self, enable)
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)
    def Disable(self):
        wx.BitmapButton.Disable(self)
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:
            return            
        if self.GetTopLevelParent().IsActive() == False:
            return            
        self.shouldPOP = True
        logger.debug('%s.OnEnterWindow called (focus: %s)' % (self.__class__.__name__, self.HasFocus()))
        # create the popup window at the mouse position
        #pos = wx.GetMousePosition()
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))    # it looks better with the button position
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        self.shouldPOP = False
        #logger.debug("%s%s" % ('LeaveButton called ', self.popUpWin))
        logger.debug('%s.OnLeaveWindow called (focus: %s)' % (self.__class__.__name__, self.HasFocus()))
        # destroy the popup window
        self.killPop()

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:   # when we have already one, don't create another
            try:
                self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)
            except RuntimeError:
                pass

    def killPop(self):
        if self.popUpWin is not None:  # only when we have one, we can kill it
            self.popUpWin.Kill()
            self.popUpWin = None

    def setButtonUpICO(self, ico):
        if ico is not None:
            if self.scale:
                self.SetBitmapLabel( getOpticamIcon2(ico, self.bmpSize, self.customeSize) )          # Sets the bitmap label for the button.
            else:
                self.SetBitmapLabel( getOpticamIcon(ico) )          # Sets the bitmap label for the button.
                
    def setButtonDownICO(self, ico):
        if ico is not None:
            if self.scale:
                self.SetBitmapCurrent( getOpticamIcon2(ico, self.bmpSize, self.customeSize) )        # Sets the bitmap to be shown when the mouse is over the button.
            else:
                self.SetBitmapCurrent( getOpticamIcon(ico) )        # Sets the bitmap to be shown when the mouse is over the button.
                
    def setButtonPressedICO(self, ico):
        if ico is not None:
            if self.scale:
                self.SetBitmapPressed( getOpticamIcon2(ico, self.bmpSize, self.customeSize) )        # Sets the bitmap to be shown when the button is pressed.
            else:
                self.SetBitmapPressed( getOpticamIcon(ico) )        # Sets the bitmap to be shown when the button is pressed.

    def setDisabledButtonICO(self, ico):
        if ico is not None:
            if self.scale:
                self.SetBitmapDisabled( getOpticamIcon2(ico, self.bmpSize, self.customeSize) )       # Sets the bitmap for the disabled button appearance.
            else:
                self.SetBitmapDisabled( getOpticamIcon(ico) )       # Sets the bitmap for the disabled button appearance.

    def setButtonHasFocusICO(self, ico):
        if ico is not None:
            if self.scale:
                self.SetBitmapFocus( getOpticamIcon2(ico, self.bmpSize, self.customeSize) )          # Sets the bitmap for the button appearance when it has the keyboard focus.
            else:
                self.SetBitmapFocus( getOpticamIcon(ico) )          # Sets the bitmap for the button appearance when it has the keyboard focus.

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #wx.BitmapButton.SetToolTipString(self, toolTipString)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def SetValue(self, value):
        pass

    def GetValue(self):
        return True


class PopupWindow(wx.MiniFrame):
    '''Represents the miniwindow for the tooltip message (optional an image is allowed).'''
    def __init__(self, parent=None, pos=wx.DefaultPosition, text='ToolTip', image=None, backColour=INFOBK, holdTime=None):
        logger.info("%s%s" % (self.__class__.__name__ , ".__init__"))

        # wx.MiniFrame: a window without border and title bar.
        wx.MiniFrame.__init__(self, parent, wx.ID_ANY, pos=pos, style=wx.MINIMIZE_BOX)

        # paints the popup window light yellow
        # self.SetBackgroundColour(backColour) # not necessary, wx.StaticText() does it

        # get the image and convert it to bitmap
        if image is not None:
            bmp = getOpticamIcon(image)
            # get the width and height of the image
            (w, h) = bmp.GetSize()
            # place the image
            wx.StaticBitmap(self, wx.ID_ANY, bmp, (SMALLBORDER, SMALLBORDER), (w, h))

        # place the text
        """ RichText-Variante
        self.rtc = wx.richtext.RichTextCtrl(self, wx.ID_ANY, size=(100, 20))
        self.rtc.WriteText(' ' + text)
        self.rtc.SetFocus()
        """
        # Prevent NoneType Error for Argument 3 (text)
        if text == None:
            text = 'ToolTip'

        self.t = wx.StaticText(self, wx.ID_ANY, text, pos=(SMALLBORDER, SMALLBORDER), size=wx.DefaultSize, style=wx.ALIGN_LEFT, name="_popuptext")

        """ Font Auswahl
        pointSize = 10
        family = wx.FONTFAMILY_DEFAULT  # wx.FONTFAMILY_DECORATIVE
        style = wx.FONTSTYLE_NORMAL
        weight = wx.FONTWEIGHT_NORMAL # wx.FONTWEIGHT_LIGHT, wx.FONTWEIGHT_BOLD
        underline = False        # True
        t.SetFont(wx.Font(pointSize, family, style, weight, underline))
        """
        #self.t.SetFont(ICONTITLE_FONT)

        self.t.SetForegroundColour(INFOTEXT)
        self.t.SetBackgroundColour(backColour)

        self.Fit()      # size fits exatly around the content
        self.Show()     # make it visible

        if holdTime is not None:
            wx.FutureCall(holdTime, self.Kill)   # like a soap-bubble

    def setPopupText(self, text):
        self.t.SetLabel(text)
    def getPopupText(self):
        return self.t.GetLabel()
    def Kill(self):
        try:
            self.DestroyChildren()
            self.Destroy()
        except:
            pass
        

def ListEnableCheck(enable):
    if type(enable) == list:
        return enable[0]
    else:
        return enable

def ListValueCheck(Value):
    if type(Value) == list:
        return Value[1]
    else:
        return Value

class DoubleLabeledComboBox(BasePanel):
    '''Represents an label field with two choice-boxes.'''
    # Events: wx.EVT_CHOICE
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, choices1=[], choices2=[], toolTipString=wx.EmptyString, name='labeledComboBox', sizeChoice1=wx.DefaultSize, sizeChoice2=wx.DefaultSize, propChoice1=0, propChoice2=0):  # @ReservedAssignment @UnusedVariable
        self.resourcelabel = label
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)

        BasePanel.__init__(self, parent, id, pos, size, wx.TAB_TRAVERSAL|wx.NO_BORDER, name)
        if _DEBUG & 0x4:
            self.SetBackgroundColour(LIGHTYELLOW)

        self.hbox = wx.BoxSizer(wx.HORIZONTAL)
        self.SetSizer(self.hbox)

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False

        if label != wx.EmptyString:
            self.lbl = wx.StaticText(self, wx.ID_ANY, label, style=wx.ALIGN_LEFT, name="_" + name)
            self.hbox.Add(self.lbl, 0, wx.ALL|wx.CENTER, SMALLBORDER)
            self.hbox.Add(SPACER, 1, wx.ALL, SMALLBORDER)
            if _DEBUG & 0x4:
                self.lbl.SetBackgroundColour('YELLOW')

        self.cb1 = wx.Choice(self, wx.ID_ANY, choices=choices1, name="__" + name + "1", size=sizeChoice1)  # I think this widget looks better
        self.hbox.Add(self.cb1, propChoice1, wx.ALL, SMALLBORDER)

        self.cb2 = wx.Choice(self, wx.ID_ANY, choices=choices2, name="__" + name + "2", size=sizeChoice1)  # I think this widget looks better
        self.hbox.Add(self.cb2, propChoice2, wx.ALL, SMALLBORDER)

        self.hbox.Fit(self)

    def GetResourceLabel(self):
        return getattr(self, "resourcelabel", "")

    def GetValue(self):
        """
        Returns the index of the selected item or wx.NOT_FOUND if no item is selected.
        """
        if self.GetBackgroundColour() == PINK:
            return None
#        return self.cb.GetSelection()      # Returns the index of the selected item or wx.NOT_FOUND if no item is selected.
        return (self.cb1.GetStringSelection(), self.cb2.GetStringSelection()) # Returns the label of the selected item or an empty string if no item is selected.
    def SetValue(self, s):
        """
        Select the item with the specifed string
        """
        if s is None:
            self.cb1.SetStringSelection(wx.EmptyString)
            self.cb2.SetStringSelection(wx.EmptyString)
#            self.cb.SetBackgroundColour(PINK)        # show the not initialized state
            self.SetBackgroundColour(PINK)        # show the not initialized state
        else:
#            self.cb.SetSelection(index)
            #We have to append the string before we can set it
            s1 = str(s[0])
            s2 = str(s[1])
            if self.cb1.FindString(s1) == -1:
                self.cb1.Append(s1)
            if self.cb2.FindString(s2) == -1:
                self.cb2.Append(s2)

            self.cb1.SetStringSelection(s1)
            self.cb2.SetStringSelection(s2)

    def Append(self, s):
        """
        Adds the String to the choice list
        """
        if s is not None:
            self.cb1.Append(str(s[0]))
            self.cb2.Append(str(s[1]))

    def Clear(self):
        """
        Clears the Choice List
        """
        self.cb1.Clear()
        self.cb2.Clear()

    def GetItems(self):
        return (self.cb1.GetItems(), self.cb2.GetItems())

    def SetItems(self, items):
        self.cb1.SetItems(items[0])
        self.cb2.SetItems(items[1])

    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)

        if hasattr(self,"lbl"):
            self.lbl.Enable(enable)
        self.cb1.Enable(enable)
        self.cb2.Enable(enable)
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)
        BasePanel.Enable(self, enable)
    def Disable(self):
        if hasattr(self,"lbl"):
            self.lbl.Disable()
        self.cb1.Disable()
        self.cb2.Disable()
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)
        BasePanel.Disable(self)
    def Show(self, show):
        if hasattr(self,"lbl"):
            self.lbl.Show(show)
        self.cb1.Show(show)
        self.cb2.Show(show)

    def __del__(self):
        # destroy the popup window
        self.killPop()

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        self.shouldPOP = True
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        rect   = self.GetScreenRect()
        # in this case we get also a leave event when the mouse moves over the label or edit field
        # -> so we have to check whether we are really outside our panel
        if not rect.Contains(wx.GetMousePosition()):
            self.shouldPOP = False
            self.killPop()

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:
            self.popUpWin.Kill()
            self.popUpWin = None

    def GetLabel(self):
        if hasattr(self,"lbl"):
            return self.lbl.GetLabel()
        else:
            return wx.EmptyString

    def SetLabel(self, labelString):
        if hasattr(self,"lbl"):
            self.lbl.SetLabel(labelString)

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #BasePanel.SetToolTipString(self, toolTipString)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)


class NormalButton(wx.Button):
    '''Represents a normal button'''
    # EVT_BUTTON    Sent when the button is clicked.
    def __init__(self, parent, id=wx.ID_ANY, label='MyButton', pos=wx.DefaultPosition, size = wx.DefaultSize, style = wx.NO_BORDER, name='NormalButton', toolTipString=wx.EmptyString):  # @ReservedAssignment
        self.resourcelabel = label
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)

        wx.Button.__init__(self, parent, id, label, pos, size, style, wx.DefaultValidator, name)

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False

    def __del__(self):
        # destroy the popup window
        self.killPop()

    def GetResourceLabel(self):
        return getattr(self, "resourcelabel", "")

    def SetValue(self, value):
        pass

    def GetValue(self):
        return True

    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)

        wx.Button.Enable(self, enable)
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)
    def Disable(self):
        wx.Button.Disable(self)
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        self.shouldPOP = True
        logger.debug('-> EnterButton called')
        # create the popup window at the mouse position
#        pos = wx.GetMousePosition()
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))    # it looks better with the button position
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        self.shouldPOP = False
        logger.debug("%s%s" % ('LeaveButton called ', self.popUpWin))
        # destroy the popup window
        self.killPop()

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:   # when we have already one, don't create another
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:  # only when we have one, we can kill it
            self.popUpWin.Kill()
            self.popUpWin = None

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #wx.Button.SetToolTipString(self, toolTipString)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)


class TextField(wx.StaticText):
    '''Represents an alphanumerical input field.'''       # can be accessed via __doc__
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, style = 0, name='TextField', toolTipString=wx.EmptyString):  # @ReservedAssignment @UnusedVariable
        self.resourcelabel = label
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
                toolTipString= getToolTip(toolTipString, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
                toolTipString= getToolTip(toolTipString, name)
        else:
            label = getText(label, name)
            toolTipString= getToolTip(toolTipString, name)

        wx.StaticText.__init__(self, parent, id=id, label = label, pos = pos, size = size, style = style, name = name)

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False

    def GetResourceLabel(self):
        return getattr(self, "resourcelabel", "")

    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)

        wx.StaticText.Enable(self, enable)        # Important: call base-class method
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)
    def Disable(self):
        wx.StaticText.Disable(self)               # Important: call base-class method
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:  # only when we have one, we can kill it
            self.popUpWin.Kill()
            self.popUpWin = None

    # when the mouse enters the control -> the tooltip should be shown
    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        self.shouldPOP = True
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    # when the mouse leaves the control -> the tooltip should be killed
    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        self.shouldPOP = False
        self.killPop()

    def SetLabel(self, LabelStr):
        #self.SetLabel(LabelStr) #Whats that, a endless loop?
        LabelStr = str(LabelStr)
        wx.StaticText.SetLabel(self, LabelStr)

    def GetValue(self):
        value = wx.StaticText.GetLabel(self)
        #This a pain in the ass, cant pass a instance to a single variable of a this. So we first have to have the instance of this object.
        #value = (self.Parent.FindWindowByName(self.Name)).Enabled
        return value

    def SetValue(self, value):
        #Dont do this. The TransferToWindow will write True/False as label
        value = str(value)
        wx.StaticText.SetLabel(self, value) 
        #if type(value) == bool:
        #    wx.StaticText.Enable(self, value)

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #wx.TextCtrl.SetToolTipString(self, toolTipString)   # pass the translated string to baseclass-method
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)


class OptiLine(wx.StaticLine):
    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.LI_HORIZONTAL, name='_OPT_LINE'):  # @ReservedAssignment
        wx.StaticLine.__init__(self, parent, id, pos, size, style, name)


class OptiCheckListBox(wx.CheckListBox):
    '''A class for a simple custom check list box'''
    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, toolTipString=wx.EmptyString, ChoicesList = [], name="OptiCheckListBox"):  # @ReservedAssignment @UnusedVariable
        wx.CheckListBox.__init__( self, parent, wx.ID_ANY, pos, size, ChoicesList, style, name=name )
        
        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False   
        
    def __del__(self):
        # destroy the popup window
        self.killPop()    
        
    def ClearAllSelections(self):
        #There isn't a native method to deselect all entries. So here is one.
        for i in range(0, self.GetCount()):
            #There is only the method "Check(id, check=False)" to uncheck items
            self.Check(i, check=False)        
        
    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #wx.ListBox.SetToolTipString(self, toolTipString)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)        
        
    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:
            self.popUpWin.Kill()
            self.popUpWin = None    
            
    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        self.shouldPOP = True
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        rect   = self.GetScreenRect()
        if not rect.Contains(wx.GetMousePosition()):
            self.shouldPOP = False
            self.killPop()            

class OptiTreeCtrl(wx.TreeCtrl):
    def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.TR_DEFAULT_STYLE, validator=wx.DefaultValidator, name=wx.TreeCtrlNameStr, toolTipString=wx.EmptyString):  # @ReservedAssignment

        wx.TreeCtrl.__init__(self, parent, id, pos, size, style, validator, name) 

        self.SetToolTipString(toolTipString)
        self.popUpWin = None
        self.shouldPOP = False

    def __del__(self):
        # destroy the popup window
        self.killPop()

    def Enable(self, enable=True):
        if enable is None:
            return
        #Check if enable is type==list and return value for enable
        enable = ListEnableCheck(enable)

        wx.TreeCtrl.Enable(self, enable)
        if self.GetToolTipString() != wx.EmptyString:
            if enable == True:
                self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
                self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
            else:
                self.Unbind(wx.EVT_ENTER_WINDOW)
                self.Unbind(wx.EVT_LEAVE_WINDOW)
    def Disable(self):
        wx.TreeCtrl.Disable(self)
        if self.GetToolTipString() != wx.EmptyString:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

    def OnEnterWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == True:     # if there is already a request to popup -> do nothing
            return
        if self.GetTopLevelParent().IsActive() == False:
            return            
        self.shouldPOP = True
        (w, h) = self.GetClientSize()
        pos = self.ClientToScreen((w / 2, h))
        wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        self.shouldPOP = False
        self.killPop()

    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:
            self.popUpWin.Kill()
            self.popUpWin = None

    def GetValue(self):
        if self.GetBackgroundColour() == PINK:
            return None
        return wx.TreeCtrl.GetSelection(self)

    def SetValue(self, value):
        if value is None:
            wx.TreeCtrl.SetSelection(self, 0)
            self.SetBackgroundColour(PINK)        # show the not initialized state
        else:
            wx.TreeCtrl.SetSelection(self, value)
            self.SetBackgroundColour(wx.NullColour)

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def SetToolTipString(self, toolTipString):
        self.toolTipString = getToolTip(toolTipString, self.Name)
        if self.toolTipString != wx.EmptyString:
            #wx.RadioBox.SetToolTipString(self, toolTipString)
            self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        else:
            self.Unbind(wx.EVT_ENTER_WINDOW)
            self.Unbind(wx.EVT_LEAVE_WINDOW)

def getOpticamIcon(iconName, size=(32,32), alternateDir=None ):
    if alternateDir != None:
        iconsPath = os.path.join(alternateDir, iconName)
    else:
        iconsPath = os.path.join(iconsDir, iconName)
    #
    #size = wx.Size(int(size.width*ScreenScaleFactor), int(size.height*ScreenScaleFactor))
    bNewScale = False
    if bNewScale:
        size = (int(size[0]*ScreenScaleFactorNeeded), int(size[1]*ScreenScaleFactorNeeded))
    else:
        size = (int(size[0]*ScreenScaleFactor), int(size[1]*ScreenScaleFactor))

    # c'tor saves current, The local setting of SW is special
    local = cad.LocalPy()
    local.set("C")
    # d'tor resets to saved!
    
    if not os.path.exists(iconsPath):
        cad.DebLogA('getOpticamIcon cannot find : %s ' % iconsPath)
        logger.error("Can't find icon : %s" % iconsPath)
        return wx.ArtProvider.GetBitmap(wx.ART_MISSING_IMAGE, wx.ART_OTHER, size)
    
    #bmp = wx.Image(iconsPath, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
    bmp = wx.Image(iconsPath, wx.BITMAP_TYPE_ANY)
    # Why do we scale to 1.0?
    if bNewScale:
        width = int(bmp.GetWidth() * ScreenScaleFactorNeeded)
        height = int(bmp.GetHeight() * ScreenScaleFactorNeeded)
    else:
        width = int(bmp.GetWidth() * ScreenScaleFactor)
        height = int(bmp.GetHeight() * ScreenScaleFactor)
    bmp.Rescale(width, height, quality=wx.IMAGE_QUALITY_HIGH)       # IMAGE_QUALITY_NORMAL, IMAGE_QUALITY_HIGH, IMAGE_QUALITY_NEAREST
    bmp = bmp.ConvertToBitmap()
   
    if not bmp.IsOk():
        logger.error("Can't load icon : %s" % iconsPath)
        return wx.ArtProvider.GetBitmap(wx.ART_MISSING_IMAGE, wx.ART_OTHER, size)

    logger.info("Loaded icon : %s" % iconsPath)
    return bmp

# Used in toggle NiceToggleButtons!
def getOpticamIcon2(iconName, size=(32,32), customeSize=False, alternateDir=None ):
    if alternateDir != None:
        iconsPath = os.path.join(alternateDir, iconName)
    else:
        iconsPath = os.path.join(iconsDir, iconName)
    #
    #size = wx.Size(int(size.width*ScreenScaleFactor), int(size.height*ScreenScaleFactor))
    bNewScale = True
    if bNewScale:
        size = (int(size[0]*ScreenScaleFactorNeeded), int(size[1]*ScreenScaleFactorNeeded))
    else:
        size = (int(size[0]*ScreenScaleFactor), int(size[1]*ScreenScaleFactor))

    # c'tor saves current, The local setting of SW is special
    local = cad.LocalPy()
    local.set("C")
    # d'tor resets to saved!
    
    if not os.path.exists(iconsPath):
        cad.DebLogA('getOpticamIcon cannot find : %s ' % iconsPath)
        logger.error("Can't find icon : %s" % iconsPath)
        return wx.ArtProvider.GetBitmap(wx.ART_MISSING_IMAGE, wx.ART_OTHER, size)
    
    #bmp = wx.Image(iconsPath, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
    bmp = wx.Image(iconsPath, wx.BITMAP_TYPE_ANY)
    # Why do we scale to 1.0?
    if bNewScale:
        width = int(bmp.GetWidth() * ScreenScaleFactorNeeded)
        height = int(bmp.GetHeight() * ScreenScaleFactorNeeded)
    else:
        width = int(bmp.GetWidth() * ScreenScaleFactor)
        height = int(bmp.GetHeight() * ScreenScaleFactor)
    if customeSize:
        width = int(size[0]*ScreenScaleFactorNeeded)
        height = int(size[1]*ScreenScaleFactorNeeded)
        
    bmp.Rescale(width, height, quality=wx.IMAGE_QUALITY_HIGH)       # IMAGE_QUALITY_NORMAL, IMAGE_QUALITY_HIGH, IMAGE_QUALITY_NEAREST
    bmp = bmp.ConvertToBitmap()
   
    # 08/15/2025 That doesn't work as expected!
    # Why is there a difference between bmp and png and ico files?
    # 08/15/2025 That doesn't work as expected!
    if not bmp.IsOk():
        logger.error("Can't load icon : %s" % iconsPath)
        return wx.ArtProvider.GetBitmap(wx.ART_MISSING_IMAGE, wx.ART_OTHER, size)

    logger.info("Loaded icon : %s" % iconsPath)
    return bmp

#***************************************************************************************************************************************************************#
class CustomPopupControl(wx.Control):
    def __init__(self,*_args,**_kwargs):
        if 'value' in _kwargs:
            del _kwargs['value']
        style = _kwargs.get('style', 0)
        if (style & wx.BORDER_MASK) == 0:
            style |= wx.BORDER_NONE
            _kwargs['style'] = style
        wx.Control.__init__(self, *_args, **_kwargs)

        self.textCtrl = wx.TextCtrl(self, wx.ID_ANY, '', pos = (0,0), style=wx.TE_READONLY)
        self.bCtrl = pop.PopButton(self, wx.ID_ANY, style=wx.BORDER_NONE)
        self.pop = None
        self.content = None

        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.bCtrl.Bind(wx.EVT_BUTTON, self.OnButton, self.bCtrl)
        self.Bind(wx.EVT_SET_FOCUS, self.OnFocus)

        self.SetInitialSize(_kwargs.get('size', wx.DefaultSize))
        self.SendSizeEvent()


    def OnFocus(self,evt):
        # embedded control should get focus on TAB keypress
        self.textCtrl.SetFocus()
        evt.Skip()


    def OnSize(self, evt):
        # layout the child widgets
        w,h = self.GetClientSize()
        self.textCtrl.SetSize(0, 0, w - self.marginWidth - self.buttonWidth, h)
        self.bCtrl.SetSize(w - self.buttonWidth, 0, self.buttonWidth, h)

    def DoGetBestSize(self):
        # calculate the best size of the combined control based on the
        # needs of the child widgets.
        tbs = self.textCtrl.GetBestSize()
        return wx.Size(tbs.width + self.marginWidth + self.buttonWidth,
                       tbs.height)

    def OnButton(self, evt):
        if not self.pop:
            if self.content:
                self.pop = pop.PopupDialog(self, self.content)
                def NewDisplay(self):
                    pos = self.ctrl.ClientToScreen( (0,0) )
                    dSize = wx.GetDisplaySize()
                    selfSize = self.GetSize()
                    tcSize = self.ctrl.GetSize()
            
                    pos.x -= int((selfSize.width - tcSize.width) / 2)
                    if pos.x + selfSize.width > dSize.width:
                        pos.x = dSize.width - selfSize.width
            
                    pos.y += int(tcSize.height)
                    if pos.y + selfSize.height > dSize.height:
                        pos.y = dSize.height - selfSize.height
                    if pos.y < 0:
                        pos.y = 0
            
                    self.Move(pos)
            
                    self.ctrl.FormatContent()
            
                    self.ShowModal()
                self.pop.Display = partial(NewDisplay, self.pop)
                btn = evt.GetEventObject()
                sz =  btn.GetSize()
                x, y = evt.GetEventObject().ClientToScreen(evt.GetEventObject().GetPosition())
                self.pop.SetPosition((int(x + 10), int(y + sz[1])))
                del self.content
            else:
                print('No Content to pop')
        if self.pop:
            x, y = evt.GetEventObject().ClientToScreen(evt.GetEventObject().GetPosition())
            btn = evt.GetEventObject()
            sz =  btn.GetSize()
            self.pop.SetPosition((int(x + 10), int(y + sz[1])))
            self.pop.Display()

    def Enable(self, flag):
        wx.Control.Enable(self,flag)
        self.textCtrl.Enable(flag)
        self.bCtrl.Enable(flag)

    def SetPopupContent(self, content):
        if not self.pop:
            self.content = content
            self.content.Show(False)
        else:
            self.pop.SetContent(content)

    def FormatContent(self):
        pass

    def PopDown(self):
        if self.pop:
            self.pop.EndModal(1)

    def SetValue(self, value):
        self.textCtrl.SetValue(value)

    def GetValue(self):
        return self.textCtrl.GetValue()

    def SetFont(self, font):
        self.textCtrl.SetFont(font)

    def GetFont(self):
        return self.textCtrl.GetFont()
    
    def _get_buttonWidth(self):
        return 20
    buttonWidth = property(_get_buttonWidth)


#***************************************************************************************************************************************************************#
class CustomPopupDataControl(CustomPopupControl):
    def __init__(self,*_args,**_kwargs):
        self.marginWidth = 0
        self.callback = None
        self.selected_string = ''
        self.selected_formated_string = ''
        if 'choices' in _kwargs:
            del _kwargs['choices']
        CustomPopupControl.__init__(self, *_args, **_kwargs)
        self.win = wx.Window(self, -1, pos = (0,0) ,style = 0)
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.lb = wx.ListCtrl(self.win, -1, size=(300, 200), style=wx.LC_REPORT | wx.LC_SINGLE_SEL | wx.BORDER_NONE)
        self.lb.InsertColumn(0, "Sequece")
        self.lb.InsertColumn(1, "Ra [\u03BCm]", wx.LIST_FORMAT_RIGHT)
        self.lb.InsertColumn(2, "PR [\u03BCm]", wx.LIST_FORMAT_RIGHT)
        self.lb.SetColumnWidth(0, 184)
        self.lb.SetColumnWidth(1, 57)
        self.lb.SetColumnWidth(2, 57)
        sizer.Add(self.lb, 0, wx.ALL | wx.EXPAND, 0)
        self.win.SetSizerAndFit(sizer)
        self.SetPopupContent(self.win)
        self.lb.Bind(wx.EVT_RIGHT_DOWN, self.OnRightMouseClicked)
        self.lb.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftMouseDClicked)
        self.lb.Bind(wx.EVT_LEFT_UP, self.OnLeftMouseUpClicked)
        self.lb.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelected)
    
    def OnLeftMouseUpClicked(self, event):
        self.PopDown()
        
    def OnRightMouseClicked(self, event):
        self.PopDown()
        
    def OnLeftMouseDClicked(self, event):
        self.textCtrl.Clear()
        selected_value = self.lb.GetItemText(event.Index)
        selected_value_1 = self.lb.GetItemText(event.Index, 1)
        selected_value_2 = self.lb.GetItemText(event.Index, 2)
        selected_data = self.lb.GetItemData(event.Index)
        self.selected_string = selected_value + '|' + selected_value_1 + '|' + selected_value_2 + '| ' + str(selected_data)
        formated_selected_value = self.FormatSelectString(selected_value)
        self.selected_formated_string = formated_selected_value
        self.textCtrl.SetValue(formated_selected_value)
        self.PopDown()
        if self.callback != None:
            self.callback()
        
    def OnSelected(self, event):
        self.textCtrl.Clear()
        selected_value = self.lb.GetItemText(event.Index)
        selected_value_1 = self.lb.GetItemText(event.Index, 1)
        selected_value_2 = self.lb.GetItemText(event.Index, 2)
        selected_data = self.lb.GetItemData(event.Index)
        self.selected_string = selected_value + '|' + selected_value_1 + '|' + selected_value_2 + '| ' + str(selected_data)
        formated_selected_value = self.FormatSelectString(selected_value)
        self.selected_formated_string = formated_selected_value
        self.textCtrl.SetValue(formated_selected_value)
        self.PopDown()
        if self.callback != None:
            self.callback()
    
    def FormatSelectString(self, input_text):
        fomated_selection = input_text.split('|')[0]
        fomated_selection = fomated_selection.rstrip()
        return input_text
    
    def GetSelection(self):
        return self.selected_string
    
    def GetFormatSelection(self):
        return self.selected_formated_string
    
    def GetStringSelection(self):
        return self.selected_formated_string
    
    def SetItems(self, items):
        try:
            for ls in items:
                format_selection_01 = ("{0}".format(ls[0]))
                format_selection_02 = ("{0:.3f}".format(eval(ls[1])))
                format_selection_03 = ("{0:.3f}".format(eval(ls[2])))
                index = self.lb.InsertItem(self.lb.GetItemCount(), format_selection_01)
                self.lb.SetItem(index, 1, format_selection_02)
                self.lb.SetItem(index, 2, format_selection_03)
                self.lb.SetItemData(index, ls[3])
            return True
        except Exception as e:  # @UnusedVariable
            return False
    
    def Clear(self):
        self.selected_string = ''
        self.selected_formated_string = ''
        self.textCtrl.Clear()
        return self.lb.DeleteAllItems()
        

class LabeledCustomPopupDataControl(_LabeledBaseBox):
    '''Represents a label field with a choice-box.'''
    # Events: wx.EVT_COMBOBOX
    def __init__(self, parent, id=wx.ID_ANY, label=wx.EmptyString, pos=wx.DefaultPosition, size=wx.DefaultSize, choices=None, toolTipString=wx.EmptyString, name='labeledComboBox', sizeChoice=wx.DefaultSize, propChoice=0, minSizeChoice=(100, -1), prettyNamesDict=None):  # @ReservedAssignment

        _LabeledBaseBox.__init__(self, parent, id=id, label=label, pos=pos, size=size, toolTipString=toolTipString,
                                name=name, propChoice=propChoice, prettyNamesDict=prettyNamesDict)

        self.cb = CustomPopupDataControl(self, -1, pos = (0, 0), style=wx.BORDER_SUNKEN)
        if minSizeChoice != None:
            self.cb.SetInitialSize(minSizeChoice)
            if propChoice > 0:
                proportion = int(propChoice * 100)
            else: 
                proportion = 0
        self.hbox.Add(self.cb, proportion, wx.ALL, SMALLBORDER)

        self.SetSizerAndFit(self.hbox)
        
    def SetItems(self, items):
        self.cb.SetItems(items)
    
    def GetSelection(self):
        return self.cb.GetSelection()
    
    def GetFormatSelection(self):
        return self.cb.GetFormatSelection()
    
    def Clear(self):
        return self.cb.Clear()
    
    def set_callback(self, value):
        self.cb.callback = value
        
    callback = property(None, set_callback)


#***************************************************************************************************************************************************************#
class PopupWinAsTooltipForStandardTechDataGrid(wx.PopupWindow):
    """
    Since we can't specify a tooltip for each row for wx.grid. It can only have one tooltip, 
    so use popwindows to display the tooltip's message.
    Adds a bit of text and mouse movement to the wx.PopupWindow
    """
    def __init__(self, parent, style, header="", message=""):
        wx.PopupWindow.__init__(self, parent, style)
        pnl = self.pnl = wx.Panel(self)
        pnl.SetBackgroundColour((255, 255, 225, 0))
        
        vSizer = wx.BoxSizer(wx.VERTICAL)
        
        self.tcHeader = wx.TextCtrl(self.pnl, -1, header, size=(-1, -1), style = wx.TE_RICH2)
        self.tcHeader.SetFont(wx.Font(11, wx.SCRIPT, wx.NORMAL, wx.BOLD, False))
        self.tcHeader.SetBackgroundColour((255, 255, 225, 0))
        vSizer.Add(self.tcHeader, 0, wx.EXPAND | wx.ALL, SMALLBORDER)
        self.tcMsg = wx.TextCtrl(self.pnl, -1, message, size=(400, 200), style = wx.TE_MULTILINE | wx.TE_NO_VSCROLL | wx.TE_RICH)
        self.tcMsg.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, True))
        self.tcMsg.SetBackgroundColour((255, 255, 225, 0))
        vSizer.Add(self.tcMsg, 1, wx.EXPAND | wx.ALL, SMALLBORDER)
        
        self.pnl.SetSizerAndFit(vSizer)
        
        self.Fit()

        pnl.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown)
        pnl.Bind(wx.EVT_MOTION, self.OnMouseMotion)
        pnl.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp)
        pnl.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
        
        self.tcHeader.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown)
        self.tcHeader.Bind(wx.EVT_MOTION, self.OnMouseMotion)
        self.tcHeader.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp)
        self.tcHeader.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
        
        self.tcMsg.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown)
        self.tcMsg.Bind(wx.EVT_MOTION, self.OnMouseMotion)
        self.tcMsg.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp)
        self.tcMsg.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)

        #wx.CallAfter(self.Refresh)
        
    def __del__(self):
        """
        Make sure that any possible catched capture of mouse will be freed in d'tor
        try this solution bacause we have a freezing problem in some situations (Joerg and I at 07. Nov. 2019)
        """
        if getattr(self, 'pnl', None) is not None:
            if self.pnl.HasCapture():
                self.pnl.ReleaseMouse()
        wx.PopupWindow.__del__(self)     # base class
    
    def SetMessage(self, message=""):
        self.tcMsg.SetValue(message)
        self.Fit()
    
    def OnMouseLeftDown(self, evt):
        self.Refresh()
        self.ldPos = evt.GetEventObject().ClientToScreen(evt.GetPosition())
        self.wPos = self.ClientToScreen((0,0))
        self.pnl.CaptureMouse()

    def OnMouseMotion(self, evt):
        if evt.Dragging() and evt.LeftIsDown():
            dPos = evt.GetEventObject().ClientToScreen(evt.GetPosition())
            nPos = (self.wPos.x + (dPos.x - self.ldPos.x),
                    self.wPos.y + (dPos.y - self.ldPos.y))
            self.Move(nPos)

    def OnMouseLeftUp(self, evt):  # @UnusedVariable
        if self.pnl.HasCapture():
            self.pnl.ReleaseMouse()

    def OnRightUp(self, evt):  # @UnusedVariable
        self.Show(False)
        #self.Destroy()
        
        
class StaticBox(wx.StaticBox):
    def __init__(self, parent, id=wx.ID_ANY, label='', name='staticbox'):  # @ReservedAssignment
        self.resourcelabel = label
        #measurecycle widgets are treated differently
        if hasattr(parent,"isMainPanel"):
            if parent.isMainPanel==True:
                classnameofparent=type(parent).__name__
                label = getText(label, name, classnameofparent=classnameofparent)
            else:
                label = getText(label, name)
        else:
            label = getText(label, name)

        wx.StaticBox.__init__(self, parent, id, label)
        self.Name = name

    def GetResourceLabel(self):
        return getattr(self, "resourcelabel", "")
    
    def GetName(self):
        return self.Name

#***************************************************************************************************************************************************************#
class StandardTechDataGrid(wx.grid.Grid):
    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, name='wxGrid', DialogObj=None,  # @ReservedAssignment
                 SingleSelectionMode=True, LabelRowColmnSelectionMode=3, SetHighlightMode=False, MinColumnWidth=80, SortingEnabled=True):  # @UnusedVariable
        #Init for or Tech Data Grid
        #wxGrid (wxWindow *parent, wxWindowID id, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxWANTS_CHARS, const wxString &name=wxGridNameStr)
        wx.grid.Grid.__init__( self, parent, id, pos, size, style, name )
        
        #DialgObject for later use
        self.DialogObj = DialogObj
        
        #Single Selection Mode
        self.singleSelectionMode = None
        self.SetSingleSelectionMode(SingleSelectionMode) #Standard is single selection = True
        
        #Label Row or Colmn Click Mode
        #Modes: 0=Nothing, 1=Both, 2=OnlyColumn, 3=OnlyRow
        self.LabelRowColmnSelectionMode = LabelRowColmnSelectionMode #Standard Mode = 3, only Rows are selectable
        
        #Enable/Disable Highlight
        self.HighlightMode = None
        self.HighlightPenWidth = self.GetCellHighlightPenWidth() #For Buffering line width
        self.HighlightROPenWidth = self.GetCellHighlightROPenWidth() #For Buffering line width
        self.SetHighlightMode(SetHighlightMode) #standard is no highlight
        
        #Min Column Size
        self.MinColumnWidth = 80
        self.MinRowWidth = 19
        
        #Sorting Stuff
        if SortingEnabled == True:
            self.UseNativeColHeader(True) #Needed for show Sorting icon
            #self.SetUseNativeColLabels(True)
        self.Bind(wx.grid.EVT_GRID_COL_SORT, self.EvtColumnSort)
        
        #due to the fact we dont have access to the GetRowMinimalHeight and GetColMinimalWidth Method (these are Protected Member Functions and not exported in grid.py)
        #We have to store the Minimal Heights of Rows and Minimal Width of Columns for ourself
        self.ListMinColumnWidth = []
        self.ListMinRowHeight = []
        self.Bind(wx.grid.EVT_GRID_COL_MOVE, self.EvtColumMove)
        
        self.ShowDetailsInTooltip = False
        #Custom Events

        # TEST (rename automatically created child widgets with leading underscore to prevent being displayed in translation dialoog)
        for wdg in self.GetChildren():
            name = wdg.GetName()
            if not name.startswith('_'):
                wdg.SetName('_' + name)      
        # TEST TEST TEST  

    def CreateGrid(self, numRows, numCols ):
        #Intercept create grid
        wx.grid.Grid.CreateGrid(self, numRows, numCols)
        
        #Fill our own lists with Width/ranges
        self.ListMinRowHeight = []
        for iRow in range(0, numRows):  # @UnusedVariable
            self.ListMinRowHeight.append(self.MinColumnWidth)
        self.ListMinColumnWidth = []    
        for iColumn in range(0, numCols):  # @UnusedVariable
            self.ListMinColumnWidth.append(self.MinRowWidth) 
            
    def AppendCols (self, numCols=1,updateLabels=True):
        #Intercept AppendCols
        wx.grid.Grid.AppendCols(self, numCols, updateLabels)
        
        #Extend our List
        for iColumn in range(0, numCols):  # @UnusedVariable
            self.ListMinColumnWidth.append(self.MinColumnWidth)         
    
    def AppendRows (self, numRows=1,updateLabels=True):
        #Intercept AppendRows
        wx.grid.Grid.AppendRows(self, numRows, updateLabels)
        
        #Extend our List
        for iColumn in range(0, numRows):  # @UnusedVariable
            self.ListMinRowHeight.append(self.MinRowWidth)  
    
    def DeleteCols (self, pos=0, numCols=1, updateLabels=True):
        #Intercept DeleteCols
        wx.grid.Grid.DeleteCols(self, pos,numCols, updateLabels)
        
        #Remove the items from our list
        for iColumn in range(0, numCols):  # @UnusedVariable
            self.ListMinColumnWidth.pop(pos) #delete the item at pos for numCols-times 
    
    def DeleteRows (self, pos=0, numRows=1, updateLabels=True):
        #Intercept DeleteRows
        wx.grid.Grid.DeleteRows(self, pos, numRows, updateLabels)
        
        #Remove the items from our list
        for iRow in range(0, numRows):  # @UnusedVariable
            self.ListMinRowHeight.pop(pos) #delete the item at pos for numCols-times 
    
    def InsertCols (self, pos=0, numCols=1, updateLabels=True):
        #Intercept InsertCols
        wx.grid.Grid.InsertCols(self, pos,numCols, updateLabels)
        
        #Insert the items in our list
        iCounter=0
        for iColumn in range(0, numCols):  # @UnusedVariable
            self.ListMinColumnWidth.insert(pos+iCounter, self.MinColumnWidth) #delete the item at pos for numCols-times 
            iCounter=iCounter+1
    
    def InsertRows (self, pos=0, numRows=1, updateLabels=True):
        #Intercept InsertRows
        wx.grid.Grid.InsertCols(self, pos,numRows, updateLabels)
        
        #Insert the items in our list
        iCounter=0
        for iColumn in range(0, numRows):  # @UnusedVariable
            self.ListMinRowHeight.insert(pos+iCounter, self.MinRowWidth) #delete the item at pos for numRows-times 
            iCounter=iCounter+1
    
    def EvtColumMove (self, event):
        #Intercept EvtColumMove
        #todo: move items ins list when moving columns
        
        #keep going
        event.Skip()
        
    def EvtColumnSort(self, event):
        #Intercept EvtColumSort
        #Event hanlder for Sorting event
        #We have to do this by us, because the normal grid dont implement sorting by itself
        #Maybe we will have to do something because of our minimalwidth stuff
        
        #Column Clicked
        Ascending = True
        Column = event.GetCol()
        SortAlreadySet = self.IsSortingBy(Column)
        
        #if Column ist already sorting -> reverse the current order
        if SortAlreadySet == True:
            if self.IsSortOrderAscending() == True:
                Ascending = False
            else:
                Ascending = True
                
        #Do the sorting
        ret = self.SortColumn(Column, Ascending)                
                
        #Set Column Sort order
        if ret == True:
            self.SetSortingColumn(Column, Ascending)
            # 
            grid_parent = self.GetParent()
            #
            if isinstance(self.GetParent(), BasePanel):
                grid_parent = grid_parent.GetParent()
            # 
            if hasattr(grid_parent, 'grid_columns_uid_sort'):
                grid_parent.grid_columns_uid_sort = Column
            if hasattr(grid_parent, 'grid_columns_uid_asc'):
                grid_parent.grid_columns_uid_asc = Ascending
        
        event.Skip()
        
    def SortColumn(self, colId, Ascending=True):
        #sort the grid data based on the column indexed by col
        try:
            NewData = []
            _data = [] #temp object for sorting
            
            #data = [ ('RowIdX'), {'ColIdY':ValueRowXColY, ... }, ... ]
            #_data = [ValueRowXCoY, &self.data-Object]
            
            #Fill our OldData List with current grid information
            OldData = self.GetDataFromGrid()
            
            #Create the temp list and sort it
            for row in OldData:
                currRowId, currRowValues = row  # @UnusedVariable
                _data.append((currRowValues.get(colId, None), row))
    
            #Sorting, first value decides which method we use
            
            if ConvertCheckFloat(_data[0][0]) == True:
                _data=sorted(_data, key=lambda i: (float(i[0])))
            elif ConvertCheckInt(_data[0][0]) == True:
                _data=sorted(_data, key=lambda i: (int(i[0]))) #custom search
            elif ConvertCheckStr(_data[0][0]) == True:
                _data=sorted(_data, key=lambda i: (str(i[0])))
            elif ConvertCheckStr(_data[0][0]) == True:
                _data=sorted(_data, key=lambda i: (str(i[0])))
            else:
                _data.sort()
            
            if Ascending == False:
                _data.reverse()
    
            #Get the sorted data back into data-list
            for sortvalue, row in _data:  # @UnusedVariable
                NewData.append(row)  
                
            #Show the NewData on Screen
            self.ShowDataOnGrid(NewData)   
            
            return True               
        except:
            return False                
                
    def GetDataFromGrid(self):
        #Create a List with all grid data
        #Data = [ ('RowIdX'), {'ColIdY':ValueRowXColY, ... }, ... ]
        Data = []
        for iRow in range(0, self.GetNumberRows()):       
            colDict = {}
            for iColmn in range(0, self.GetNumberCols()):               
                value = self.GetCellValue(iRow, iColmn)
                colDict[iColmn] = value
            Data.append((iRow, colDict))  
        return Data     
    
    def ShowDataOnGrid(self, Data=[]):
        #Show the given data list on grid
        #Data = [ ('RowIdX'), {'ColIdY':ValueRowXColY, ... }, ... ]
        self.BeginBatch() #avoid flickering
        
        self.ClearGrid()
        rowCounter = 0
        for RowEntry in Data:       
            rowIdOld, rowValues = RowEntry  # @UnusedVariable
            for colId in rowValues: 
                cellValue = rowValues[colId]
                self.SetCellValue(rowCounter, colId, cellValue)  
            rowCounter = rowCounter + 1
            
        self.EndBatch() #avoid flickering
        
    def ResetGrid(self):
        #An enhanced Cleargrid method
        
        #Do this at start
        self.BeginBatch()
        
        #Clear Grid values
        self.ClearGrid()
        
        #Delete all rows
        NoOfRows = self.GetNumberRows ()
        if NoOfRows > 0:
            self.DeleteRows(0, NoOfRows) #delete all row from begnning
            
        #Remove Sorting if set
        self.UnsetSortingColumn()
        
        #Do this at end
        self.EndBatch()
        
    def SetHighlightMode(self, enable):
        #Mehtod to disable/enable the highlighing of cells
        if self.HighlightMode == enable:
            #Mode already set
            return    
        
        if enable == True:
            self.HighlightMode = True
            self.SetCellHighlightPenWidth(self.HighlightPenWidth)
            self.SetCellHighlightROPenWidth(self.HighlightROPenWidth)              
        else:
            self.HighlightMode = False
            self.SetCellHighlightPenWidth(0)
            self.SetCellHighlightROPenWidth(0)                        
        
    def SetSingleSelectionMode(self, enable):
        #Custom Selection Mode
        if self.singleSelectionMode == enable:
            #Mode already set
            return
        if enable:
            self.Bind(wx.grid.EVT_GRID_RANGE_SELECT, self.OnGridRangeSelect)
            self.Bind(wx.grid.EVT_GRID_SELECT_CELL, self.OnGridSelectCell)
            self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnGridCellLeftClick)
            self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.OnGridCellLeftDoubleClick)
            #self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.DisableCtrlMaiusHandler)
            self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.OnGridLabelLeftClick)
            self.GetGridWindow().Bind(wx.EVT_MOTION, self.DisableDraggingHandler)
            self.singleSelectionMode = True
        else:
            self.Unbind(wx.grid.EVT_GRID_RANGE_SELECT, self.OnGridRangeSelect)
            self.Unbind(wx.grid.EVT_GRID_SELECT_CELL, self.OnGridSelectCell)
            self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnGridCellLeftClick)
            self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.OnGridCellLeftDoubleClick)
            #self.Unbind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.DisableCtrlMaiusHandler)
            self.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.OnGridLabelLeftClick)
            self.GetGridWindow().Unbind(wx.EVT_MOTION, self.DisableDraggingHandler)
            self.singleSelectionMode = False         
        
    def OnGridRangeSelect(self, event):
        #Event Handler for selecting a range
        if (event.Selecting() and (event.GetTopRow() != event.GetBottomRow())):
            #Range disabling
            event.StopPropagation()
            event.Veto()
        
    def OnGridSelectCell(self, event):
        #Event Handler after filling stuff in
        #Is calles after filling information into the grid, with this we auto select the first row
        self.SelectRow(event.GetRow())
    '''    
    def DisableCtrlMaiusHandler(self, event):
        #Event Handler for selecting a cell
        if (event.ControlDown() or event.ShiftDown()):
            event.Veto()
        else:
            event.Skip()
    '''      
    def DisableDraggingHandler(self, event):
        #Event Handler
        if event.Dragging():
            event.Skip(False)

    def OnGridLabelLeftClick( self, event ):
        #Event Handler for selecting a cell
        #If a row is clicked, event.GetCol() will be -1 and vice versa
        #self.LabelRowColmnSelectionMode = True #Modes: 0=Nothing, 1=Both, 2=OnlyColumn, 3=OnlyRow
        if hasattr(self, "tipballoon"):
            self.tipballoon.Hide()
        if event.GetRow() == -1 and event.GetCol() >= 0:
            #A column was clicked
            if self.LabelRowColmnSelectionMode == 1 or self.LabelRowColmnSelectionMode == 2:
                #Clicking/selection is allowed
                event.Skip()           
        elif event.GetRow() >= 0 and event.GetCol() == -1:
            #A Row was clicked
            if self.LabelRowColmnSelectionMode == 1 or self.LabelRowColmnSelectionMode == 3:
                #Clicking/selection is allowed
                event.Skip()            
        else:
            #Both are -1, clickd on Left/Top Label field
            pass
        
    def OnGridCellLeftClick( self, event ):
        """
        Used to handle mouse left click events, including three cases, left click, Shift + left click, Ctrl + left click.
        """
        #Event Handler for Custom Event, EVT_GRID_CELL_LEFT_CLICK
        #Get Current row no
        if hasattr(self, "tipballoon"):
            self.tipballoon.Hide()
        CurrentRow = event.GetRow()
        state = wx.GetMouseState()
        if state.ControlDown():
            #CurrentCol = event.GetCol()
            #self.SetGridCursor(CurrentRow, CurrentCol)
            self.SelectRow(CurrentRow, True)
            #Enable the Ok and Select Button:
            if CheckIfMethodOK(self.DialogObj, 'EnableOkSelect'):
                self.DialogObj.EnableOkSelect()
            else:
                pass
            # plase not call event.Skip in this if block
        elif state.ShiftDown():
            #CurrentCol = event.GetCol()
            lastSelectLines = self.GetSelectedRows()
            if len(lastSelectLines) <= 1:
                if len(lastSelectLines) == 0:
                    #Clear selection
                    self.ClearSelection()
                    #Select current row
                    self.SelectRow(CurrentRow)
                else:
                    if CurrentRow > lastSelectLines[0]:
                        for iRow in range(lastSelectLines[0] + 1, CurrentRow + 1):
                            self.SelectRow(iRow, True)
                    elif CurrentRow < lastSelectLines[0]:
                        for iRow in range(CurrentRow, lastSelectLines[0]):
                            self.SelectRow(iRow, True)
                    else:
                        pass
            else:
                #Clear selection
                self.ClearSelection()
                #Select current row
                self.SelectRow(CurrentRow)
            #self.DeselectCell(CurrentRow, CurrentCol)
            #Enable the Ok and Select Button:
            if CheckIfMethodOK(self.DialogObj, 'EnableOkSelect'):
                self.DialogObj.EnableOkSelect()
            else:
                pass
            # plase not call event.Skip in this if block
        else:
            #Clear selection
            self.ClearSelection()
            #Get Current row no
            CurrentRow = event.GetRow()
            #Select current row
            self.SelectRow(CurrentRow)
            
            #Enable the Ok and Select Button:
            if CheckIfMethodOK(self.DialogObj, 'EnableOkSelect'):
                self.DialogObj.EnableOkSelect()
                
            #If we have a details panel, we want to update this
            if hasattr(self.Parent.Parent, 'DetailsPanel'):
                DetailsPanel = self.Parent.Parent.DetailsPanel
                if CheckIfMethodOK(DetailsPanel, 'UpdateGrid'):
                    DetailsPanel.UpdateGrid(CurrentRow)
                    
            if CheckIfMethodOK(self.DialogObj, 'CreateTooltipLines') and self.ShowDetailsInTooltip == True:
                strTooltipLines = self.DialogObj.CreateTooltipLines(iCurrentRow=CurrentRow)
                if hasattr(self, "tipballoon"):
                    # Set The Target
                    self.tipballoon.SetMessage(strTooltipLines)
                    pos = list(self.ClientToScreen((0,0)))
                    pos2 = list(event.GetPosition())
                    sz =  self.GetRowLabelSize()
                    self.tipballoon.Position(tuple([sum(x) for x in zip(pos, pos2)]), (0, sz))
                    self.tipballoon.Show(True)
                else:        
                    self.tipballoon = PopupWinAsTooltipForStandardTechDataGrid(self, wx.SIMPLE_BORDER, "Details", strTooltipLines)
                    #win = TestPopupWithListbox(self, wx.SIMPLE_BORDER, self.log)
            
                    # Show the popup right below or above the button
                    # depending on available screen space...
                    pos = list(self.ClientToScreen((0,0)))
                    pos2 = list(event.GetPosition())
                    sz =  self.GetRowLabelSize()
                    self.tipballoon.Position(tuple([sum(x) for x in zip(pos, pos2)]), (0, sz))
                    self.tipballoon.Show(True)
            #Call the custom event at end
            event.Skip()
        
    def OnGridCellLeftDoubleClick(self, event):
        #Event Handler for Custom Event, EVT_GRID_CELL_LEFT_DCLICK
        if hasattr(self, "tipballoon"):
            self.tipballoon.Hide()
        listSelectedRows = self.GetSelectedRows()
        if len(listSelectedRows) == 1:
            if event.GetRow() in listSelectedRows:
                if CheckIfMethodOK(self.DialogObj, 'OnOK'):
                    self.DialogObj.OnOK(event)
                    event.Skip()
                else:
                    event.Skip()
            else:
                event.Skip()
        else:
            event.Skip()
    
    '''    
    def SelectRow(self, CurrentRow, addtoSelected=False ):
        #Handler for Select Row, Overwrite if you want
        wx.grid.Grid.SelectRow(self, CurrentRow, addtoSelected)
        
    def SelectCol(self, CurrentCol, addtoSelected=False ):
        #Handler for Select Column, Overwrite if you want
        if False:
            wx.grid.Grid.SelectCol(self, CurrentCol, addtoSelected)
        
    def SelectBlock(self, TopLeft, BottomRight, addtoSelected=False ):
        #Handler for Select Column, Overwrite if you want
        if False:
            wx.grid.Grid.SelectBlock(self, TopLeft, BottomRight, addtoSelected)
    '''
    def SetColSize(self, iColumn, width, ignoreMin=False):
        #Custom SetColSize Method, expanded with Minimal Column width check
        if ignoreMin == True:
            #Normal Mode, ignore minimal width
            wx.grid.Grid.SetColSize(self, iColumn, width)
        else:
            #enhanced check
            #check if new width smaller than Minimal widht and set the minimal width if yes
            minWidth = self.GetColMinimalWidth(iColumn)    
            if width < minWidth:
                #If we want to set a smaller width,we set the minimal value instead
                wx.grid.Grid.SetColSize(self, iColumn, minWidth)
            else:
                wx.grid.Grid.SetColSize(self, iColumn, width)
                
    def SetRowSize(self, iRow, height, ignoreMin=False):
        #Custom SetRowSize Method, expanded with Minimal Row height check
        if ignoreMin == True:
            #Normal Mode, ignore minimal height
            wx.grid.Grid.SetRowSize(self, iRow, height)
        else:
            #enhanced check
            #check if new height smaller than Minimal height and set the minimal height if yes
            minHeight = self.GetRowMinimalHeight(iRow)    
            if height < minHeight:
                #If we want to set a smaller height,we set the minimal value instead
                wx.grid.Grid.SetRowSize(self, iRow, minHeight)
            else:
                wx.grid.Grid.SetRowSize(self, iRow, height)    
    
    def AutoSizeColumn(self, iColumn, setAsMin=True, ignoreMin=False):
        #Custom AutoSizeColumn Method, expanded with Minimal Column width check
        if ignoreMin == True:
            #Normal Mode, ignore minimal width
            wx.grid.Grid.AutoSizeColumn(self, iColumn, setAsMin)
        else:
            #enhanced check
            #Set new width
            minWidth = self.GetColMinimalWidth(iColumn)
            wx.grid.Grid.AutoSizeColumn(self, iColumn, False) #Dont set as min for now
            newWidth = wx.grid.Grid.GetColSize(self, iColumn)
            #check if new width smaller than Minimal width and set the minimal width if yes
            if newWidth < minWidth:
                #If we want to set a smaller width,we set the minimal value instead
                wx.grid.Grid.SetColSize(self, iColumn, minWidth)
            else:
                wx.grid.Grid.AutoSizeColumn(self, iColumn, setAsMin) #Do this once again with the proper setAsMin-value   
                
    def AutoSizeRow(self, iRow, setAsMin=True, ignoreMin=False):
        #Custom AutoSizeColumn Method, expanded with Minimal Column width check
        if ignoreMin == True:
            #Normal Mode, ignore minimal height
            wx.grid.Grid.AutoSizeRow(self, iRow, setAsMin)
        else:
            #enhanced check
            #Set new height
            minHeight = self.GetRowMinimalHeight(iRow)
            wx.grid.Grid.AutoSizeRow(self, iRow, False) #Dont set as min for now
            newHeight = wx.grid.Grid.GetRowSize(self, iRow)
            #check if new height smaller than Minimal height and set the minimal height if yes
            if newHeight < minHeight:
                #If we want to set a smaller height, we set the minimal value instead
                wx.grid.Grid.SetRowSize(self, iRow, minHeight)
            else:
                wx.grid.Grid.AutoSizeRow(self, iRow, setAsMin) #Do this once again with the proper setAsMin-value  
                
    def AutoSizeColLabelSize(self, iColumn, ignoreMin=False):
        #Custom AutoSizeColLabelSize Method, expanded with Minimal Column width check
        if ignoreMin == True:
            #Normal Mode, ignore minimal width
            wx.grid.Grid.AutoSizeColLabelSize(self, iColumn)
        else:
            #enhanced check
            #Set new width
            minWidth = self.GetColMinimalWidth(iColumn)
            wx.grid.Grid.AutoSizeColLabelSize(self, iColumn) #Dont set as min for now
            newWidth = wx.grid.Grid.GetColSize(self, iColumn)
            #check if new width smaller than Minimal width and set the minimal width if yes
            if newWidth < minWidth:
                #If we want to set a smaller width,we set the minimal value instead
                wx.grid.Grid.SetColSize(self, iColumn, minWidth) 
                
    def AutoSizeRowLabelSize(self, iRow, ignoreMin=False):
        #Custom AutoSizeRowLabelSize Method, expanded with Minimal Column height check
        if ignoreMin == True:
            #Normal Mode, ignore minimal height
            wx.grid.Grid.AutoSizeRowLabelSize(self, iRow)
        else:
            #enhanced check
            #Set new height
            minHeight = self.GetRowMinimalHeight(iRow)
            wx.grid.Grid.AutoSizeRowLabelSize(self, iRow) #Dont set as min for now
            newHeight = wx.grid.Grid.GetRowSize(self, iRow)
            #check if new height smaller than Minimal height and set the minimal height if yes
            if newHeight < minHeight:
                #If we want to set a smaller height,we set the minimal value instead
                wx.grid.Grid.SetRowSize(self, iRow, minHeight)     
                
    def AutoSizeColumns(self, setAsMin=True, ignoreMin=False):  # @UnusedVariable
        #Custom AutoSizeColumns Method, expanded with Minimal Column width check
        for iColmn in range(0, self.GetNumberCols()):
            self.AutoSizeColumn(iColmn, ignoreMin)
            
    def AutoSizeRows(self, setAsMin=True, ignoreMin=False):  # @UnusedVariable
        #Custom AutoSizeRows Method, expanded with Minimal row height check
        for iRow in range(0, self.GetNumberRows()):
            self.AutoSizeRow(iRow, ignoreMin)    
            
    def AutoSize(self, ignoreMin=False):
        #Custom AutoSize Method, expanded with Minimal width/height check
        
        #First Columns
        for iColmn in range(0, self.GetNumberCols()):
            self.AutoSizeColumn(iColmn, ignoreMin)     
            
        #Second Rows
        for iRow in range(0, self.GetNumberRows()):
            self.AutoSizeRow(iRow, ignoreMin)   
            
    def GetColMinimalWidth(self, iColumn):
        #Replaces the GetColMinimalWidth method
        #which didnt exist for us anyway, due to private member mehtod in c++
        if iColumn >= len(self.ListMinColumnWidth):
            #error
            #todo: error handling
            pass
        else:
            return self.ListMinColumnWidth[iColumn]

    
    def SetColMinimalWidth(self, iColumn, width):
        #Replaces the SetColMinimalWidth method
        if iColumn >= len(self.ListMinColumnWidth):
            #error
            #todo: error handling
            pass
        else:        
            self.ListMinColumnWidth[iColumn] = width
    
    def GetRowMinimalHeight(self, iRow):
        #Replaces the GetRowMinimalHeight method
        #which didnt exist for us anyway, due to private member mehtod in c++
        if iRow >= len(self.ListMinRowHeight):
            #error
            #todo: error handling
            pass
        else:        
            return self.ListMinRowHeight[iRow] 

    
    def SetRowMinimalHeight(self, iRow, width):
        #Replaces the SetRowMinimalHeight method
        if iRow >= len(self.ListMinRowHeight):
            #error
            #todo: error handling
            pass
        else:             
            self.ListMinRowHeight[iRow] = width
            
#***************************************************************************************************************************************************************#
#----------------------------------------------------------------------
# different icons for the collapsed/expanded states.
# Taken from standard Windows XP collapsed/expanded states.
#----------------------------------------------------------------------

def GetCollapsedIconData():
    return \
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x01\x8eIDAT8\x8d\xa5\x93-n\xe4@\x10\x85?g\x03\n6lh)\xc4\xd2\x12\xc3\x81\
\xd6\xa2I\x90\x154\xb9\x81\x8f1G\xc8\x11\x16\x86\xcd\xa0\x99F\xb3A\x91\xa1\
\xc9J&\x96L"5lX\xcc\x0bl\xf7v\xb2\x7fZ\xa5\x98\xebU\xbdz\xf5\\\x9deW\x9f\xf8\
H\\\xbfO|{y\x9dT\x15P\x04\x01\x01UPUD\x84\xdb/7YZ\x9f\xa5\n\xce\x97aRU\x8a\
\xdc`\xacA\x00\x04P\xf0!0\xf6\x81\xa0\xf0p\xff9\xfb\x85\xe0|\x19&T)K\x8b\x18\
\xf9\xa3\xe4\xbe\xf3\x8c^#\xc9\xd5\n\xa8*\xc5?\x9a\x01\x8a\xd2b\r\x1cN\xc3\
\x14\t\xce\x97a\xb2F0Ks\xd58\xaa\xc6\xc5\xa6\xf7\xdfya\xe7\xbdR\x13M2\xf9\
\xf9qKQ\x1fi\xf6-\x00~T\xfac\x1dq#\x82,\xe5q\x05\x91D\xba@\xefj\xba1\xf0\xdc\
zzW\xcff&\xb8,\x89\xa8@Q\xd6\xaaf\xdfRm,\xee\xb1BDxr#\xae\xf5|\xddo\xd6\xe2H\
\x18\x15\x84\xa0q@]\xe54\x8d\xa3\xedf\x05M\xe3\xd8Uy\xc4\x15\x8d\xf5\xd7\x8b\
~\x82\x0fh\x0e"\xb0\xad,\xee\xb8c\xbb\x18\xe7\x8e;6\xa5\x89\x04\xde\xff\x1c\
\x16\xef\xe0p\xfa>\x19\x11\xca\x8d\x8d\xe0\x93\x1b\x01\xd8m\xf3(;x\xa5\xef=\
\xb7w\xf3\x1d$\x7f\xc1\xe0\xbd\xa7\xeb\xa0(,"Kc\x12\xc1+\xfd\xe8\tI\xee\xed)\
\xbf\xbcN\xc1{D\x04k\x05#\x12\xfd\xf2a\xde[\x81\x87\xbb\xdf\x9cr\x1a\x87\xd3\
0)\xba>\x83\xd5\xb97o\xe0\xaf\x04\xff\x13?\x00\xd2\xfb\xa9`z\xac\x80w\x00\
\x00\x00\x00IEND\xaeB`\x82'

def GetCollapsedIconBitmap():
    w = GetCollapsedIconImage()
    # wx.Bitmap(w)
    return wx.BitmapFromImage(w)

def GetCollapsedIconImage():
#    bmp = iconsDir + 'GroupBoxDown.bmp.NOT'
#    if fileExist(bmp):
#        return wx.Image(bmp)
#    else:
    try:
        stream = StringIO(GetCollapsedIconData().decode("utf-8"))
        #return wx.ImageFromStream(stream)       # .Scale(16, 16)
        return wx.ImageFromStream(stream).Scale(int(16*ScreenScaleFactor), int(16*ScreenScaleFactor))
    except:
        from io import BytesIO
        stream = BytesIO(bytearray(GetCollapsedIconData()))
        #return wx.Image(stream, wx.BITMAP_TYPE_ANY) # wx.ImageFromStream for legacy wx
        return wx.Image(stream, wx.BITMAP_TYPE_ANY).Scale(int(16*ScreenScaleFactor), int(16*ScreenScaleFactor)) # wx.ImageFromStream for legacy wx

#----------------------------------------------------------------------
def GetExpandedIconData():
    return \
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x01\x9fIDAT8\x8d\x95\x93\xa1\x8e\xdc0\x14EO\xb2\xc4\xd0\xd2\x12\xb7(mI\
\xa4%V\xd1lQT4[4-\x9a\xfe\xc1\xc2|\xc6\xc2~BY\x83:A3E\xd3\xa0*\xa4\xd2\x90H!\
\x95\x0c\r\r\x1fK\x81g\xb2\x99\x84\xb4\x0fY\xd6\xbb\xc7\xf7>=\'Iz\xc3\xbcv\
\xfbn\xb8\x9c\x15 \xe7\xf3\xc7\x0fw\xc9\xbc7\x99\x03\x0e\xfbn0\x99F+\x85R\
\x80RH\x10\x82\x08\xde\x05\x1ef\x90+\xc0\xe1\xd8\ryn\xd0Z-\\A\xb4\xd2\xf7\
\x9e\xfbwoF\xc8\x088\x1c\xbbae\xb3\xe8y&\x9a\xdf\xf5\xbd\xe7\xfem\x84\xa4\
\x97\xccYf\x16\x8d\xdb\xb2a]\xfeX\x18\xc9s\xc3\xe1\x18\xe7\x94\x12cb\xcc\xb5\
\xfa\xb1l8\xf5\x01\xe7\x84\xc7\xb2Y@\xb2\xcc0\x02\xb4\x9a\x88%\xbe\xdc\xb4\
\x9e\xb6Zs\xaa74\xadg[6\x88<\xb7]\xc6\x14\x1dL\x86\xe6\x83\xa0\x81\xba\xda\
\x10\x02x/\xd4\xd5\x06\r\x840!\x9c\x1fM\x92\xf4\x86\x9f\xbf\xfe\x0c\xd6\x9ae\
\xd6u\x8d \xf4\xf5\x165\x9b\x8f\x04\xe1\xc5\xcb\xdb$\x05\x90\xa97@\x04lQas\
\xcd*7\x14\xdb\x9aY\xcb\xb8\\\xe9E\x10|\xbc\xf2^\xb0E\x85\xc95_\x9f\n\xaa/\
\x05\x10\x81\xce\xc9\xa8\xf6><G\xd8\xed\xbbA)X\xd9\x0c\x01\x9a\xc6Q\x14\xd9h\
[\x04\xda\xd6c\xadFkE\xf0\xc2\xab\xd7\xb7\xc9\x08\x00\xf8\xf6\xbd\x1b\x8cQ\
\xd8|\xb9\x0f\xd3\x9a\x8a\xc7\x08\x00\x9f?\xdd%\xde\x07\xda\x93\xc3{\x19C\
\x8a\x9c\x03\x0b8\x17\xe8\x9d\xbf\x02.>\x13\xc0n\xff{PJ\xc5\xfdP\x11""<\xbc\
\xff\x87\xdf\xf8\xbf\xf5\x17FF\xaf\x8f\x8b\xd3\xe6K\x00\x00\x00\x00IEND\xaeB\
`\x82'

def GetExpandedIconBitmap():
    w = GetExpandedIconImage()
    # wx.Bitmap(w)
    return wx.BitmapFromImage(w)

def GetExpandedIconImage():
    """
    from io import BytesIO
    stream = BytesIO(bytearray(image_data)) # just bytes() for py3
    image = wx.Image(stream, wx.BITMAP_TYPE_ANY) # wx.ImageFromStream for legacy wx
    bitmap = wx.Bitmap(image) # wx.BitmapFromImage for legacy wx
    """
#    bmp = iconsDir + 'GroupBoxUp.bmp.NOT'
#    if fileExist(bmp):
#        return wx.Image(bmp)
#    else:
    try:
        stream = StringIO(GetExpandedIconData().decode("utf-8"))
        #return wx.ImageFromStream(stream)       # .Scale(16, 16)
        return wx.ImageFromStream(stream).Scale(int(16*ScreenScaleFactor), int(16*ScreenScaleFactor))
    except:
        from io import BytesIO
        stream = BytesIO(bytearray(GetExpandedIconData()))
        #return wx.Image(stream, wx.BITMAP_TYPE_ANY) # wx.ImageFromStream for legacy wx
        return wx.Image(stream, wx.BITMAP_TYPE_ANY).Scale(int(16*ScreenScaleFactor), int(16*ScreenScaleFactor)) # wx.ImageFromStream for legacy wx
    

class FoldPanelItem(fpb.FoldPanelItem):
    """
    This class is a child sibling of the :class:`FoldPanelBar` class. It will
    contain a :class:`CaptionBar` class for receiving of events, and a the
    rest of the area can be populated by a :class:`Panel` derived class.
    """

    def __init__(self, parent, id=wx.ID_ANY, caption="", foldIcons=None,
                 collapsed=False, cbstyle=None, name="_FPL_ITEM"):
        """
        Default Class Constructor.
        """
        self._resourcelabel = caption
        caption = getText(caption, name)

        fpb.FoldPanelItem.__init__(self, parent, id, caption, foldIcons, collapsed, cbstyle)       # Base Class Constructor

    def GetResourceLabel(self):
        return getattr(self, "_resourcelabel", "")

class BaseGroupPanel(fpb.FoldPanelBar):
    '''Represents a sub-window with several pages.'''     # can be accessed via __doc__
    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=fpb.FPB_VERTICAL, openPages="-1"):     # change for version 2.8.11 @ReservedAssignment
        """
        Default Class Constructor.
        """
        self.popUpWin = None
        self.shouldPOP = False
        self.openPagesSize = []         # buffer for storing sizes of all open pages
        self.collapsedPagesSize = []    #...for all collapsed pages

        self.Images = wx.ImageList(int(16*ScreenScaleFactor), int(16*ScreenScaleFactor))           # create a list with ... (must give the max. size)        self.Images.Add(GetExpandedIconBitmap())     # 1. an image for the expanded state
        self.Images.Add(GetExpandedIconBitmap())     # 1. an image for the expanded state
        self.Images.Add(GetCollapsedIconBitmap())    # 2. an image for the collapsed state
        #
        fpb.FoldPanelBar.__init__(self, parent, id, pos, size, style)       # Base Class Constructor
        #
        topsizer = wx.BoxSizer( wx.VERTICAL )        # the topsizer of this class
        self.SetLabel(wx.EmptyString)
        self.SetName("_FPB_BAR")
        self.SetSizer(topsizer)
        
        # a self._foldPanel object is automatically created in fpb.FoldPanelBar.__init__() as a child of the fpb.FoldPanelBar itself
        self._foldPanel.SetLabel(wx.EmptyString)
        self._foldPanel.SetName("_FPB_PANEL")
        self._foldPanel.SetSizer( wx.BoxSizer( wx.VERTICAL ) )
        #
        topsizer.Add(self._foldPanel, 0, wx.EXPAND, 0)      # IMPORTANT STEP TO GET WORKING SIZING MECHANISM !!
        
        logger.info("%s.__init__ -> GREEN %s" % (self.__class__.__name__ , self.GetParent().__class__.__name__))
        if _DEBUG & 0x4: self.SetBackgroundColour('GREEN')

        self._expandedPages = openPages
        #
        self.createGroup1()
        self.createGroup2()
        self.createGroup3()
        self.createGroup4()         # Experimental Test Page
        self.createGroup5()         # Setupsheet

        # if there is only one open page -> give this page the size of the biggest found page (even if collapsed)
        if len(self.openPagesSize) == 1:
            maxW, maxH = self.openPagesSize[0]
            captHeight = 0
            for siz in self.collapsedPagesSize:
                maxW = max(maxW, siz.GetWidth())
                maxH = max(maxH, siz.GetHeight())
                captHeight += MEDIUMBORDER
            topsizer.SetMinSize((maxW, maxH + captHeight))
        #
        return

    # virtual methods -> override in derived classes!!
    def createGroup1(self):
        pass
    
    def createGroup2(self):
        pass
    
    def createGroup3(self):
        pass
    
    def createGroup4(self):
        pass
    
    def createGroup5(self):
        pass

    def GetToolTipString(self):
        if hasattr(self, "toolTipString"):
            return self.toolTipString
        else:
            return wx.EmptyString

    def GetExpandedPages(self):
        expandedPages = ""
        for panel in self._panels:
            if panel.IsExpanded():
                name = panel.GetName()
                expandedPages += name.lstrip('_FPL_ITEM')
                expandedPages += ","
        return expandedPages

    def IsCollapsed(self, pageStr):
        return pageStr not in self._expandedPages and "-1" not in self._expandedPages
    
    def IsExpanded(self, pageStr):
        return pageStr in self._expandedPages or "-1" in self._expandedPages
    
    def AddFoldPanel(self, caption="", collapsed=False, foldIcons=None, cbstyle=None, itemname="_FPL_ITEM", captionname="CPT_BAR"):
        """
        Adds a fold panel to the list of panels.
        Overrides original method in fpb.FoldPanelBar.
        """
        #
        item = fpb.FoldPanelBar.AddFoldPanel(self, getText(caption, captionname), collapsed, foldIcons, cbstyle)      # returns an wx.lib.agw.foldpanelbar.FoldPanelItem object
        #
        item.SetLabel(wx.EmptyString)
        item.SetName(itemname)
        def MyDrawVerticalGradient(self, dc, rect):  # @UnusedVariable
            dc = wx.PaintDC(self)
            rect = self.GetRect()
            if  rect.height < 1 or rect.width < 1:
                return
            dc.SetPen(wx.TRANSPARENT_PEN)
            # calculate gradient coefficients
            col2 = self._style.GetSecondColour()
            col1 = self._style.GetFirstColour()
            r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue())
            r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue())
            flrect = float(rect.height)
            rstep = float((r2 - r1)) / flrect
            gstep = float((g2 - g1)) / flrect
            bstep = float((b2 - b1)) / flrect
            rf, gf, bf = 0, 0, 0
            for y in range(rect.y, rect.y + rect.height):
                currCol = (r1 + rf, g1 + gf, b1 + bf)
                dc.SetBrush(wx.Brush(currCol, wx.BRUSHSTYLE_SOLID))
                dc.DrawRectangle(rect.x, rect.y + (y - rect.y), rect.width, rect.height)
                rf = rf + int(rstep)
                gf = gf + int(gstep)
                bf = bf + int(bstep)
        item._captionBar.DrawVerticalGradient = partial(MyDrawVerticalGradient, item._captionBar)
        item._captionBar.SetLabel(wx.EmptyString)
        item._captionBar.SetName(captionname)
        item._resourcelabel = caption
#         item.GetResourceLabel = self.GetResourceLabel               # pointer to function which is implemented here
        # handle different screen resolutions (usually we have ScreenScaleFactor=1.0 and 96 DPI)
        size = item._captionBar.GetSize()
        size = wx.Size(int(size.width*ScreenScaleFactor), int(size.height*ScreenScaleFactor))
        item._captionBar.SetMinSize(size)        
        item._captionBar.Bind(wx.EVT_LEFT_DOWN, self.OnPressCaption)     # bind mouse-click-event directly to the underlying panel
        item._captionBar.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
        item._captionBar.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
        #
        toolTipString = captionname
        item._captionBar.SetToolTipString(toolTipString)
        item._captionBar._resourcelabel = caption
#         item._captionBar.GetResourceLabel = self.GetResourceLabel   # pointer to function which is implemented here
        return item
    
    
    def GetResourceLabel(self):
        return getattr(self, "_resourcelabel", "")
        
    def showPop(self, pos):
        if self.popUpWin is None and self.shouldPOP:   # when we have already one, don't create another
            self.popUpWin = PopupWindow(self.GetParent(), pos, self.GetToolTipString(), holdTime=TOOLTIP_HOLDTIME)

    def killPop(self):
        if self.popUpWin is not None:  # only when we have one, we can kill it
            self.popUpWin.Kill()
            self.popUpWin = None

    def OnEnterWindow(self, event):  # @UnusedVariable
        obj = event.GetEventObject()
        logger.debug('%s.OnEnterWindow called (name: %s) (focus: %s)' % (obj.__class__.__name__, obj.Name, obj.HasFocus()))
        # setting focus if necessary
        if not obj.HasFocus():
            obj.SetFocus()
        if not self.shouldPOP:     # if there is already a request to popup -> do nothing
            self.shouldPOP = True
            # create the popup window at the mouse position
            pos = wx.GetMousePosition()
            # 
            #, "My Important {0} ToolTip!".format(obj.GetToolTipText())
            wx.FutureCall(TOOLTIP_DELAYTIME, self.showPop, pos)

    def OnLeaveWindow(self, event):  # @UnusedVariable
        if self.shouldPOP == False:      # if there is no popup reqested -> do nothing
            return
        rect   = self.GetScreenRect()
        # in this case we get also a leave event when the mouse moves over the label or edit field
        # -> so we have to check whether we are really outside our panel
        if not rect.Contains(wx.GetMousePosition()):
            self.shouldPOP = False
            self.killPop()
    
#     def AddFoldPanelWindow(self, item, page):
#         # to save orig. size seems to be necessary because it will be altered in the AddFoldPanelWindow method 
#         # -> this causes bad behaviour in sizing, scrolling, docking
#         size = page.GetSize()
#         ret = fpb.FoldPanelBar.AddFoldPanelWindow(self, item, page)
#         page.SetSize(size)
#         return ret

    def GetFoldPanelWindow(self, panel, winNo=0):
        try:
            item = self._panels.index(panel)  # @UnusedVariable (check if panel is in panels list)
        except:
            raise Exception("ERROR: Invalid Panel Passed To GetFoldPanelWindow: " + repr(panel))
        
        return panel._items[winNo]._wnd

    def OnPressCaption(self, event):
        """
        Overrides original method in fpb.FoldPanelBar.
        This is NECESSARY because the original method FAILS when called from here with the mouse-event: wx.EVT_LEFT_DOWN (-> here we miss a GetTag() method)
        """
        # self                                           # <optionsdlg.GroupPanel object at 0x0000017374667948>
        # event.GetClassName()                           # 'wxMouseEvent', 'wxCommandEvent'
        # obj = event.GetEventObject()                   # <wx.lib.agw.foldpanelbar.CaptionBar object at 0x0000023FC69CED38>
        item = event.GetEventObject().GetParent()        # <wx.lib.agw.foldpanelbar.FoldPanelItem object at 0x0000017374699E58>
        logger.info("%s.OnPressCaption %s @ %s" % (self.__class__.__name__ , event.GetClassName(), item.GetName()))

        if item.IsExpanded():
            self.Collapse(item)
        else:
            self.Expand(item)

        # page = self.GetFoldPanelWindow(item, 0)     # test
        itemSizer = item.GetSizer()
        win = itemSizer.GetItem(1).GetWindow()      # in our environment here are always two widgets: the captionbar and the content-panel itself
        itemSizer.Show(win, show=item.IsExpanded(), recursive=False)

        self.Layout()               # <optionsdlg.GroupPanel object>
        self.GetParent().Layout()   # <p2c.window.ScrolledBasePanel object>
        self.GetParent().OnInnerSizeChanged()
        #self.GetParent().SetupScrolling()   # <p2c.window.ScrolledBasePanel object>
        #self.GetGrandParent().Layout()   # <optionsdlg.ACVisionPostOptionsDialog object> PROBABLY NOT NEEDED

    def ResizeFPB(self):
        """
        Calculate and set the actual needed size for the
        foldpanelbar depending on the opened pages
        now presumably obsolete (automatically done with nested sizers on foldpanelbar elements) !!!
        """
        pass


#***************************************************************************************************************************************************************#
class CustomStatusBar(wx.StatusBar):
    """ Example from the wxPython Demo """
    def __init__(self, parent, txt1=wx.EmptyString, txt2=wx.EmptyString, style=wx.STB_DEFAULT_STYLE):
        wx.StatusBar.__init__(self, parent, wx.ID_ANY, name='_STATUSBAR', style=style)

        # This status bar has three fields
        self.SetFieldsCount(2)
        # Sets the three fields to be relative widths to each other.
        self.SetStatusWidths([-3, -1])
        self.sizeChanged = False
        
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_IDLE, self.OnIdle)

        self.text1 = txt1 if isinstance(txt1, str) else wx.EmptyString
        self.text2 = txt2 if isinstance(txt2, str) else wx.EmptyString
        #
        # Field 0 ... just text
        #self.SetStatusText("A Custom StatusBar...", 0)
        self.tc1 = TextField( self, wx.ID_ANY, self.text1, pos = wx.DefaultPosition, size = wx.DefaultSize, style = 0, name = '_STATUSBAR_T1' )

        # This will fall into field 1 (the second field)
#         self.cb = wx.CheckBox(self, wx.ID_ANY, "toggle clock")
#         self.Bind(wx.EVT_CHECKBOX, self.OnToggleClock, self.cb)
#         self.cb.SetValue(True)

        # set the initial position of the checkbox
#        self.Reposition()

        # We're going to use a timer to drive a 'clock' in the last field.
#         self.timer = wx.PyTimer(self.Notify)
#         self.timer.Start(1000)
#         self.Notify()
        self.tc2 = TextField( self, wx.ID_ANY, self.text2, pos = wx.DefaultPosition, size = wx.DefaultSize, style = 0, name = '_STATUSBAR_T2' )
        # set the initial position of the both controls
        
        self.Reposition()


    # Handles events from the timer we started in __init__().
    # We're using it to drive a 'clock' in field 2 (the third field).
#     def Notify(self):
#         t = time.localtime(time.time())
#         st = time.strftime("%d-%b-%Y   %I:%M:%S", t)
#         self.SetStatusText(st, 2)
#         logger.debug("tick...\n")
# 
# 
#     # the checkbox was clicked
#     def OnToggleClock(self, event):
#         if self.cb.GetValue():
#             self.timer.Start(1000)
#             self.Notify()
#         else:
#             self.timer.Stop()

    def OnSize(self, evt):
        evt.Skip()
        self.Reposition()  # for normal size events

        # Set a flag so the idle time handler will also do the repositioning.
        # It is done this way to get around a buglet where GetFieldRect is not
        # accurate during the EVT_SIZE resulting from a frame maximize.
        self.sizeChanged = True

    def OnIdle(self, evt):  # @UnusedVariable
        if self.sizeChanged:
            self.Reposition()

    # reposition the checkbox
    def __Reposition(self):
        rect = self.GetFieldRect(1)
        rect.x += 1
        rect.y += 1
        self.cb.SetRect(rect)
        self.sizeChanged = False
        
    def Reposition(self):
        rect = self.GetFieldRect(0)
        rect.x += 1
        rect.y += 1
        self.tc1.SetRect(rect)
        rect = self.GetFieldRect(1)
        rect.x += 1
        rect.y += 1
        self.tc2.SetRect(rect)
        self.sizeChanged = False
        
    def SetText1(self, txt, color=None):
        self.text1 = txt
#        self.tc1.SetValue(self.text1)
        self.tc1.SetLabel(self.text1)
        if color:
            self.txtColor1 = color
            self.tc1.SetForegroundColour(self.txtColor1)
        
    def SetText2(self, txt, color=None):
        self.text2 = txt
#        self.tc2.SetValue(self.text2)
        self.tc2.SetLabel(self.text2)
        if color:
            self.txtColor2 = color
            self.tc2.SetForegroundColour(self.txtColor2)
        
#***************************************************************************************************************************************************************#
def my_screenshot(filename, typ='jpg'):
    """
    Makes a screenshot and saves image to file
    """
    context = wx.ScreenDC()
    width, height = context.GetSize()
    bitmap = wx.EmptyBitmap(width, height, -1)
    memory = wx.MemoryDC()
    memory.SelectObject(bitmap)
    memory.Blit(0, 0, width, height, context, -1, -1)
    memory.SelectObject(wx.NullBitmap)
    # save
    if typ == 'gif':
        bitmap.SaveFile("%s.%s" % (filename, typ), wx.BITMAP_TYPE_GIF)
    elif typ == 'png':
        bitmap.SaveFile("%s.%s" % (filename, typ), wx.BITMAP_TYPE_PNG)
    elif typ == 'jpg':
        bitmap.SaveFile("%s.%s" % (filename, typ), wx.BITMAP_TYPE_JPEG) 
    else:
        pass
    del context


