
'''
This software is licensed under the GPL (GNU General Public License) version 2
as it appears here: http://www.gnu.org/copyleft/gpl.html
It is also included with this archive as `gpl.txt <gpl.txt>`_.
'''


import wx
import wx.lib.mixins.listctrl as listmix

#todo: add icon support

class pseudo_event(object):
    def __init__(self, index):
        self.index = index
    def GetIndex(self):
        return self.index

class hbrowser(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
    def __init__(self, parent, containers, items):
        wx.ListCtrl.__init__(self, parent, style=wx.LC_NO_HEADER|wx.LC_REPORT|wx.LC_ALIGN_LEFT|wx.LC_SINGLE_SEL)#|wx.LC_SMALL_ICON
        self.InsertColumn(0, 'unseen')
        listmix.ListCtrlAutoWidthMixin.__init__(self)
        self.parent = parent
        self.containers = {}
        self.items = {}
        for i,j in containers:
            x = self.InsertStringItem(2147483647, "[%s]"%i)
            self.containers[x] = i,j
        for i,j in items:
            x = self.InsertStringItem(2147483647, i)
            self.items[x] = i,j
        
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelected)
        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnActivated)
        self.Bind(wx.EVT_LEFT_DOWN, self.OnClicked)
    
    def Back(self, which=None):
        if which is None:
            which = self.GetFirstSelected()
        self.OnSelected(pseudo_event(which))
    
    def OnClicked(self, e):
        index = self.HitTest(e.GetPosition())[0]
        if index == self.GetFirstSelected():
            self.Back()
        else:
            e.Skip()
    
    def OnSelected(self, e):
        it = e.GetIndex()
        if it in self.containers:
            name, token = self.containers[it]
            self.parent.ExpandChildren(self, token)
        else:
            self.parent.ClearChildren(self, dc=1)
    
    def OnActivated(self, e):
        it = e.GetIndex()
        if it in self.containers:
            name, token = self.containers[it]
            self.parent.ExpandChildren(self, token, dc=1)
        else:
            name, token = self.items[it]
            self.parent.ChildActivated(self, token)

class HorizontalBrowser(wx.Panel):
    def __init__(self, parent, get_children, on_activation):
        wx.Panel.__init__(self, parent)
        
        self.get_children = get_children
        self.on_activation = on_activation
        containers, items = get_children(None)
        self.lcs = [wx.Panel(self), wx.Panel(self), hbrowser(self, containers, items)]
        
        self.sizer = wx.BoxSizer(wx.HORIZONTAL)
        
        for i in self.lcs:
            self.sizer.Add(i, 1, wx.ALL|wx.EXPAND, 2)
        
        othersizer = wx.BoxSizer(wx.HORIZONTAL)
        p = wx.Panel(self)
        btn = wx.Button(p, -1, "Back")
        othersizer.Add(p, 1, wx.ALL|wx.EXPAND, 2)
        othersizer.Add(wx.StaticText(self, -1, "Current"), 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER, 2)
        othersizer.Add(wx.StaticText(self, -1, "Forward"), 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER, 2)
        
        self.Bind(wx.EVT_BUTTON, self.OnBack, btn)
        
        sizer2 = wx.BoxSizer(wx.VERTICAL)
        sizer2.Add(othersizer, 0, wx.EXPAND)
        sizer2.Add(self.sizer, 1, wx.EXPAND)
        
        self.SetSizer(sizer2)
    
    def OnBack(self, e):
        if isinstance(self.lcs[-3], hbrowser):
            self.lcs[-3].Back()
    
    def ClearChildren(self, lc, dc=0):
        self.Freeze()
        while self.lcs[-1] != lc:
            popped = self.lcs.pop()
            self.sizer.Remove(popped)
            popped.Destroy()
        for i in xrange(min(3+dc, len(self.lcs))):
            self.lcs[-1-i].Hide()
        if dc:
            self.lcs.append(wx.Panel(self))
            self.sizer.Add(self.lcs[-1], 1, wx.ALL|wx.EXPAND, 2)
        for i in xrange(3):
            self.lcs[-1-i].Show()
        self.Layout()
        self.Thaw()
    
    def ExpandChildren(self, lc, token, dc=0):
        if dc:
            dc = lc == self.lcs[-2]
            print "dc:", dc
        self.ClearChildren(lc)
        self.Freeze()
        for i in xrange(3):
            self.lcs[-1-i].Hide()
        containers, items = self.get_children(token)
        self.lcs.append(hbrowser(self, containers, items))
        self.sizer.Add(self.lcs[-1], 1, wx.ALL|wx.EXPAND, 2)
        if dc:
            self.lcs.append(wx.Panel(self))
            self.sizer.Add(self.lcs[-1], 1, wx.ALL|wx.EXPAND, 2)
        for i in xrange(3):
            self.lcs[-1-i].Show()
        self.Layout()
        self.Thaw()
    
    def ChildActivated(self, lc, token):
        print token


if __name__ == '__main__':
    ## def get_children(token):
        ## if token is None:
            ## token = ()
        ## return [("<dir %s>"%(token+(i,),), token+(i,)) for i in xrange(5)], [("file_%s"%(token+(i,),), token+(i,)) for i in xrange(5)]
    
    import os, stat
    
    root = ["C:\\", "D:\\", "E:\\", "F:\\"]
    
    sfcn = lambda a,b: cmp(a[0].lower(), b[0].lower())
    
    def get_children(token):
        if token is None:
            return [(i,i) for i in root], []
        try:
            l = os.listdir(token)
        except:
            return [], []
        dire = []
        file = []
        for i in l:
            j = os.path.join(token, i)
            try:
                if stat.S_ISDIR(os.stat(j).st_mode):
                    dire.append((i,j))
                else:
                    file.append((i,j))
            except:
                pass
        
        dire.sort(sfcn)
        file.sort(sfcn)
        
        return dire, file
    
    def on_activation(token):
        pass
    
    a = wx.App(0)
    b = wx.Frame(None, title="spacial browser")
    c = HorizontalBrowser(b, get_children, on_activation)
    b.Show(1)
    b.SetSize((800,400))
    a.MainLoop()
