#!/usr/bin/env python
# coding: iso-8859-1
"""The wxPython classes to help loading GUI from XRC file easily."""

import wx
import wx.xrc as xrc

def MethodNameToEvent(name, prefix='On'):
    """Convert method name to event and event sources. The method name should 
    be one of following formats.
    
    <prefix><capitalize event name>_[<control name>]
    <prefix><capitalize event name>_[<id1>]
    <prefix><capitalize event name>_[<id1>_<id2>]
    
    For example, OnButton_Button1 method will be bound to EVT_BUTTON event 
    and Button1 control. OnButton_1001_1010 will be bound to EVT_BUTTON event
    and all control which id is between 1001 and 1010.
 
    @param name: Method name to be converted.
    @param prefix: The prefix of event. 
    
    @return: The return value contain four items. They are event object, event
        source, id1 and id2 which will be used in Bind method.
    """
    charList = []
    idx = len(prefix)
    for c in name[idx:]:
        idx += 1
        if c == '_':
            break
        if c.isupper():
            charList.append('_')
        charList.append(c.upper())
        
    evtName = 'EVT' + ''.join(charList)
    
    id1 = -1
    id2 = -1
    src = None
    
    evtSrc = name[idx:].split('_')
    if len(evtSrc) >= 2:
        if evtSrc[0].isdigit() and evtSrc[1].isdigit():
            id1 = int(evtSrc[0])
            id2 = int(evtSrc[1])
        elif evtSrc[0]:
            src = name[idx:]
    else:
        if evtSrc[0].isdigit():
            id1 = int(evtSrc[0])
        elif evtSrc[0]:
            src = name[idx:]
            
    evt = getattr(wx, evtName)
    
    return evt, src, id1, id2

def AutoBindEvent(win, prefix='On', excludes=[]):
    """Bind methods of a given window object to corresponding events. The method
    name must following the rules which used by MethodNameToEvent function.
    
    @param win: The window object to be bound.
    @param prefix: The prefix of method name of event handler to be bound.
    @param excludes: All method names listed in the list will not be bound.
    """
    wxEvtPrefix = 'EVT_'
    wxEvtPrefixLen = len(wxEvtPrefix)
    
    for attr in dir(win):
        value = getattr(win, attr)
        if attr not in excludes and attr.startswith(prefix) and callable(value):
            event, src, id1, id2 = MethodNameToEvent(attr, prefix)
            if src:
                src = getattr(win, src)
            if src is not None or id1 >= 0 or id2 >= 0:
                win.Bind(event, value, src, id1, id2)

class XrcFrame(wx.Frame):
    """XrcFrame is a helper class derived from wx.Frame. It can help to load 
    frame from XRC resource automatically and bind the corresponding event 
    handlers easily."""
    
    def __init__(self, parent, id=wx.ID_ANY, title=wx.EmptyString, 
        pos=wx.DefaultPosition, size=wx.DefaultSize, 
        style=wx.DEFAULT_FRAME_STYLE, name=wx.FrameNameStr, 
        resName=None, res=None, autoBindEvt=True):
        """The constructor of XrcFrame. 
        
        @param self: self
        @param parent: The parent window.
        @param id: The id.
        @param title: The title.
        @param pos: The position of window.
        @param size: The size of window in pixel.
        @param name: The frame name.
        @param resName: The resource name of this window in XRC resource file.
        @param res: The XRC resource. If it's None, the global XRC resource will
            be used.
        @param autoBindEvt: If it's True, the method names of this window which
            matched the rules of MethodNameToEvent method will be bound to 
            corresponding event automatically.
        """
        
        pre = wx.PreFrame()
        
        if not res:
            self.res = xrc.XmlResource.Get()
        else:
            self.res = res
            
        if not resName:
            self.resName = self.__class__.__name__
        else:
            self.resName = resName
        
        self.res.LoadOnFrame(pre, parent, self.resName)
        self.PostCreate(pre)
        
        self.SetId(id)    
        self.SetTitle(title)
        self.SetPosition(pos)
        self.SetSize(size)
        self.SetWindowStyle(style)
        self.SetName(name)
        
        if autoBindEvt:
            AutoBindEvent(self)
            
    def __getattr__(self, name):
        self.__dict__[name] = xrc.XRCCTRL(self, name)
        return self.__dict__[name]
        
    
class XrcDialog(wx.Dialog):
    """XrcDialog will load dialog from XRC resource automatically."""
    
    def __init__(self, parent, id=-1, title=wx.EmptyString, 
        pos=wx.DefaultPosition, size=wx.DefaultSize, 
        style=wx.DEFAULT_DIALOG_STYLE, name=wx.DialogNameStr,
        resName=None, res=None, autoBindEvt=True):
        """The constructor of XrcFrame. 
        
        @param self: self
        @param parent: The parent window.
        @param id: The id.
        @param title: The title.
        @param pos: The position of window.
        @param size: The size of window in pixel.
        @param name: The dialog name.
        @param resName: The resource name of this window in XRC resource file.
        @param res: The XRC resource. If it's None, the global XRC resource will
            be used.
        @param autoBindEvt: If it's True, the method names of this window which
            matched the rules of MethodNameToEvent method will be bound to 
            corresponding event automatically.
        """
        pre = wx.PreDialog()
        
        if not res:
            self.res = xrc.XmlResource.Get()
        else:
            self.res = res
            
        if not resName:
            self.resName = self.__class__.__name__
        else:
            self.resName = resName
            
        self.res.LoadOnDialog(pre, parent, self.resName)
        self.PostCreate(pre)
        
        self.SetId(id)
        self.SetTitle(title)
        self.SetPosition(pos)
        self.SetSize(size)
        self.SetWindowStyle(style)
        self.SetName(name)
        
        if autoBindEvt:
            AutoBindEvent(self)
            
    def __getattr__(self, name):
        self.__dict__[name] = xrc.XRCCTRL(self, name)
        return self.__dict__[name]

class XrcPanel(wx.Panel):
    """XrcPanel will load panel from XRC resource automatically."""
    
    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, 
        size=wx.DefaultSize, style=wx.TAB_TRAVERSAL|wx.NO_BORDER, 
        name=wx.EmptyString, resName=None, res=None, autoBindEvt=True):
        """The constructor of XrcFrame. 
        
        @param self: self
        @param parent: The parent window.
        @param id: The id.
        @param title: The title.
        @param pos: The position of window.
        @param size: The size of window in pixel.
        @param name: The panel name.
        @param resName: The resource name of this window in XRC resource file.
        @param res: The XRC resource. If it's None, the global XRC resource will
            be used.
        @param autoBindEvt: If it's True, the method names of this window which
            matched the rules of MethodNameToEvent method will be bound to 
            corresponding event automatically.
        """
        pre = wx.PrePanel()
        
        if not res:
            self.res = xrc.XmlResource.Get()
        else:
            self.res = res
            
        if not resName:
            self.resName = self.__class__.__name__
        else:
            self.resName = resName
            
        self.res.LoadOnPanel(pre, parent, self.resName)
        self.PostCreate(pre)
        
        self.SetId(id)
        self.SetTitle(title)
        self.SetPosition(pos)
        self.SetSize(size)
        self.SetWindowStyle(style)
        self.SetName(name)
        
        if autoBindEvt:
            AutoBindEvent(self)
            
    def __getattr__(self, name):
        self.__dict__[name] = xrc.XRCCTRL(self, name)
        return self.__dict__[name]
        

# EOF.