2020년 4월 20일 월요일

[Jython] PDF to Image Converter


1. PDF to Image Converter (pdfbox)


import sys
sys.path.append(r"D:\jarlibs\pdfbox-app-2.0.11.jar")

from java.awt.image import *
from java.io import *
from org.apache.pdfbox.pdmodel import *
from org.apache.pdfbox.rendering import *
from org.apache.pdfbox.tools.imageio import *

def PdfToPng(file,folder):
    pdf = PDDocument.load(File(file))
    dir = File(folder)
    if not dir.exists(): dir.mkdirs()
    render = PDFRenderer(pdf);
    for page in range(pdf.getNumberOfPages()): 
        bim = render.renderImageWithDPI(page, 300, ImageType.RGB)
        ImageIOUtil.writeImage( bim, folder + "/image_%04d.png" % page, 300 )

if __name__ == '__main__':
    PdfToPng("D:/a.pdf", "D:/a.pdf.out2" )

2020년 4월 19일 일요일

[ezGuiLib] ezWxPyApp

1. ezWxPyApp


import os
import sys
import time
import wx
import ezWxPython as ew

def initCtrls():
    ew.getWxCtrl('top1').SetBackgroundColour(wx.Colour(200,200,240))
    
def onExit(event):
    appWin.close()
   
def onAbout(event):
    appWin.messageBox("About", "Control Demo\nzdiv")

def onGo(event):
    kind = ew.getValue('kind')
    action = ew.getValue('action')
    if action == 'getLabel':
        ew.setValue('value',ew.getLabel(kind))
    elif action == 'setLabel':
        ew.setLabel(kind,ew.getValue('value'))
    elif action == 'getValue':
        ew.setValue('value',str(ew.getValue(kind)))
    elif action == 'setValue':
        ew.setValue(kind,ew.castValue(kind,ew.getValue('value')))
    elif action == 'appendValue':
        ew.appendValue(kind,ew.getValue('value'))
    elif action == 'removeValue':
        ew.removeValue(kind,ew.getValue('value'))
    elif action == 'setFgColor':
        ew.setFgColor(kind,wx.Colour(0,0,255))
    elif action == 'setBgColor':
        ew.setBgColor(kind,wx.Colour(255,0,0))
        
menu_def = { 
    "File" : { 
        "Exit" : [ onExit, wx.ART_QUIT ],
    }, 
    "Help" : { 
        "About" : onAbout 
    },
}

body_def = [
    [ ew.Choice(['label','button','toggle','check','text','choice','combo','list','date','time'], key='kind'),
      ew.Choice(['getLabel','setLabel','getValue','setValue','appendValue','removeValue','setFgColor','setBgColor'], key='action'),
      ew.Text("",key='value'),
      ew.Button("Go",handler=onGo),
    ], 
    [ ew.Label("Label: ",expand=True),
      ew.Label("Value",expand=True,proportion=1,key='label',size=(64,-1)), ],
    [ ew.Label("Button: ",expand=True),
      ew.Button("Button",expand=True,proportion=1,key='button',size=(64,-1)), ],
    [ ew.Label("ToggleButton: ",expand=True),
      ew.ToggleButton("ToggleButton",value=True,expand=True,proportion=1,key='toggle',size=(64,-1)), ],
    [ ew.Label("CheckButton: ",expand=True),
      ew.CheckButton("CheckButton",value=True,expand=True,proportion=1,key='check',size=(64,-1)), ],
    [ ew.Label("Text: ",expand=True),
      ew.Text("Text",expand=True,proportion=1,key='text',size=(64,-1)), ],
    [ ew.Label("Choice: ",expand=True),
      ew.Choice(['apple','lemon'],expand=True,size=(64,-1),proportion=1,key='choice'), ],
    [ ew.Label("Combo: ",expand=True),
      ew.Combo(['apple','lemon'],expand=True,size=(64,-1),proportion=1,key='combo'),], 
    [ ew.Label("List: ",expand=True),
      ew.List(['apple','lemon'],expand=True,size=(64,-1),proportion=1,key='list'),],       
    [ ew.Label("Date: ",expand=True),
      ew.Date(expand=True,size=(64,-1),proportion=1,key='date'),],       
    [ ew.Label("Time: ",expand=True),
      ew.Time(expand=True,size=(64,-1),proportion=1,key='time'),],       
]

status_def = [
    ["Ready", -1],
]

layout = {
    "menu"   : menu_def,
    "body"   : body_def, 
    "status"   : status_def, 
}

######################################################################
# Main
######################################################################

if __name__ == "__main__":
    appWin = ew.WxApp(u"Control Demo", 400, 480)
    appWin.makeLayout(layout)
    appWin.run()

[ezGuiLib] ezWxPyLib

1. ezWxPyLib


import os
import sys
import time
import wx
import wx.adv

from threading import Thread

######################################################################
# Library
######################################################################

ID_START = 1000
CtrlTable = {}

def getId():
    global ID_START
    ID_START += 1
    return ID_START

def registerCtrl(name,ctrl):
    global CtrlTable
    CtrlTable[name] = ctrl

def getCtrl(name):
    global CtrlTable
    if name in CtrlTable:
        return CtrlTable[name]
    else:
        return None

def getWxCtrl(name):
    global CtrlTable
    if name in CtrlTable:
        return CtrlTable[name].ctrl
    else:
        return None

def getWxTimer(name):
    return getCtrl(name)

def getWxAppCtrl():
    global CtrlTable
    name = 'WxApp'
    if name in CtrlTable:
        return CtrlTable[name].ctrl
    else:
        return None

def clearValue(key):
    ctrl = getCtrl(key)
    if ctrl is not None:
        return ctrl.clearValue() 
    else:
        return None

def getLabel(key):
    ctrl = getCtrl(key)
    if ctrl is not None:
        return ctrl.getLabel() 
    else:
        return None

def setLabel(key,value):
    ctrl = getCtrl(key)
    if ctrl is not None:
        ctrl.setLabel(value) 

def getValue(key):
    ctrl = getCtrl(key)
    if ctrl is not None:
        return ctrl.getValue() 
    else:
        return None

def setValue(key,value):
    ctrl = getCtrl(key)
    if ctrl is not None:
        ctrl.setValue(value) 

def appendValue(key,value):
    ctrl = getCtrl(key)
    if ctrl is not None:
        return ctrl.appendValue(value) 
    else:
        return None

def removeValue(key,value):
    ctrl = getCtrl(key)
    if ctrl is not None:
        return ctrl.removeValue(value) 
    else:
        return None
 
def setFgColor(key,color):
    ctrl = getCtrl(key)
    if ctrl is not None:
        ctrl.setFgColor(color)

def setBgColor(key,color):
    ctrl = getCtrl(key)
    if ctrl is not None:
        ctrl.setBgColor(color)

def castValue(key,value):
    ctrl = getCtrl(key)
    if ctrl is not None:
        return ctrl.castValue(value)
    else:
        return value
        
def encodeIcon(filename):
    from zlib import compress
    from base64 import b64encode
    with open(filename, "rb") as f:
        data = b64encode(compress(f.read()))
    return data

def encodeIconToStr(filename):
    icon = encodeIcon(filename)
    return icon.decode('utf-8')
    
def decodeIcon(data):
    from base64 import b64decode
    from zlib import decompress
    image_data = decompress(b64decode(data))
    return image_data

def getBitmap(data):
    from io import BytesIO
    image_data = decodeIcon(data)
    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
    return bitmap

def getMenuBitmap(data, size=(16,16)):
    if data[0] == b'w'[0] and data[1] == b'x'[0]:
        return wx.ArtProvider.GetBitmap(data, wx.ART_MENU, size)
    else:
        return getBitmap(data)

def getToolbarBitmap(data, size=(32,32)):
    if data[0] == b'w'[0] and data[1] == b'x'[0]:
        return wx.ArtProvider.GetBitmap(data, wx.ART_TOOLBAR, size)
    else:
        return getBitmap(data)

def getButtonBitmap(data, size=(16,16)):
    if data[0] == b'w'[0] and data[1] == b'x'[0]:
        return wx.ArtProvider.GetBitmap(data, wx.ART_BUTTON, size)
    else:
        return getBitmap(data)

def threadHandle(handler,start=False,key=None,daemon=True,args=()):
    #from threading import *
    import threading
    thread = threading.Thread(target=handler,args=args)
    thread.daemon = daemon
    if key is not None:
        registerCtrl(key,thread)
    if start is True:
        thread.start()

def threadStart(key):
    thread = getCtrl(key)
    if thread is not None:
        thread.start()

def threadJoin(key):
    thread = getCtrl(key)
    if thread is not None:
        thread.join()

def callAfter(handler,*args):
    wx.CallAfter(handler,*args)

def doBusyJob(job,args=(),message="Please wait ...",parent=None,bgColor=None,fgColor=None):
    import wx.lib.busy
    with wx.lib.busy.BusyInfo(message,parent,bgColor,fgColor):
        job(args)

######################################################################
# Layouts
######################################################################

class VBox():
    def __init__(self,parent=None,label=None,orient=wx.VERTICAL,proportion=0):
        if label is None:
            self.ctrl = wx.BoxSizer( orient )
        else:
            self.ctrl = wx.StaticBoxSizer( wx.StaticBox( parent, wx.ID_ANY, label ), orient )

    def add(self,child,proportion=0,expand=True,border=5,align=0):
        flags = align
        flags |= wx.EXPAND if expand == True else 0
        flags |= wx.ALL if border > 0 else 0
        self.ctrl.Add( child, proportion, flags, border )

    def addSpacer(self,proportion=1):
        self.ctrl.Add( ( 0, 0), proportion, wx.EXPAND|wx.ALL, 5 )

class HBox(VBox):
    def __init__(self,parent=None,label=None,orient=wx.HORIZONTAL,proportion=0):
        super().__init__(parent,label,orient,proportion)

class Control():
    def __init__(self,key=None,expand=False,proportion=0,border=2,size=wx.DefaultSize,pos=wx.DefaultPosition,tooltip=None):
        self.ctrl = None
        self.key = key
        self.tooltip = tooltip
        self.expand = expand
        self.proportion = proportion
        self.border = border
        self.size = size
        self.pos = pos
    def getLabel(self): #button
        return self.ctrl.GetLabel()
    def setLabel(self,value): #button
        self.ctrl.SetLabel(value)
    def getValue(self):
        return self.ctrl.GetValue()
    def setValue(self,value):
        self.ctrl.SetValue(value)
    def clearValue(self):
        self.ctrl.SetValue('')
    def appendValue(self,value):
        self.ctrl.Append(value)
    def deleteValue(self,value):
        if type(value) is str:
            n = self.ctrl.FindString(value)
            if n != wx.NOT_FOUND:
                self.ctrl.Delete(n)
        elif type(value) is int:
                self.ctrl.Delete(value)
    def removeValue(self,value):
        self.deleteValue(value)
    def setFgColor(self,value):
        self.ctrl.SetForegroundColour(value)
        self.ctrl.Refresh()
    def setBgColor(self,value):
        self.ctrl.SetBackgroundColour(value)
        self.ctrl.Refresh()
    def castValue(self,value):
        return value
        
######################################################################
# Containers
######################################################################

def wrapSizer(widget):
    sizer = wx.BoxSizer()
    sizer.Add( widget, 1, wx.EXPAND, 0 )
    sizer.Fit( widget )
    return sizer

def dictValue(new_value,old_value):
    try:
        if new_value is not None:
            return new_value
    except:
        pass
    return old_value

def makeLayout(layout,parent):
    if type(layout) is not list:
        return VBox();
    vbox_label = None;
    if type(layout[0]) is str:
        vbox_label = layout[0]
        layout.remove(layout[0])
    vbox = VBox(parent,vbox_label)
    for row in layout:
        hbox_label = None;
        if type(row[0]) is str:
            hbox_label = row[0]
            row.remove(row[0])
        hbox = HBox(parent,hbox_label)        
        prop = 0
        expand = True
        border = 2
        if type(row) is list:
            for col in row:
                if type(col) is dict:
                    prop = dictValue( col.get('proportion'), prop )
                    expand = dictValue( col.get('expand'), expand )
                    border = dictValue( col.get('border'), border )
                elif col is None:
                    hbox.addSpacer(proportion=1)
                else:
                    col.create(parent)
                    hbox.add(col.ctrl,proportion=col.proportion,expand=col.expand,border=col.border,align=wx.ALIGN_CENTER_VERTICAL|wx.ALL)
        else: #compound control
            row.create(parent)
        vbox.add(hbox.ctrl,proportion=prop,expand=expand,border=border,align=wx.ALIGN_LEFT|wx.ALL)
    return vbox

class Book(Control):
    def __init__(self,layouts,parent=None,create=False,horizontal=True,expand=False,proportion=0,border=2,
                size=wx.DefaultSize,pos=wx.DefaultPosition,style='note',key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.layouts = layouts
        self.style = style
        self.simplePages = []
        if create is True and parent is not None:
            self.create(parent)
    def create(self,parent):
        if self.style == 'note':
            self.ctrl = wx.Notebook( parent, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 )
        elif self.style == 'choice':
            self.ctrl = wx.Choicebook( parent, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 )
        else: #simple
            self.ctrl = wx.Simplebook( parent, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 )
        self.titles = []
        self.panels = []
        for layout in self.layouts:
            if type(layout) == str:
                self.titles.append(layout)
            elif type(layout) == list:
                self.panels.append(Panel(layout, self.ctrl, create=True))
        for i in range(len(self.panels)):
            if self.style == 'simple':
                self.simplePages.append(self.panels[i].ctrl);
            else:
                self.ctrl.AddPage( self.panels[i].ctrl, self.titles[i], False )              
        if self.style == 'simple':
            self.setPage(0)
        if self.key is not None:
            registerCtrl( self.key, self )            
    def setEffect(self,effect=None):
        if self.style == 'simple':
            if effect == 'roll_to_left':
                self.ctrl.SetEffect(wx.SHOW_EFFECT_ROLL_TO_LEFT)
            elif effect == 'roll_to_right':
                self.ctrl.SetEffect(wx.SHOW_EFFECT_ROLL_TO_RIGHT)
            elif effect == 'roll_to_top':
                self.ctrl.SetEffect(wx.SHOW_EFFECT_ROLL_TO_TOP)
            elif effect == 'roll_to_bottom':
                self.ctrl.SetEffect(wx.SHOW_EFFECT_ROLL_TO_BOTTOM)
            elif effect == 'slide_to_left':
                self.ctrl.SetEffect(wx.SHOW_EFFECT_SLIDE_TO_LEFT)
            elif effect == 'slide_to_right':
                self.ctrl.SetEffect(wx.SHOW_EFFECT_SLIDE_TO_RIGHT)
            elif effect == 'slide_to_top':
                self.ctrl.SetEffect(wx.SHOW_EFFECT_SLIDE_TO_TOP)
            elif effect == 'slide_to_bottom':
                self.ctrl.SetEffect(wx.SHOW_EFFECT_SLIDE_TO_BOTTOM)
            elif effect == 'blend':
                self.ctrl.SetEffect(wx.SHOW_EFFECT_BLEND)
            elif effect == 'expand':
                self.ctrl.SetEffect(wx.SHOW_EFFECT_EXPAND)
            else:
                self.ctrl.SetEffect(wx.SHOW_EFFECT_NONE)                
    def setPage(self,index):
        if self.style == 'simple':
            if index >= len(self.simplePages):
                index = 0
            self.ctrl.ShowNewPage(self.simplePages[index])

class Notebook(Book):
    def __init__(self,layouts,parent=None,create=False,horizontal=True,expand=False,proportion=0,size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(layouts,parent,create,horizontal,expand,proportion,style='note',size=size,pos=pos,key=key)

class Choicebook(Book):
    def __init__(self,layouts,parent=None,create=False,horizontal=True,expand=False,proportion=0,size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(layouts,parent,create,horizontal,expand,proportion,style='choice',size=size,pos=pos,key=key)

class Simplebook(Book):
    def __init__(self,layouts,parent=None,create=False,horizontal=True,expand=False,proportion=0,size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(layouts,parent,create,horizontal,expand,proportion,style='simple',size=size,pos=pos,key=key)

class Panel(Control):
    import wx.lib.scrolledpanel
    def __init__(self,layout,parent=None,create=False,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,label="",style=None,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.layout = layout
        self.label = label
        self.style = style
        if create is True and parent is not None:
            self.create(parent)
    def create(self,parent):
        if self.style is None:
            self.ctrl = wx.Panel( parent, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
            self.sizer = makeLayout(self.layout,self.ctrl)
            self.ctrl.SetSizer( self.sizer.ctrl )
            self.ctrl.Layout()
        elif self.style == 'scroll':
            self.ctrl = wx.lib.scrolledpanel.ScrolledPanel( parent, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.HSCROLL|wx.VSCROLL|wx.TAB_TRAVERSAL )
            self.sizer = makeLayout(self.layout,self.ctrl)
            self.ctrl.SetSizer( self.sizer.ctrl )
            #begin for scrolledwindow
            self.ctrl.SetAutoLayout(1)
            #self.ctrl.SetupScrolling(scroll_y = True)
            width = self.ctrl.GetBestSize().width
            height = self.ctrl.GetBestSize().height
            self.ctrl.SetSize((width, height))
            self.ctrl.SetScrollbars( 1, 1, 1, 1 )
            self.sizer.ctrl.SetSizeHints(self.ctrl)
            #end
            self.ctrl.Layout()
        elif self.style == 'collapsible':
            self.ctrl = wx.CollapsiblePane( parent, wx.ID_ANY, self.label, wx.DefaultPosition, wx.DefaultSize, wx.CP_DEFAULT_STYLE|wx.CP_NO_TLW_RESIZE )
            pane = self.ctrl.GetPane()
            self.sizer = makeLayout(self.layout,pane)
            pane.SetSizer( self.sizer.ctrl )
            self.ctrl.Expand()
            self.sizer.ctrl.SetSizeHints(pane)
            pane.Layout()

class ScrolledPanel(Panel):
    def __init__(self,layout,parent=None,create=False,expand=False,proportion=0,size=wx.DefaultSize,pos=wx.DefaultPosition,label="",key=None):
        super().__init__(layout,parent=parent,create=create,expand=expand,proportion=proportion,size=size,pos=pos,label=label,style='scroll',key=key)

class CollapsiblePanel(Panel):
    def __init__(self,layout,parent=None,create=False,expand=False,proportion=0,size=wx.DefaultSize,pos=wx.DefaultPosition,label="",key=None):
        super().__init__(layout,parent=parent,create=create,expand=expand,proportion=proportion,size=size,pos=pos,label=label,style='collapsible',key=key)

##class Scroll(Control): #TODO: Change ScrolledWindow -> ScrolledPane
##    def __init__(self,layout,parent=None,create=False,horizontal=True,expand=False,proportion=0,key=None):
##        super().__init__(key,expand,proportion)
##        self.layout = layout
##        if create is True and parent is not None:
##            self.create(parent)
##    def create(self,parent):
##        self.ctrl = wx.ScrolledWindow( parent, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize,  wx.HSCROLL|wx.VSCROLL  )
##        #self.ctrl.EnableScrolling(True,True)
##        #self.ctrl.SetAutoLayout(1)
##        #self.ctrl.ShowScrollbars( True, True )
##        self.sizer = makeLayout(self.layout,self.ctrl)
##        self.ctrl.SetSizer( self.sizer.ctrl )
##        width = self.ctrl.GetBestSize().width
##        height = self.ctrl.GetBestSize().height
##        self.ctrl.SetSize((width, height))
##        self.ctrl.SetScrollbars( 1, 1, 1, 1 )
##        #self.ctrl.SetScrollRate( 5, 5 )
##        #panel = Panel(self.layout, self.ctrl, create=True)
##        #self.ctrl.SetSizer( wrapSizer(panel.ctrl) )
##        self.ctrl.Layout()

class Spliter(Control):
    def __init__(self,layouts,parent=None,create=False,style='vertical',expand=False,proportion=0,border=2,size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.layouts = layouts #left(top),right(bottom)
        self.style = style
        if create is True and parent is not None:
            self.create(parent)
    def create(self,parent):
        self.ctrl = wx.SplitterWindow( parent, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.SP_3D )
        self.sashpos = 0
        self.panels = []
        for layout in self.layouts:
            if type(layout) is int:
                self.sashpos = layout
            else:
                self.panels.append(Panel(layout, self.ctrl, create=True))
        if self.style == 'vertical':
            self.ctrl.SplitVertically( self.panels[0].ctrl, self.panels[1].ctrl, self.sashpos )
        else:
            self.ctrl.SplitHorizontally( self.panels[0].ctrl, self.panels[1].ctrl, self.sashpos )

class VerticalSpliter(Spliter):
    def __init__(self,layouts,parent=None,create=False,expand=False,proportion=0,border=2,size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(layouts,parent=parent,create=create,style='vertical',expand=expand,proportion=proportion,border=border,size=size,pos=pos,key=key)

class HorizontalSpliter(Spliter):
    def __init__(self,layouts,parent=None,create=False,expand=False,proportion=0,border=2,size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(layouts,parent=parent,create=create,style='horizontal',expand=expand,proportion=proportion,border=border,size=size,pos=pos,key=key)

class MultiSpliter(Control):
    import wx.lib.splitter
    def __init__(self,layouts,parent=None,create=False,style='vertical',expand=False,proportion=0,border=2,size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.layouts = layouts #left(top),right(bottom)
        self.style = style
        if create is True and parent is not None:
            self.create(parent)
    def create(self,parent):
        self.ctrl = wx.lib.splitter.MultiSplitterWindow( parent, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 )
        self.sashpos = []
        self.panels = []
        for layout in self.layouts:
            if type(layout) is int:
                self.sashpos.append(layout)
            else:
                self.panels.append(Panel(layout, self.ctrl, create=True))
        if self.style == 'vertical': # reverted concept compared with Splitter
            self.ctrl.SetOrientation(wx.HORIZONTAL)
        else:
            self.ctrl.SetOrientation(wx.VERTICAL)
        for i in range(len(self.panels)):
            self.ctrl.AppendWindow(self.panels[i].ctrl, self.sashpos[i])

class VerticalMultiSpliter(MultiSpliter):
    def __init__(self,layouts,parent=None,create=False,expand=False,proportion=0,border=2,size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(layouts,parent=parent,create=create,style='vertical',expand=expand,proportion=proportion,border=border,size=size,pos=pos,key=key)

class HorizontalMultiSpliter(MultiSpliter):
    def __init__(self,layouts,parent=None,create=False,expand=False,proportion=0,border=2,size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(layouts,parent=parent,create=create,style='horizontal',expand=expand,proportion=proportion,border=border,size=size,pos=pos,key=key)


######################################################################
# Controls
######################################################################

class FileDrop(wx.FileDropTarget):
    def __init__(self, window):
        wx.FileDropTarget.__init__(self)
        self.window = window
    def OnDropFiles(self, x, y, filenames):
        self.window.drop_handle(filenames)
        return True

class Bitmap(Control):
    def __init__(self,filename=None,bitmap=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None,tooltip=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos,tooltip=tooltip)
        self.bitmap = bitmap
        self.filename = filename
    def create(self,parent):
        flags = wx.ALIGN_CENTER
        if self.filename is not None:
            self.bitmap = wx.Bitmap( self.filename, wx.BITMAP_TYPE_ANY )
        self.ctrl = wx.StaticBitmap( parent, wx.ID_ANY, self.bitmap, self.pos, self.size, 0|flags )
        self.ctrl.Bind( wx.EVT_SIZE, self.onEvtBitmapSize )
        if self.key is not None:
            registerCtrl( self.key, self )
    def onEvtBitmapSize(self,event):
        #print("onEvtBitmapSize()",event.GetSize()) #(width, height)
        event.Skip()
    #TODO: getValue,setValue check

class Button(Control):
    def __init__(self,label="",handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None,tooltip=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos,tooltip=tooltip)
        self.label = label
        self.handler = handler
    def create(self,parent):
        id = getId()
        if type(self.label) is str:
            self.ctrl = wx.Button( parent, id, self.label, self.pos, self.size, 0 )
        else:
            self.ctrl = wx.BitmapButton( parent, id, getButtonBitmap(self.label), self.pos, self.size, 0 )
        if self.handler:
            self.ctrl.Bind( wx.EVT_BUTTON, self.handler, id=id )
        if self.tooltip:
            self.ctrl.SetToolTip(wx.ToolTip(self.tooltip))
        if self.key:
            registerCtrl( self.key, self )
    def getValue(self):
        pass
    def setValue(self,value):
        pass
    def clearValue(self):
        pass
    def appendValue(self,value):
        pass
    def removeValue(self,value):
        pass  

class Calendar(Control):
    def __init__(self,handler=None,date=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.date = date
        self.handler = handler
    def create(self,parent):
        self.ctrl = wx.adv.CalendarCtrl( parent, wx.ID_ANY, wx.DefaultDateTime, self.pos, self.size, wx.adv.TP_DEFAULT )
        self.ctrl.Bind( wx.adv.EVT_CALENDAR, self.handler ) #double click
        self.ctrl.Bind( wx.adv.EVT_CALENDAR_SEL_CHANGED, self.handler )
        if self.key is not None:
            registerCtrl( self.key, self )
    #TODO: getValue,setValue check

class CheckButton(Control):
    def __init__(self,label="",value=None,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None,tooltip=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos,tooltip=tooltip)
        self.label = label
        self.handler = handler
        self.value = value
    def create(self,parent):
        id = getId()
        self.ctrl = wx.CheckBox( parent, id, self.label, self.pos, self.size, 0 )
        self.ctrl.Bind( wx.EVT_CHECKBOX, self.handler, id=id )
        if self.value is not None:
            self.setValue(self.value)
        if self.tooltip is not None:
            self.ctrl.SetToolTip(wx.ToolTip(self.tooltip))
        if self.key is not None:
            registerCtrl( self.key, self )
    def clearValue(self):
        pass
    def appendValue(self,value):
        pass
    def removeValue(self,value):
        pass  
    def castValue(self,value):
        return bool(value)
        
class Check(CheckButton):
    def __init__(self,label="",value=None,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None,tooltip=None):
        super().__init__(label,value,handler,expand,proportion,border,size,pos,key,tooltip)

class Choice(Control):
    def __init__(self,choices=[],select=0,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.choices = choices
        self.select = select
        self.handler = handler
    def create(self,parent):
        id = getId()
        self.ctrl = wx.Choice( parent, id, self.pos, self.size, self.choices, 0 )
        self.ctrl.SetSelection(self.select)
        self.ctrl.Bind( wx.EVT_CHOICE, self.handler, id=id )
        if self.key is not None:
            registerCtrl( self.key, self )
    def getValue(self,):
        return self.ctrl.GetString(self.ctrl.GetCurrentSelection())
    def setValue(self,value):
        n = self.ctrl.FindString(value)
        if n != wx.NOT_FOUND:
            self.ctrl.SetSelection(n)

class Clock(Control):
    import wx.lib.analogclock
    def __init__(self,handler=None,date=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.date = date
        self.handler = handler
    def create(self,parent):
        self.ctrl = wx.lib.analogclock.analogclock.AnalogClock( parent, wx.ID_ANY, self.pos, self.size, wx.NO_BORDER)
        if self.key is not None:
            registerCtrl( self.key, self )
    #TODO: getValue,setValue check

class Combo(Control):
    def __init__(self,choices=[],value=None,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.choices = choices
        self.value = value
        self.handler = handler
    def create(self,parent):
        id = getId()
        if self.value is None:
            self.value = self.choices[0]
        self.ctrl = wx.ComboBox( parent, id, self.value, self.pos, self.size, self.choices, 0 )
        #self.ctrl.SetValue(self.value)
        self.ctrl.Bind( wx.EVT_COMBOBOX, self.handler, id=id )
        if self.key is not None:
            registerCtrl( self.key, self )

class Date(Control):
    def __init__(self,date=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.date = date
    def create(self,parent):
        self.ctrl = wx.adv.DatePickerCtrl( parent, wx.ID_ANY, wx.DefaultDateTime, self.pos, self.size, wx.adv.TP_DEFAULT )
        if self.key is not None:
            registerCtrl( self.key, self )
    #TODO: getValue,setValue check

class Gauge(Control): #842
    def __init__(self,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
    def create(self,parent):
        self.ctrl = wx.Gauge(parent=parent,pos=self.pos,size=self.size)
        if self.key is not None:
            registerCtrl( self.key, self )
    def setMaxValue(self,maxValue):
        self.ctrl.SetRange(maxValue)
    def update(self,percent):
        wx.CallAfter(self.updateAfter, percent)
    def updateAfter(self,percent):
        self.ctrl.SetValue(percent)
    def pulse(self):
        wx.CallAfter(self.pulseAfter)
    def pulseAfter(self):
        self.ctrl.Pulse()
    #TODO: getValue,setValue check

class Label(Control):
    def __init__(self,text="",expand=False,proportion=0,border=2,multiline=False,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None,tooltip=None,align='center'):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos,tooltip=tooltip)
        self.text = text
        self.multiline = multiline
        self.align = align
    def create(self,parent):
        flags = wx.ALIGN_CENTER 
        if self.align == 'left': flags = wx.ALIGN_LEFT
        if self.align == 'right': flags = wx.ALIGN_RIGHT
        flags |= wx.ALIGN_CENTER_VERTICAL
        if self.multiline == True: flags |= wx.TE_MULTILINE
        self.ctrl = wx.StaticText( parent, wx.ID_ANY, self.text, self.pos, self.size, 0|flags )
        if self.tooltip is not None:
            self.ctrl.SetToolTip(wx.ToolTip(self.tooltip))
        if self.key is not None:
            registerCtrl( self.key, self )
    def getValue(self):
        return self.ctrl.GetLabel()
    def setValue(self,item):
        self.ctrl.SetLabel(item)
    def clearValue(self):
        pass
    def appendValue(self,value):
        pass
    def removeValue(self,value):
        pass

class LedNumber(Control):
    import wx.lib.gizmos.ledctrl
    def __init__(self,text="",expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.text = text
    def create(self,parent):
        flags = wx.lib.gizmos.ledctrl.LED_ALIGN_LEFT|wx.lib.gizmos.ledctrl.LED_DRAW_FADED
        self.ctrl = wx.lib.gizmos.ledctrl.LEDNumberCtrl( parent, wx.ID_ANY, self.pos, self.size, flags )
        self.ctrl.SetValue(self.text)
        if self.key is not None:
            registerCtrl( self.key, self )
    #TODO: getValue,setValue check

class Line(Control):
    def __init__(self,text="",expand=False,proportion=0,border=2,style="horizontal",
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.style = style
    def create(self,parent):
        flags = wx.LI_HORIZONTAL if self.style == "horizontal" else wx.LI_VERTICAL
        self.ctrl = wx.StaticLine( parent, wx.ID_ANY, self.pos, self.size, 0|flags )
        if self.key is not None:
            registerCtrl( self.key, self )
    #TODO: getValue,setValue check

class Link(Control):
    def __init__(self,text="",url="",expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None,tooltip=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos,tooltip=tooltip)
        self.text = text
        self.url = url
    def create(self,parent):
        self.ctrl = wx.adv.HyperlinkCtrl( parent, wx.ID_ANY, self.text, self.url, self.pos, self.size)
        if self.tooltip is not None:
            self.ctrl.SetToolTip(wx.ToolTip(self.tooltip))
        if self.key is not None:
            registerCtrl( self.key, self )
    #TODO: getValue,setValue check

class List(Control):
    def __init__(self,choices=[],select=0,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,check=False,label="",style=None,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.choices = choices
        self.select = select
        self.handler = handler
        self.check = check
        self.label = label
        self.style = style
    def create(self,parent):
        import sys
        id = getId()
        if self.style is None:
            if self.check is True:
                self.ctrl = wx.CheckListBox( parent, id, self.pos, self.size, self.choices, 0 )
            else:
                self.ctrl = wx.ListBox( parent, id, self.pos, self.size, self.choices, 0 )
            if self.select < len(self.choices):
                self.ctrl.SetSelection(self.select)
            self.ctrl.SetDropTarget(FileDrop(self))
            self.ctrl.Bind( wx.EVT_LISTBOX, self.handler, id=id )
        elif self.style == 'multicol':
            self.ctrl = wx.ListCtrl(parent, id, style = wx.LC_REPORT)
            widths = []
            if len(self.choices) > 1:
                aligns = (wx.LIST_FORMAT_LEFT, wx.LIST_FORMAT_CENTER, wx.LIST_FORMAT_RIGHT)
                cols = len(self.choices[0])
                for col in range(cols):
                    label = self.choices[0][col][0]
                    width = self.choices[0][col][1]
                    align = aligns[self.choices[0][col][2]+1]
                    self.ctrl.AppendColumn(label, align, width)
                    #self.ctrl.InsertColumn(col, label, align, width)
                for row in range(1,len(self.choices)):
                    self.ctrl.Append(self.choices[row])
        elif self.style == 'edit':
            self.ctrl = wx.adv.EditableListBox( parent, id, self.label, self.pos, self.size, 0 )
            #TODO:
        if self.key is not None:
            registerCtrl( self.key, self )
    def drop_handle(self,filenames):
        for filename in filenames:
            self.ctrl.Append(filename)
    def getValue(self,):
        return self.ctrl.GetString(self.ctrl.GetSelection())
    def setValue(self,item):
        n = self.ctrl.FindString(item)
        if n != wx.NOT_FOUND:
            self.ctrl.SetSelection(n)

class Picker(Control):
    def __init__(self,style="",value=None,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.style = style
        self.value = value
        self.handler = handler
    def create(self,parent):
        id = getId()
        if self.style == 'dir': #value: path str
            self.value = "" if self.value is None else self.value
            self.ctrl = wx.DirPickerCtrl( parent, id, self.value, pos=self.pos, size=self.size, style=wx.DIRP_DEFAULT_STYLE )
            self.ctrl.Bind( wx.EVT_DIRPICKER_CHANGED, self.handler, id=id )
        elif self.style == 'file':
            self.value = "" if self.value is None else self.value
            self.ctrl = wx.FilePickerCtrl( parent, id, self.value, pos=self.pos, size=self.size, style=wx.FLP_DEFAULT_STYLE )
            self.ctrl.Bind( wx.EVT_FILEPICKER_CHANGED, self.handler, id=id )
        elif self.style == 'color':
            self.value = wx.BLACK if self.value is None else self.value
            self.ctrl = wx.ColourPickerCtrl( parent, id, self.value, pos=self.pos, size=self.size, style=wx.CLRP_DEFAULT_STYLE )
            self.ctrl.Bind( wx.EVT_COLOURPICKER_CHANGED, self.handler, id=id )
        elif self.style == 'font':
            self.value = wx.NullFont if self.value is None else self.value
            self.ctrl = wx.FontPickerCtrl( parent, id, self.value, pos=self.pos, size=self.size, style=wx.FNTP_DEFAULT_STYLE )
            self.ctrl.Bind( wx.EVT_FONTPICKER_CHANGED, self.handler, id=id )
        elif self.style == 'date':
            self.value = wx.DefaultDateTime if self.value is None else self.value
            self.ctrl = wx.adv.DatePickerCtrl( parent, id, self.value, pos=self.pos, size=self.size, style=wx.adv.TP_DEFAULT )
            self.ctrl.Bind( wx.adv.EVT_DATE_CHANGED, self.handler, id=id )
        elif self.style == 'time':
            self.value = wx.DefaultDateTime if self.value is None else self.value
            self.ctrl = wx.adv.TimePickerCtrl( parent, id, self.value, pos=self.pos, size=self.size, style=wx.adv.TP_DEFAULT )
            self.ctrl.Bind( wx.adv.EVT_TIME_CHANGED, self.handler, id=id )
        else: #TODO: throw exception
            pass
        if self.key is not None:
            registerCtrl( self.key, self )
    #TODO: getValue,setValue check

class DirPicker(Picker):
    def __init__(self,style="",value=None,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__('dir',value,handler,expand,proportion,border,size,pos,key)

class FilePicker(Picker):
    def __init__(self,style="",value=None,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__('file',value,handler,expand,proportion,border,size,pos,key)

class ColorPicker(Picker):
    def __init__(self,style="",value=None,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__('color',value,handler,expand,proportion,border,size,pos,key)

class FontPicker(Picker):
    def __init__(self,style="",value=None,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__('font',value,handler,expand,proportion,border,size,pos,key)

class DatePicker(Picker):
    def __init__(self,style="",value=None,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__('date',value,handler,expand,proportion,border,size,pos,key)

class TimePicker(Picker):
    def __init__(self,style="",value=None,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__('time',value,handler,expand,proportion,border,size,pos,key)

class Progress(Control):
    import wx.lib.progressindicator as pi
    def __init__(self,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
    def create(self,parent):
        self.ctrl = wx.lib.progressindicator.ProgressIndicator(parent=parent,pos=self.pos,size=self.size)
        if self.key is not None:
            registerCtrl( self.key, self )
    def setMaxValue(self,maxValue):
        self.ctrl.SetRange(maxValue)
    def update(self,percent):
        wx.CallAfter(self.callAfter, percent)
    def callAfter(self,percent):
        self.ctrl.SetValue(percent)
    #TODO: getValue,setValue check

class Radio(Control):
    def __init__(self,label="",choices=[],value="",handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,style='row',key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.label = label
        self.choices = choices
        self.value = value
        self.handler = handler
        self.style = wx.RA_SPECIFY_ROWS if style == 'row' else wx.RA_SPECIFY_COLS
    def create(self,parent):
        id = getId()
        self.ctrl = wx.RadioBox( parent, id, self.label, self.pos, self.size, self.choices, 0, self.style )
        self.ctrl.Bind( wx.EVT_RADIOBOX, self.handler, id=id )
        for i in range(len(self.choices)):
            if self.value == self.choices[i]:
                self.ctrl.SetSelection(i)
                break
        if self.key is not None:
            registerCtrl( self.key, self )
    #TODO: getValue,setValue check

class Slider(Control):
    def __init__(self,text="",value=0,minValue=0,maxValue=100,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,style="horizontal",key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.value = value
        self.minValue = minValue
        self.maxValue = maxValue
        self.handler = handler
        self.style = style
    def create(self,parent):
        id = getId()
        flags = wx.SL_HORIZONTAL if self.style == "horizontal" else wx.SL_VERTICAL
        self.ctrl = wx.Slider( parent, id, self.value, self.minValue, self.maxValue, self.pos, self.size, 0|flags )
        self.ctrl.Bind( wx.EVT_SLIDER, self.handler, id=id )
        if self.key is not None:
            registerCtrl( self.key, self )
    #TODO: getValue,setValue check

class Spin(Control):
    def __init__(self,text="",value="",minValue=0,maxValue=100,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.value = str(value)
        self.minValue = minValue
        self.maxValue = maxValue
        self.handler = handler
    def create(self,parent):
        id = getId()
        flags = wx.SP_ARROW_KEYS
        self.ctrl = wx.SpinCtrl( parent, id, self.value, self.pos, self.size, 0|flags, self.minValue, self.maxValue )
        self.ctrl.Bind( wx.EVT_SPIN, self.handler, id=id )
        if self.key is not None:
            registerCtrl( self.key, self )
    #TODO: getValue,setValue check

class StyledText(Control):
    import wx.stc
    def __init__(self,text="",handler=None,expand=True,proportion=1,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.text = text
        self.handler = handler        
    def create(self,parent):
        flags = 0
        self.ctrl = wx.stc.StyledTextCtrl( parent, wx.ID_ANY, self.pos, self.size, 0|flags )
        self.enableLineNumber()
        self.ctrl.SetText(self.text)
        drop_target = FileDrop(self)
        self.ctrl.SetDropTarget(drop_target)
        if self.key is not None:
            registerCtrl( self.key, self )
    def drop_handle(self,filenames):
        for filename in filenames:
            self.ctrl.AppendText( filename + '\n' )
    def enableLineNumber(self):
        #self.stc.SetProperty("fold", "1")
        #self.stc.SetProperty("fold.html", "1")
        self.ctrl.SetMargins(0, 0)
        self.ctrl.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER)
        self.ctrl.SetMarginMask(2, wx.stc.STC_MASK_FOLDERS)
        self.ctrl.SetMarginSensitive(2, True)
        self.ctrl.SetMarginWidth(1, 32) # 2,25
        self.ctrl.SetMarginWidth(2, 16) # 2,25
    #TODO: getValue,setValue check

class Text(Control):
    def __init__(self,text="",handler=None,expand=True,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,
                 multiline=False,password=False,readonly=False,wrap=True,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.text = text
        self.multiline = multiline
        self.password = password
        self.readonly = readonly
        self.wrap = wrap
        self.handler = handler
        #self.expand = True if multiline == True else False
    def create(self,parent):
        id = getId()
        flags = 0
        flags |= wx.TE_MULTILINE if self.multiline is True else 0
        flags |= wx.TE_PASSWORD if self.password is True else 0
        flags |= wx.TE_READONLY if self.readonly is True else 0
        flags |= wx.TE_DONTWRAP if self.wrap is False else 0
        self.ctrl = wx.TextCtrl( parent, id, self.text, self.pos, self.size, 0|flags )
        self.ctrl.Bind( wx.EVT_TEXT, self.handler, id=id )
        #self.ctrl.Bind( wx.EVT_CHAR, self.handler )
        drop_target = FileDrop(self)
        self.ctrl.SetDropTarget(drop_target)
        if self.key is not None:
            registerCtrl( self.key, self )
    def drop_handle(self,filenames):
        for filename in filenames:
            self.ctrl.AppendText( filename )
            if self.multiline is False:
                break
            self.ctrl.AppendText( '\n' )
    def appendValue(self,value):
        self.ctrl.AppendText(value)
        
class Ticker(Control):
    import wx.lib.ticker
    def __init__(self,text="",fgcolor=wx.BLACK,bgcolor=wx.WHITE,expand=True,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.text = text
        self.fgcolor = fgcolor
        self.bgcolor = bgcolor
    def create(self,parent):
        self.ctrl = wx.lib.ticker.Ticker( parent, wx.ID_ANY, self.text, self.fgcolor, self.bgcolor, True, pos=self.pos, size=self.size, style=wx.NO_BORDER )
        self.ctrl.Bind(wx.EVT_CLOSE, self.onClose)
        if self.key is not None:
            registerCtrl( self.key, self )
    def onClose(self,event):
        self.ctrl.Stop()
        event.Skip()
    #TODO: getValue,setValue check

class Time(Control):
    def __init__(self,date=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.date = date
    def create(self,parent):
        self.ctrl = wx.adv.TimePickerCtrl( parent, wx.ID_ANY, wx.DefaultDateTime, self.pos, self.size, wx.adv.TP_DEFAULT )
        if self.key is not None:
            registerCtrl( self.key, self )
    #TODO: getValue,setValue check

class ToggleButton(Control):
    def __init__(self,label="",value=None,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None,tooltip=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos,tooltip=tooltip)
        self.label = label
        self.value = value
        self.handler = handler
    def create(self,parent):
        id = getId()
        if type(self.label) is str:
            self.ctrl = wx.ToggleButton( parent, id, self.label, self.pos, self.size, 0 )
            self.ctrl.Bind( wx.EVT_TOGGLEBUTTON, self.handler, id=id )
        else: #byte[]
            self.ctrl = wx.BitmapToggleButton( parent, id, getButtonBitmap(self.label), self.pos, self.size, 0 ) 
            self.ctrl.Bind( wx.EVT_TOGGLEBUTTON, self.handler, id=id )
        if self.value is not None:
            self.setValue(self.value)
        if self.tooltip is not None:
            self.ctrl.SetToolTip(wx.ToolTip(self.tooltip))
        if self.key is not None:
            registerCtrl( self.key, self )
    def clearValue(self):
        pass
    def appendValue(self,value):
        pass
    def removeValue(self,value):
        pass  
    def castValue(self,value):
        return bool(value)

class Tree(Control):
    def __init__(self,data=None,collapse=False,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.data = data
        self.collapse = collapse
        self.handler = handler
    def create(self,parent):
        id = getId()
        self.ctrl = wx.TreeCtrl( parent, id, self.pos, self.size, wx.TR_DEFAULT_STYLE )
        self.ctrl.Bind( wx.EVT_TREE_SEL_CHANGED, self.handler, id=id )
        if self.data is not None:
            root = self.ctrl.AddRoot(self.data[0])
            if type(self.data[1]) is list:
                self.addItems(root,self.data[1])
            if self.collapse is not True:
                self.ctrl.ExpandAllChildren(root)
        if self.key is not None:
            registerCtrl( self.key, self )
    def addItems(self,parent,data):
        node = None
        for item in data:
            if type(item) is list and node is not None:
                self.addItems(node,item)
            else: #list
                node = self.ctrl.AppendItem(parent,item)
    #TODO: getValue,setValue check

class Web(Control):
    import wx.lib.iewin
    def __init__(self,url=None,engine='ie',expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.url = url
        self.engine = engine
    def create(self,parent):
        if self.engine == 'ie':
            self.ctrl = wx.lib.iewin.IEHtmlWindow( parent, wx.ID_ANY, self.pos, self.size, 0 )
            if self.url is not None:
                self.ctrl.LoadUrl(self.url)
            if self.key is not None:
                registerCtrl( self.key, self )
    #TODO: getValue,setValue check

class PdfWin(Control):
    import wx.lib.pdfwin
    def __init__(self,url=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.url = url
    def create(self,parent):
        self.ctrl = wx.lib.pdfwin.PDFWindow( parent, wx.ID_ANY, self.pos, self.size, 0 )
        if self.url is not None:
            self.ctrl.LoadFile(self.url)
        if self.key is not None:
            registerCtrl( self.key, self )
    #TODO: getValue,setValue check

class PdfView(Control):
    import wx.lib.pdfviewer
    def __init__(self,url=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.url = url
    def create(self,parent):
        self.ctrl = wx.lib.pdfviewer.pdfViewer( parent, wx.ID_ANY, self.pos, self.size, wx.HSCROLL|wx.VSCROLL|wx.SUNKEN_BORDER )
        #self.ctrl.SetSizerProps(expand=True, proportion=1)
        #self.buttonpanel = wx.lib.pdfviewer.pdfButtonPanel(parent, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0)
        #self.buttonpanel.SetSizerProps(expand=True)
        #self.buttonpanel.viewer = self.ctrl
        #self.ctrl.buttonpanel = self.buttonpanel            
        if self.url is not None:
            self.ctrl.LoadFile(self.url)
        if self.key is not None:
            registerCtrl( self.key, self )
    #TODO: getValue,setValue check

class Media(Control):
    import wx.media
    def __init__(self,url=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.url = url
    def create(self,parent):
        self.ctrl = wx.media.MediaCtrl( parent, wx.ID_ANY, szBackend=wx.media.MEDIABACKEND_WMP10, pos=self.pos, size=self.size )
        self.ctrl.Bind(wx.media.EVT_MEDIA_LOADED, self.onLoaded)
        if self.url is not None:
            self.ctrl.Load(self.url)
        if self.key is not None:
            registerCtrl( self.key, self )
    def onLoaded(self,event):
        self.ctrl.Play()
    #TODO: getValue,setValue check

######################################################################
# Clipboard
######################################################################
def GetClipboardText():
    if not wx.TheClipboard.IsOpened():
        do = wx.TextDataObject()
        wx.TheClipboard.Open()
        success = wx.TheClipboard.GetData(do)
        wx.TheClipboard.Close()
        if success:
            return do.GetText()
    return ''
    
def GetClipboardHtmlText():
    if not wx.TheClipboard.IsOpened():
        do = wx.HTMLDataObject()
        wx.TheClipboard.Open()
        success = wx.TheClipboard.GetData(do)
        wx.TheClipboard.Close()
        if success:
            return do.GetHTML()
    return 'No Html Data'
    
def GetClipboardFilenames():
    if not wx.TheClipboard.IsOpened():
        do = wx.FileDataObject()
        wx.TheClipboard.Open()
        success = wx.TheClipboard.GetData(do)
        wx.TheClipboard.Close()
        if success:
            return do.Filenames
    return []
    
    
######################################################################
# Compound Control
######################################################################
class Toolbar(Control):
    def __init__(self,tool_def, largeButton=False,expand=False,proportion=0,border=2,size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.ctrl = None
        self.tool_def = tool_def
        self.largeButton = largeButton
    def create(self, parent):  #icon, text, handler
        flags = wx.TB_FLAT|wx.TB_HORIZONTAL
        if len(self.tool_def[0]) >= 3:
            flags |= wx.TB_TEXT
        self.ctrl = wx.ToolBar( parent, wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=flags)
        for value in self.tool_def:
            if value[0] is None:
                self.ctrl.AddSeparator()
            else:
                text = handler = tooltip = None
                if len(value) >= 2:
                    handler = value[1]
                if len(value) >= 3:
                    text = value[2]
                if len(value) >= 4:
                    tooltip = value[3]
                if self.largeButton: 
                    icon = getToolbarBitmap(value[0],size=(32,32))
                else:
                    icon = getToolbarBitmap(value[0],size=(24,24))
                id = getId()
                if text is not None:
                    tool = self.ctrl.AddTool( id, text, icon, wx.NullBitmap, wx.ITEM_NORMAL, wx.EmptyString, wx.EmptyString, None )
                else:
                    tool = self.ctrl.AddTool( id, '', icon, wx.NullBitmap, wx.ITEM_NORMAL, wx.EmptyString, wx.EmptyString, None )
                    #tool = self.ctrl.AddSimpleTool( id, icon, wx.EmptyString, wx.EmptyString, None )
                if tooltip is not None:
                    self.ctrl.SetToolShortHelp(id, tooltip);
                if handler is None:
                    tool.Enable( False )
                else:
                    self.ctrl.Bind( wx.EVT_TOOL, handler, id = id )
        self.ctrl.Realize()
    def getValue(self):
        pass
    def setValue(self,item):
        pass
    def clearValue(self):
        pass
    def appendValue(self,value):
        pass
    def removeValue(self,value):
        pass
        
class FileBrowser(Control): 
    def __init__(self,label=None,text=None,buttonText="Browse",handler=None,save=False,directory=False,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.ctrl = None
        self.layout = [[]]
        self.label = label
        self.text = text
        self.buttonText = buttonText
        self.handler = handler
        self.save = save
        self.directory = directory
    def create(self,parent):
        self.textCtrl = Text(self.text, expand=True, proportion=1, border=2)
        self.buttonCtrl = Button(self.buttonText, handler=self.onBrowse, border=2 )
        if self.label: 
            self.layout[0].append( Label(self.label, border=2) )
        self.layout[0].append( self.textCtrl )
        self.layout[0].append( self.buttonCtrl )
        self.layout[0].append( { 'expand' : True, 'border' : 0 } )
        vbox = makeLayout(self.layout,parent)
        self.ctrl = vbox.ctrl
        if self.key is not None:
            registerCtrl( self.key, self.textCtrl )
    def onBrowse(self,event):
        if self.directory:
            f = DirectoryDialog(defaultPath=self.text)
        else:
            f = OpenFileDialog(defaultDir=self.text, save=self.save)
        if f is not None:
            self.textCtrl.ctrl.Clear()
            self.textCtrl.ctrl.AppendText(f)
            if self.handler: self.handler(f)
    def getValue(self):
        pass
    def setValue(self,item):
        pass
    def clearValue(self):
        pass
    def appendValue(self,value):
        pass
    def removeValue(self,value):
        pass
        
class DirectoryBrowser(FileBrowser):
    def __init__(self,label=None,text=None,buttonText="Browse",handler=None,save=False,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(label=label,text=text,buttonText=buttonText,handler=handler,save=save,directory=True,expand=expand,proportion=proportion,border=border,
                    size=size,pos=pos,key=key)
        
class ToolbarText(Control): 
    def __init__(self,tool_def=None,text='',largeButton=False,multiline=True,handler=None,expand=False,proportion=0,border=2,
                 size=wx.DefaultSize,pos=wx.DefaultPosition,key=None):
        super().__init__(key=key,expand=expand,proportion=proportion,border=border,size=size,pos=pos)
        self.ctrl = None
        self.layout = [[], []] #toolbar, text
        self.tool_def = tool_def
        self.text = text
        self.largeButton = largeButton
        self.multiline = multiline
        self.handler = handler
    def create(self,parent):
        if self.tool_def is None:
            self.largeButton = False
            self.tool_def = [
                [wx.ART_NEW  , self.onClear     , None, "Clear all text"],
                [wx.ART_COPY , self.onCopy      , None, "Copy text to clipboard"],
                [wx.ART_PASTE, self.onPaste     , None, "Paste text from clipboard"],
                [wx.ART_PASTE, self.onPasteHtml , None, "Paste html text from clipboard"],
            ]
        self.toolbar = Toolbar(self.tool_def,self.largeButton)
        self.textCtrl = Text(self.text, multiline=self.multiline, expand=True, proportion=1, border=0)
        self.layout[0].append( self.toolbar )
        self.layout[0].append( { 'expand' : True, 'border' : 0 } )
        self.layout[1].append( self.textCtrl )
        self.layout[1].append( { 'expand' : True, 'proportion' : 1, 'border' : 0 } )
        vbox = makeLayout(self.layout,parent)
        self.ctrl = vbox.ctrl
        if self.key is not None:
            registerCtrl( self.key, self.textCtrl )
    def onClear(self,event):
        self.textCtrl.ctrl.Clear()
    def onCopy(self,event):
        self.textCtrl.ctrl.Copy()
    def onPaste(self,event):
        self.textCtrl.ctrl.Paste()
    def onPasteHtml(self,event):
        self.textCtrl.ctrl.AppendText(GetClipboardHtmlText())

                
######################################################################
# Dialogs : deprecated use wxApp.*
######################################################################

def OpenFileDialog(defaultDir="",multiple=False,save=False):
    if not defaultDir: defaultDir = ''
    style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST if save is False else wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT
    style |= wx.FD_MULTIPLE if multiple is True else 0
    dlg = wx.FileDialog(None,defaultDir=defaultDir,style=style)
    rv = dlg.ShowModal()
    if rv == wx.ID_OK:
        if multiple == True:
            files = []
            for file in dlg.GetFilenames():
                files.append( os.path.join(dlg.GetDirectory(), file) )
            return files
        else:
            return os.path.join(dlg.GetDirectory(), dlg.GetFilename())
    else:
        return None

def SaveFileDialog(defaultDir=""):
    return OpenFileDialog(defaultDir=defaultDir, multiple=False, save=True)

def DirectoryDialog(defaultPath=""):
    dlg = wx.DirDialog(None,defaultPath=defaultPath)
    rv = dlg.ShowModal()
    if rv == wx.ID_OK:
        return dlg.GetPath()
    else:
        return None

def MessageBox(title,message):
    dlg = wx.MessageDialog(None, message, caption=title, style=wx.OK|wx.CENTER, pos=wx.DefaultPosition)
    dlg.ShowModal()

def MessageYesNo(title,message):
    dlg = wx.MessageDialog(None, message, caption=title, style=wx.YES|wx.NO|wx.CENTER, pos=wx.DefaultPosition)
    rv = dlg.ShowModal()
    if rv == wx.ID_OK or rv == wx.ID_YES:
        return True
    else: #wx.ID_CANCEL, wx.ID_NO
        return False

def MessageYesNoCancel(title,message):
    dlg = wx.MessageDialog(None, message, caption=title, style=wx.YES|wx.NO|wx.CANCEL|wx.CENTER, pos=wx.DefaultPosition)
    rv = dlg.ShowModal()
    if rv == wx.ID_OK or rv == wx.ID_YES:
        return True
    elif rv == wx.ID_NO:
        return False
    else: #wx.ID_CANCEL,
        return None

def ProgressDialog(title,message,maxValue=100):
    dlg = wx.ProgressDialog(title, message, maximum=100, parent=None, style=wx.PD_APP_MODAL|wx.PD_AUTO_HIDE)
    return dlg

def _onProgressDialog(dlg,percent):
    dlg.Update(percent)

def ProgressDialogUpdate(dlg,percent):
    wx.CallAfter(_onProgressDialog, dlg, percent)
    
def progressDialogUpdate(dlg,percent): #deprecated
    wx.CallAfter(_onProgressDialog, dlg, percent)

def CalendarDialog(parent=None,year=None,month=None,day=None):
    dlg = wx.lib.CalenDlg(parent,month,day,year)
    #TODO

class _process(wx.Process):
    def __init__(self,event_id,handler=None):
        super().__init__()
        self.event_id = event_id
        self.handler = handler
        self.Redirect()
    def OnTerminate(self,pid,status):
        print( pid, status )
        if self.handler is not None:
            self.handler(self.event_id,status)
    
def Execute(command,sync=False,show=False): #TODO
    #process = _process(event_id,handler)
    flags = 0
    if sync is True: 
        flags |= wx.EXEC_SYNC 
    else: 
        flags |= wx.EXEC_ASYNC
    if show is True: 
        flags |= wx.EXEC_SHOW_CONSOLE 
    else: 
        flags |= wx.EXEC_HIDE_CONSOLE
    #wx.Execute(command, flags=flags, callback=process)
    wx.Execute(command, flags=flags)
    
######################################################################
# WxApp
######################################################################

class WxApp():
    def __init__( self, title, width=800, height=600, popup=False ):
        if popup is False:
            self.app = wx.App()
            self.app.locale = wx.Locale(wx.Locale.GetSystemLanguage())
            self.frame = wx.Frame( parent=None, id = wx.ID_ANY, title = title, pos = wx.DefaultPosition, size = wx.Size( width,height ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
            self.frame.Bind(wx.EVT_CLOSE, self.closeEvent)
            registerCtrl( 'WxApp', self )
        else:
            self.frame = wx.Frame( parent=None, id = wx.ID_ANY, title = title, pos = wx.DefaultPosition, size = wx.Size( width,height ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
            self.frame.Bind(wx.EVT_CLOSE, self.popupCloseEvent)
        self.frame.Center();
        self.frame.Bind(wx.EVT_SHOW, self.openEvent)
        self.frame.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
        self.openHandler = None
        self.closeHandler = None
        self.lastMousePos = wx.Point(0,0)
        self.menubar = None 
        self.statusbar = None 

    def run(self):
        self.frame.Center()
        self.frame.Show()
        self.app.MainLoop()

    def close(self):
        self.frame.Close()

    def show(self):
        self.frame.Show()

    def Show(self): #TODO: remove
        self.frame.Show()

    def getCtrl(self,key):
        return getCtrl(key)

    def getWxCtrl(self,key):
        return getWxCtrl(key)

    def getWxTimer(self,key):
        return getWxTimer(key)
        
    def openEvent(self,event):
        if self.openHandler is not None:
            self.openHandler(event)
            self.openHandler = None
        self.frame.Unbind(wx.EVT_SHOW)
        event.Skip()

    def openHandle(self,handler):
        self.openHandler = handler

    def closeEvent(self,event):
        if self.closeHandler is not None:
            if self.closeHandler(event) == True:
                event.Skip()
        else:
            event.Skip()

    def popupCloseEvent(self,event): 
        self.makeModal(False) 
        if self.closeHandler is not None: #841
            if self.closeHandler(event) == True:
                event.Skip()
        else:
            event.Skip()

    def closeHandle(self,handler):
        self.closeHandler = handler

    def idleHandle(self,handler):
        self.frame.Bind(wx.EVT_IDLE, handler)

    def timerHandle(self,handler,interval=1000,start=False,key=None):
        timer = wx.Timer(self.frame)
        self.frame.Bind(wx.EVT_TIMER, handler, timer)
        if key is not None:
            registerCtrl(key,timer)
        if start is True and interval > 0:
            timer.Start(interval)

    def timerStart(self,key,interval):
        timer = getWxTimer(key)
        if timer is not None and interval > 0:
            timer.Start(interval)

    def timerStop(self,key):
        timer = getWxTimer(key)
        if timer is not None:
            timer.Stop()

    def makeMenu(self, value):
        menu = wx.Menu()
        for k, v in value.items():
            if k[0] == '-':
                menu.AppendSeparator()
            else:
                if type(v) is dict:
                    submenu = self.makeMenu(v)
                    menu.AppendSubMenu(submenu, k)
                else:
                    if type(v) is list:
                        handler = v[0]
                        icon = v[1]
                    else:
                        handler = v
                        icon = None
                    item = wx.MenuItem( menu, getId(), k, wx.EmptyString, wx.ITEM_NORMAL )
                    if icon is not None:
                        item.SetBitmap(getMenuBitmap(icon))
                    if handler is None:
                        item.Enable( False )
                    else:
                        self.frame.Bind(wx.EVT_MENU, handler, item)
                    menu.Append(item)
        return menu

    def makeMenuBar(self, menu_def):
        self.menubar = wx.MenuBar(0)
        for key, value in menu_def.items():
            if type(value) is dict:
                menu = self.makeMenu(value)
                self.menubar.Append( menu, key )
        self.frame.SetMenuBar(self.menubar)

    def makeStatusBar(self, status_def):
        self.statusbar = self.frame.CreateStatusBar( len(status_def), wx.STB_SIZEGRIP, wx.ID_ANY )
        widths = []
        for i in range(len(status_def)):
            self.statusbar.SetStatusText( status_def[i][0], i)
            widths.append(status_def[i][1])
        self.statusbar.SetStatusWidths(widths)

    def makeToolBar(self, tool_def):  #icon, text, handler
        flags = wx.TB_FLAT|wx.TB_HORIZONTAL
        if len(tool_def[0]) >= 3:
            flags |= wx.TB_TEXT
        self.toolbar = self.frame.CreateToolBar( flags, wx.ID_ANY )
        for value in tool_def:
            if value[0] is None:
                self.toolbar.AddSeparator()
            else:
                text = handler = tooltip = None
                if len(value) >= 2:
                    handler = value[1]
                if len(value) >= 3:
                    text = value[2]
                if len(value) >= 4:
                    tooltip = value[3]
                icon = getToolbarBitmap(value[0])
                id = getId()
                if text is not None:
                    tool = self.toolbar.AddTool( id, text, icon, wx.NullBitmap, wx.ITEM_NORMAL, wx.EmptyString, wx.EmptyString, None )
                else:
                    tool = self.toolbar.AddSimpleTool( id, icon, wx.EmptyString, wx.EmptyString, None )
                if tooltip is not None:
                    self.toolbar.SetToolShortHelp(id, tooltip);
                if handler is None:
                    tool.Enable( False )
                else:
                    self.toolbar.Bind( wx.EVT_TOOL, handler, id = id )
        self.toolbar.Realize()

    def makeBody(self,body_def):
        self.panel = Panel(body_def,self.frame,create=True)
        self.frame.SetSizer( wrapSizer(self.panel.ctrl) )
        self.frame.Layout()

    def makeLayout(self,layout):
        if 'menu' in layout:
            self.makeMenuBar(layout['menu'])
        if 'tool' in layout:
            self.makeToolBar(layout['tool'])
        if 'status' in layout:
            self.makeStatusBar(layout['status'])
        if 'body' in layout:
            self.makeBody(layout['body'])
        
    def makeModal(self, modal=True): 
        if modal and not hasattr(self.frame, '_disabler'):
            self.frame._disabler = wx.WindowDisabler(self.frame)
        if not modal and hasattr(self.frame, '_disabler'):
            del self.frame._disabler

    def noMinimize(self): 
        style = self.frame.GetWindowStyle()
        self.frame.SetWindowStyle(style & (~wx.MINIMIZE_BOX))
        self.frame.Refresh()

    def noMaximize(self): 
        style = self.frame.GetWindowStyle()
        self.frame.SetWindowStyle(style & (~wx.MAXIMIZE_BOX))
        self.frame.Refresh()

    def NoClose(self): 
        style = self.frame.GetWindowStyle()
        self.frame.SetWindowStyle(style & (~wx.CLOSE_BOX))
        self.frame.Refresh()
        
    def noResize(self): 
        style = self.frame.GetWindowStyle()
        self.frame.SetWindowStyle(style & (~wx.RESIZE_BORDER))
        self.frame.Refresh()

    def noSystemMenu(self): 
        style = self.frame.GetWindowStyle()
        self.frame.SetWindowStyle(style & (~wx.SYSTEM_MENU))
        self.frame.Refresh()

    def noCaption(self): 
        style = self.frame.GetWindowStyle()
        self.frame.SetWindowStyle(style & (~wx.CAPTION))
        self.frame.Refresh()
          
    def noBorder(self): 
        style = self.frame.GetWindowStyle()
        self.frame.SetWindowStyle(style & (~wx.BORDER))
        self.frame.Refresh()

    def _dragMotionHandle(self, event): 
        if event.LeftIsDown():
            currMousePos = wx.GetMousePosition()
            dx = currMousePos[0] - self.lastMousePos[0]
            dy = currMousePos[1] - self.lastMousePos[1]
            self.frame.Move(wx.Point(self.lastWinPos[0] + dx, self.lastWinPos[1] + dy))
        event.Skip()

    def _dragLeftDownHandle(self, event): 
        self.lastWinPos = self.frame.GetScreenPosition()
        self.lastMousePos = wx.GetMousePosition()
        event.Skip()

    def dragEnable(self,key): 
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            ctrl.Bind(wx.EVT_MOTION, self._dragMotionHandle)
            ctrl.Bind(wx.EVT_LEFT_DOWN, self._dragLeftDownHandle)

    def _getContextMenuHandler(self,menu): 
        def _contextMenuRightDown(event): #closure
            self.frame.PopupMenu( menu, event.GetPosition() )
        return _contextMenuRightDown

    def contextMenu(self,menu_def,key): 
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            ctrl.Bind(wx.EVT_RIGHT_DOWN, self._getContextMenuHandler(self.makeMenu(menu_def)))

    def toolTip(self,text,key): 
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            ctrl.SetToolTip(wx.ToolTip(text))

    def setStatusText(self,text,index=0): 
        if self.statusbar is not None:
            if index < self.statusbar.GetFieldsCount():
                self.statusbar.SetStatusText(text,index)

    # Dialog
    def openFileDialog(self,defaultDir="",defaultFile="",multiple=False,save=False):  
        style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST if save is False else wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT
        style |= wx.FD_MULTIPLE if multiple is True else 0
        dlg = wx.FileDialog(self.frame,defaultDir=defaultDir,defaultFile=defaultFile,style=style)
        rv = dlg.ShowModal()
        if rv == wx.ID_OK:
            if multiple == True:
                files = []
                for file in dlg.GetFilenames():
                    files.append( os.path.join(dlg.GetDirectory(), file) )
                return files
            else:
                return os.path.join(dlg.GetDirectory(), dlg.GetFilename())
        else:
            return None

    def saveFileDialog(self,defaultDir="",defaultFile=""):  
        return OpenFileDialog(defaultDir=defaultDir,defaultFile=defaultFile, multiple=False, save=True)

    def directoryDialog(self,defaultPath=""):  
        dlg = wx.DirDialog(self.frame,defaultPath=defaultPath)
        rv = dlg.ShowModal()
        if rv == wx.ID_OK:
            return dlg.GetPath()
        else:
            return None
        
    def messageBox(self,title,message):  
        dlg = wx.MessageDialog(self.frame, message, caption=title, style=wx.OK|wx.CENTER, pos=wx.DefaultPosition)
        dlg.ShowModal()

    def messageYesNo(self,title,message):  
        dlg = wx.MessageDialog(self.frame, message, caption=title, style=wx.YES|wx.NO|wx.CENTER, pos=wx.DefaultPosition)
        rv = dlg.ShowModal()
        if rv == wx.ID_OK or rv == wx.ID_YES:
            return True
        else:
            return False

    def messageYesNoCancel(self,title,message):  
        dlg = wx.MessageDialog(self.frame, message, caption=title, style=wx.YES|wx.NO|wx.CANCEL|wx.CENTER, pos=wx.DefaultPosition)
        rv = dlg.ShowModal()
        if rv == wx.ID_OK or rv == wx.ID_YES:
            return True
        elif rv == wx.ID_NO:
            return False
        else: #wx.ID_CANCEL,
            return None

    def progressDialog(self,title,message,maxValue=100):  
        dlg = wx.ProgressDialog(title, message, maximum=100, parent=self.frame, style=wx.PD_APP_MODAL|wx.PD_AUTO_HIDE)
        return dlg

    def onProgressDialog(self,dlg,percent):  
        dlg.Update(percent)

    def progressDialogUpdate(self,dlg,percent):  
        wx.CallAfter(self.onProgressDialog, dlg, percent)

    def textEntryDialog(self,title,message,value=''):
        dlg = wx.TextEntryDialog(self.frame, message, title, value=value) 
        if dlg.ShowModal() == wx.ID_OK: 
            value = dlg.GetValue()
        dlg.Destroy() 
        return value

    def dialog(self,title,layout,size=(400,300)): #TODO
        dlg = wx.Dialog( parent=self.frame, title=title, size=size )
        panel = Panel(layout,dlg,create=True)
        dlg.ShowModal()
        dlg.Destroy()

    # Control
    def clearValue(self,key):
        ctrl = self.getCtrl(key)
        if ctrl is not None:
            return ctrl.clearValue() 
        else:
            return None
    
    def getValue(self,key):
        ctrl = self.getCtrl(key)
        if ctrl is not None:
            return ctrl.getValue() 
        else:
            return None

    def setValue(self,key,value):
        ctrl = self.getCtrl(key)
        if ctrl is not None:
            ctrl.setValue(value) 

    def appendValue(self,key,value):
        ctrl = self.getCtrl(key)
        if ctrl is not None:
            return ctrl.appendValue(value) 
        else:
            return None

    def removeValue(self,key,value):
        ctrl = self.getCtrl(key)
        if ctrl is not None:
            return ctrl.removeValue(value) 
        else:
            return None
     
    # Check Button Control
    def getCheckState(self,key):  #deprecated
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            return ctrl.GetValue() 
        else:
            return None

    # Choice, Bombo, List Control
    def getSelectedText(self,key):  #deprecated
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            return ctrl.GetString(ctrl.GetSelection())
        else:
            return None

    # Text Control 
    def getText(self,key):  #deprecated
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            return ctrl.GetValue() 
        else:
            return None

    def setText(self,key,text):  #deprecated
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            ctrl.Clear() 
            ctrl.AppendText(text) 
                            
    def appendText(self,key,text):  #deprecated
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            ctrl.AppendText(text) 

    #def setWrap(self,key,wrap=True):
    #    ctrl = getWxCtrl(key)
    #    if ctrl is not None:
    #        ws = ctrl.GetWindowStyle()
    #        if wrap is True:
    #            ctrl.SetWindowStyle(ws & ~wx.TE_DONTWRAP ) #| wx.TE_BESTWRAP
    #        else:
    #            ctrl.SetWindowStyle(ws | wx.TE_DONTWRAP) #& ~wx.TE_BESTWRAP 
        
    # Ticker Control
    def setTickerText(self,key,text): 
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            ctrl.SetText(text) 

    def setTickerFont(self,key,font): 
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            ctrl.SetFont(font) 

    def setTickerPPF(self,key,text): 
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            ctrl.SetPPF(int(text)) 
            
    def setTickerFPS(self,key,text): 
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            ctrl.SetFPS(int(text)) 
                        
    def setTickerStart(self,key): 
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            ctrl.Start() 

    def setTickerStop(self,key): 
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            ctrl.Stop() 

    def setTickerDirection(self,key,direction='right'): 
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            if direction == 'right':
                ctrl.SetDirection('ltr')
            elif direction == 'left':
                ctrl.SetDirection('rtl')

    # Book Control
    def setBookPage(self,key,index): 
        ctrl = getCtrl(key)
        if ctrl is not None:
            ctrl.setPage(index)
    def setBookEffect(self,key,effect="slide_to_left"): 
        ctrl = getCtrl(key)
        if ctrl is not None:
            ctrl.setEffect(effect)
    
    #Calendar Control
    def getCalendarDate(self,key): 
        ctrl = getWxCtrl(key)
        if ctrl is not None:
            date = ctrl.GetDate()
            return date.Format('%Y-%m-%d')
    
class WxPopup(WxApp):
    def __init__( self, title, width=800, height=600 ):
        super().__init__( title, width=width, height=height, popup=True )