import gtk
import pango

class ScrollGrid:
    """
    A scrolled grid widget
    """
    def __init__(self, **args):
        defaults = {
            "scrn": None,                   # A VBox
            "width": 600,
            "height": 400,
            "heads": [],                    # General Headings
            "cols": None,                   # Column Headings
            "rows": None,                   # Number of rows
            "form": [],                     # Format of data fields as follows:
                                            #   Code  - As per the Format class
                                            #   Size  - Total size . Decimals
                                            #   Event - True or False
            "data": [],                     # Main table data
            "event": None,                  # A function to execute
            "butt": [],                     # Additional buttons
            "pbar": None}                   # Progressbar object
        for nam in args.keys():
            defaults[nam] = args[nam]
        for nam in defaults.keys():
            exec "self.%s = defaults[nam]" % nam
        self.doVariables()
        self.doProcess()

    def doVariables(self):
        if type(self.butt) == tuple:
            self.butt = list(self.butt)
        self.butt.append(("gtk-close", self.closeProcess))

    def doProcess(self):
        # main headings
        colr = self.scrn.get_style().copy().bg[gtk.STATE_ACTIVE]
        for head in self.heads:
            ebox = gtk.EventBox()
            ebox.modify_bg(gtk.STATE_NORMAL, colr)
            self.scrn.pack_start(ebox, False, False, 0)
            labl = gtk.Label()
            ebox.add(labl)
            if head:
                labl.set_markup("<b>%s</b>" % head.replace("&", "&amp;"))
        # create a heading scrolled window
        self.hwin = gtk.ScrolledWindow()
        self.hwin.set_size_request(self.width, -1)
        self.hwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
        self.hadj = self.hwin.get_hadjustment()
        self.scrn.pack_start(self.hwin, True, True, 0)
        # create an eventbox
        ebox = gtk.EventBox()
        ebox.modify_bg(gtk.STATE_NORMAL, colr)
        self.hwin.add_with_viewport(ebox)
        # create a table for the column headings
        headtab = gtk.Table(rows=len(self.cols), columns=len(self.form),
            homogeneous=False)
        ebox.add(headtab)
        # column headings
        for y, col in enumerate(self.cols):
            for x, c in enumerate(col):
                fmt = "%s-%ss" % ("%", int(self.form[x][1]))
                head = gtk.Label()
                head.set_markup(fmt % c.replace("&", "&amp;"))
                headtab.attach(head, x, x+1, y, y+1, 0, 0, 0, 0)
                exec "self.hlabl_%s_%s = head" % (y, x)
        # create a body scrolled window
        self.bwin = gtk.ScrolledWindow()
        self.bwin.set_size_request(self.width, self.height)
        self.bwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        self.badj = self.bwin.get_hadjustment()
        self.badj.connect("notify::value", self.doHAdjustment)
        self.scrn.pack_start(self.bwin, True, True, 0)
        # create a table for the body details
        bodytab = gtk.Table(rows=self.rows, columns=len(self.cols[0]),
            homogeneous=False)
        self.bwin.add_with_viewport(bodytab)
        # populate the table
        # column data
        col1 = gtk.gdk.color_parse("white")
        col2 = self.scrn.get_style().copy().bg[gtk.STATE_NORMAL]
        colr = col2
        for y, dat in enumerate(self.data):
            if self.pbar:
                self.pbar.displayProgress()
            if colr == col2:
                colr = col1
            else:
                colr = col2
            for x, d in enumerate(dat):
                ebox = gtk.EventBox()
                ebox.modify_bg(gtk.STATE_NORMAL, colr)
                val = Format(d, self.form[x][0], self.form[x][1])
                if val.err:
                    val = Format(d, "NA", self.form[x][1])
                labl = gtk.Label(val.disp)
                if len(self.form[x]) == 4 and val.work < 0:
                    labl.modify_fg(gtk.STATE_NORMAL,
                        gtk.gdk.color_parse(self.form[x][3]))
                ebox.add(labl)
                if self.form[x][2]:
                    if not self.event:
                        ebox.connect("button_release_event", self.execCmd, y, x)
                    else:
                        ebox.connect(self.event[0], self.event[1], dat[-1], x)
                bodytab.attach(ebox, x, x+1, y, y+1, 0, 0, 0, 0)
                exec "self.blabl_%s_%s = labl" % (y, x)
                exec "self.bcell_%s_%s = ebox" % (y, x)
        self.last = y
        # create a hbox to hold the buttons
        hbox = gtk.HBox(False, 0)
        # create a label and spinbox for the font
        self.scrn.pack_start(hbox, False, False, 10)
        sbl = gtk.Label("Font Size")
        sbl.set_alignment(0, 0.5)
        hbox.pack_start(sbl, False, True, 0)
        sba = gtk.Adjustment(10, 6, 12, 1, 0, 0)
        sbw = gtk.SpinButton(sba, 0, 0)
        sbw.set_wrap(True)
        hbox.pack_start(sbw, False, True, 0)
        sba.connect("value_changed", self.doSetFont, sbw)
        # create the buttons
        for num, but in enumerate(self.butt):
            exec "but%s = gtk.Button(stock=but[0])" % num
            exec "but%s.connect('clicked', self.execCmd, num)" % num
            exec "but%s.set_flags(gtk.CAN_DEFAULT)" % num
            exec "hbox.pack_start(but%s, True, True, 0)" % num
            exec "but%s.show()" % num
        self.scrn.show_all()
        if self.pbar:
            self.pbar.closeProgress()

    def doSetFont(self, *args):
        while gtk.events_pending():
            gtk.main_iteration()
        size = args[1].get_value_as_int()
        font = pango.FontDescription("Courier %s" % size)
        for y, col in enumerate(self.cols):
            for x, c in enumerate(col):
                exec "self.hlabl_%s_%s.modify_font(font)" % (y, x)
        for y in range(0, self.last + 1):
            for x, c in enumerate(col):
                try:
                    exec "self.blabl_%s_%s.modify_font(font)" % (y, x)
                except:
                    pass

    def doHAdjustment(self, *args):
        self.hadj.set_value(args[0].get_value())

    def hideCol(self, col):
        for row in range(0, self.last + 1):
            try:
                exec "self.hlabl_%s_%s.hide()" % (row, col)
            except:
                pass
            try:
                exec "self.bcell_%s_%s.hide()" % (row, col)
            except:
                pass

    def showCol(self, col):
        for row in range(0, self.last + 1):
            try:
                exec "self.hlabl_%s_%s.show()" % (row, col)
            except:
                pass
            try:
                exec "self.bcell_%s_%s.show()" % (row, col)
            except:
                pass

    def execCmd(self, widget, *args):
        if self.butt[args[0]][1]:
            self.butt[args[0]][1]()

    def closeProcess(self, widget=None, *args):
        for child in self.scrn.get_children():
            child.destroy()
        # There must be a main loop in the calling class/module
        gtk.main_quit()

class Format:
    """
    A class to format data

    Data Types
    ============================================================================
    CB = Check Box
    D0 = Date (CCYYMMDD)
    D1 = Date (CCYYMMDD)
    d1 = Date (CCYYMMDD) Alowing Zero
    D2 = Current Period Date (CCYYMM)
    d2 = Current Period Date (CCYYMM) Allowing Zero
    D3 = Date (DD-MMM-YYYY)
    DT = Date and Time (DD-MMM-YYYY-HH:MM)
    FF = File or Directory Format
    LA = Lower Case Alphanumeric (Must also have 'size' set)
    La = Lower Case Alphanumeric Right Justified (Must also have 'size' set)
    HA = Normal Alphanumeric Hidden as for Passwords
    NA = Normal Alphanumeric (Must also have 'size' set)
    Na = Normal Alphanumeric Right Justified (Must also have 'size' set)
    RW = Raw Data, No formatting or checking
    SD = Signed Decimal (size includes sign and decimals)
    Sd = Convert Integer to Signed Decimal (size includes sign and decimals)
    SI = Signed Integer (size includes sign)
    SL = Signed Long Integer (size includes sign)
    TM = Time (HH:MM)
    TS = Timestamp (CCYY-MM-DD HH:MM:SS)
    TV = Text View - This is only used with TartanDialog for input purposes
    Tv = Text View - This is only used with TartanDialog for input purposes
    TX = Text or Blob Alphanumeric Variable Length- Storing Text Views etc.
    UA = Upper Case Alphanumeric (Must also have 'size' set)
    Ua = Upper Case Alphanumeric Right Justified (Must also have 'size' set)
    UD = Unsigned Decimal (size includes decimals)
    Ud = Convert Integer to Unsigned Decimal (size includes decimals)
    UI = Unsigned Integer
    UL = Unsigned Long Integer
    US = Unsigned Serial
    """
    def __init__(self, data, type, size):
        self.mthnum = {
            "JAN":1, "FEB":2, "MAR":3, "APR":4, "MAY":5, "JUN":6,
            "JUL":7, "AUG":8, "SEP":9, "OCT":10, "NOV":11, "DEC":12}
        #=======================================================================
        # Work around data types from TartanDialog which are 3 characters long
        #=======================================================================
        if len(type) == 3:
            type = type[1:]
        #=======================================================================
        # Work around for None
        #=======================================================================
        if data == None:
            if type[1].lower() in ("a", "v", "w", "x"):
                self.data = ""
            else:
                self.data = "0"
        #=======================================================================
        # Raw Data Type
        #=======================================================================
        if  type == "RW":
            self.err = ""
            self.work = self.disp = self.data = data
            return
        #=======================================================================
        # Timestamp
        #=======================================================================
        if  type == "TS":
            self.err = ""
            self.work = self.disp = self.data = data
            return
        #=======================================================================
        # Work around for previous format error
        #=======================================================================
        elif not type[0] == "T" and type[1].upper() != "A" and data == "None":
            self.data = str(0)
        #=======================================================================
        else:
            self.data = str(data)
        self.data = self.data.strip()
        self.type = type
        self.size = size
        if type in ("D1","d1","D2","d2","DT","dT","TM"):
            if self.data[-1:] == "L":
                self.data = self.data[:-1]
        elif type in ("Sd", "Ud"):
            self.data = str(float(long(self.data) / 100.0))
        elif type[1] in ("I","L"):
            self.data = self.data.split(".")[0]
            if self.data[-1:] == "L":
                self.data = self.data[:-1]
        elif self.type[1].lower() in ("a", "v", "x"):
            self.data = self.data.replace("\\", "/")
        self.processData()

    def processData(self):
        self.quo = int(self.size / 1)
        self.rem = int(round((self.size % 1) * 10))
        self.disp = None
        self.work = None
        self.err = ""
        if self.type in ("D0","d0"):
            # Work around for previous format error
            #======================================
            if self.mthnum.has_key(self.data[3:6].upper()):
                self.chkD3_Date()
            else:
                self.chkD0_Date()
        elif self.type in ("D1","d1"):
            self.chkD1_Date()
        elif self.type in ("D2","d2"):
            self.chkD2_Date()
        elif self.type in ("D3","d3"):
            self.chkD3_Date()
        elif self.type in ("DT","dT"):
            self.chkDT_Date()
        elif self.type == "TM":
            self.chkTM_Time()
        elif self.type[1] in ("F","A","a"):
            dat = self.data[:self.quo]
            if self.type[1] in ("F","A"):
                if self.data == "":
                    self.work = dat
                    self.disp = " " * self.quo
                else:
                    if self.type[0] == "L":
                        dat = dat.lower()
                    elif self.type[0] == "U":
                        dat = dat.upper()
                    self.work = dat
                    self.disp = dat.ljust(self.quo)
            elif self.type[1] == "a":
                try:
                    if dat[-1:] == "L":
                        raise exception
                    dat = str(long(dat))
                    if dat[-1:] == "L":
                        dat = dat[:-1]
                    self.work = dat.rjust(self.quo)
                    self.disp = dat.rjust(self.quo)
                except:
                    if self.type[0] == "L":
                        dat = dat.lower()
                    elif self.type[0] == "U":
                        dat = dat.upper()
                    self.work = dat
                    self.disp = dat.ljust(self.quo)
        elif self.type == "UI":
            self.unsignedInteger()
        elif self.type == "US":
            self.unsignedInteger()
        elif self.type == "SI":
            self.signedInteger()
        elif self.type == "UL":
            self.unsignedLong()
        elif self.type == "SL":
            self.signedLong()
        elif self.type in ("UD", "Ud"):
            self.unsignedDecimal()
        elif self.type in ("SD", "Sd"):
            self.signedDecimal()
        elif self.type in ("TV", "Tv", "TX"):
            self.work = self.data
            self.disp = self.data
        else:
            self.err = "Invalid Input, Retry (%s)" % self.type

    def chkD0_Date(self):
        date = self.data.replace("-", "")
        self.disp = date
        try:
            self.work = int(date.replace("-", ""))
        except:
            self.work = date

    def chkD1_Date(self):
        date = self.data.replace("-", "")
        if date in ("", "0", "00000000") and (self.type == "d1"):
            self.work = 0
            self.disp = "0000-00-00"
        else:
            try:
                if len(date) < 5 or len(date) > 8:
                    raise Exception
                yy = int(date[0:(len(date) - 4)])
                mm = int(date[(len(date) - 4):(len(date) - 2)])
                dd = int(date[(len(date) - 2):len(date)])
                if yy < 100 and yy > 30:
                    yy += 1900
                elif yy < 100:
                    yy += 2000
                if mm < 01 or mm > 12:
                    self.err = "Invalid Date (D1-1)"
                    return
                chkmth = copy.deepcopy(mthnam)
                if mm == 2:
                    if (yy % 4) == 0:
                        chkmth[2][2] = 29
                    else:
                        chkmth[2][2] = 28
                if dd < 1 or dd > chkmth[mm][2]:
                    self.err = "Invalid Date (D1-2)"
                    return
                self.work = (yy * 10000) + (mm * 100) + dd
                self.disp = "%04i-%02i-%02i" % (yy, mm, dd)
                if len(self.disp) < self.size:
                    self.disp = self.disp + \
                    (" " * (int(self.size/1) - len(self.disp)))
            except:
                self.err = "Invalid Date (D1-3)"

    def chkD2_Date(self):
        date = self.data.replace("-", "")
        if date in ("", "0", "000000") and (self.type == "d2"):
            self.work = 0
            self.disp = "0000-00"
        else:
            try:
                if len(date) < 3 or len(date) > 6:
                    raise Exception
                yy = int(date[0:(len(date) - 2)])
                mm = int(date[(len(date) - 2):len(date)])
                if yy < 100 and yy > 30:
                    yy += 1900
                elif yy < 100:
                    yy += 2000
                if mm < 01 or mm > 12:
                    self.err = "Invalid Month (D2-1)"
                else:
                    self.work = (yy * 100) + mm
                    self.disp = "%04i-%02i" % (yy, mm)
                    if len(self.disp) < self.size:
                        self.disp = self.disp + \
                        (" " * (int(self.size/1) - len(self.disp)))
            except:
                self.err = "Invalid Current Date (D2-2)"

    def chkD3_Date(self):
        date = self.data
        self.work = date
        self.disp = date
        try:
            yy = int(date[7:11])
            mm = self.mthnum[date[3:6].upper()]
            dd = int(date[0:2])
            if yy < 100 and yy > 30:
                yy += 1900
            elif yy < 100:
                yy += 2000
            chkmth = copy.deepcopy(mthnam)
            if mm == 2:
                if (yy % 4) == 0:
                    chkmth[2][2] = 29
                else:
                    chkmth[2][2] = 28
            if mm < 01 or mm > 12:
                self.err = "Invalid Month (D3-1)"
            elif dd < 1 or dd > chkmth[mm][2]:
                self.err = "Invalid Day (D3-2)"
            else:
                self.isoDate = (yy * 10000) + (mm*100) + dd
        except:
            self.err = "Invalid Date (D3-3)"

    def chkDT_Date(self):
        date = self.data.replace("-", "")
        date = self.data.replace(":", "")
        if date in ("", "0", "00000000") and (self.type == "dT"):
            self.work = 0
            self.disp = "0000-00-00-00:00"
        else:
            try:
                if len(date) < 9 or len(date) > 12:
                    raise Exception
                yy = int(date[0:(len(date) - 8)])
                mm = int(date[(len(date) - 8):(len(date) - 6)])
                dd = int(date[(len(date) - 6):(len(date) - 4)])
                hh = int(date[(len(date) - 4):(len(date) - 2)])
                tt = int(date[(len(date) - 2):len(date)])
                if yy < 100 and yy > 30:
                    yy += 1900
                elif yy < 100:
                    yy += 2000
                if mm < 01 or mm > 12:
                    self.err = "Invalid Date (D1-1)"
                    return
                chkmth = copy.deepcopy(mthnam)
                if mm == 2:
                    if (yy % 4) == 0:
                        chkmth[2][2] = 29
                    else:
                        chkmth[2][2] = 28
                if dd < 1 or dd > chkmth[mm][2]:
                    self.err = "Invalid Date (D1-2)"
                    return
                self.work = (yy*100000000)+(mm*1000000)+(dd*10000)+(hh*100)+tt
                self.disp = "%04i-%02i-%02i-%02i:%02i" % (yy, mm, dd, hh, tt)
                if len(self.disp) < self.size:
                    self.disp = self.disp + \
                    (" " * (int(self.size/1) - len(self.disp)))
            except:
                self.err = "Invalid Date (DT)"

    def chkTM_Time(self):
        time = self.data.replace(":", "")
        try:
            if len(time) < 1 or len(time) > 4:
                raise Exception
            time = int(time)
            hh = time / 100
            mm = time % 100
            self.work = (hh*100)+mm
            self.disp = "%02i:%02i" % (hh, mm)
            if len(self.disp) < self.size:
                self.disp = self.disp+(" "*(int(self.size/1)-len(self.disp)))
        except:
            self.err = "Invalid Time (TM)"

    def unsignedInteger(self):
        if self.data == "":
            self.data = "0"
        try:
            if self.data.find("-") != -1:
                self.err = "Invalid UnSigned Integer (UI-)"
            else:
                self.work = int(self.data)
                self.disp = self.data.rjust(self.quo)
                if len(self.disp) > self.quo:
                    self.err = "Invalid UnSigned Integer (UIs)"
        except:
            self.err = "Invalid UnSigned Integer (UI)"

    def signedInteger(self):
        if self.data == "":
            self.data = "0"
        try:
            s = self.data.find("-")
            if s == (len(self.data) - 1):
                self.data = self.data.replace("-", "")
                self.data = "-" + self.data
            self.work = int(self.data)
            s = self.data.find("-")
            if s != -1:
                self.data = self.data.replace("-", "")
                self.data = self.data + "-"
            else:
                self.data = self.data + " "
            self.disp = self.data.rjust(self.quo)
            if len(self.disp) > self.quo:
                self.err = "Invalid UnSigned Integer (UIs)"
        except:
            self.err = "Invalid Signed Integer (SI)"

    def unsignedLong(self):
        if self.data == "":
            self.data = "0"
        try:
            if self.data.find("-") != -1:
                self.err = "Invalid UnSigned Long (UI-)"
            else:
                self.work = long(self.data)
                self.disp = self.data.rjust(self.quo)
                if len(self.disp) > self.quo:
                    self.err = "Invalid UnSigned Long (ULs)"
        except:
            self.err = "Invalid UnSigned Long (UL)"

    def signedLong(self):
        if self.data == "":
            self.data = "0"
        try:
            s = self.data.find("-")
            if s == (len(self.data) - 1):
                self.data = self.data.replace("-", "")
                self.data = "-" + self.data
            self.work = long(self.data)
            s = self.data.find("-")
            if s != -1:
                self.data = self.data.replace("-", "")
                self.data = self.data + "-"
            else:
                self.data = self.data + " "
            self.disp = self.data.rjust(self.quo)
            if len(self.disp) > self.quo:
                self.err = "Invalid UnSigned Long (ULs)"
        except:
            self.err = "Invalid Signed Long (SL)"

    def unsignedDecimal(self):
        if self.data == "":
            self.data = "0.0"
        try:
            if self.data.find("-") != -1:
                self.err = "Invalid UnSigned Decimal (UD-)"
            else:
                if self.data.find(".") == -1:
                    self.data = self.data + "." + (self.rem*"0")
                self.work = float(self.data)
                dec = self.data.split(".", self.rem)
                if len(dec[0]) > self.quo - (self.rem + 1):
                    self.err = "Invalid Unsigned Decimal (UDs)"
                elif len(dec[1]) > self.rem:
                    self.err = "Invalid Unsigned Decimal (UDd)"
                else:
                    self.data = self.data + ((self.rem - len(dec[1]))*"0")
                    self.disp = self.data.rjust(self.quo)
                    d = len(self.disp) - self.quo
                    if d > 0:
                        self.disp = self.disp[d:]
        except:
            self.err = "Invalid UnSigned Decimal (UD)"

    def signedDecimal(self):
        if self.data == "":
            self.data = "0.0"
        try:
            s = self.data.find("-")
            if s == (len(self.data) - 1):
                self.data = self.data.replace("-", "")
                self.data = "-" + self.data
            if self.data.find(".") == -1:
                self.data = self.data + "." + (self.rem*"0")
            self.work = float(self.data)
            dec = self.data.split(".", self.rem)
            if len(dec[0]) > self.quo - (self.rem + 1):
                self.err = "Invalid Signed Decimal (SDs)"
            elif len(dec[1]) > self.rem:
                self.err = "Invalid Signed Decimal (SDd)"
            else:
                self.data = self.data + ((self.rem - len(dec[1]))*"0")
                s = self.data.find("-")
                if s != -1:
                    self.data = self.data.replace("-", "")
                    self.data = self.data + "-"
                else:
                    self.data = self.data + " "
                self.disp = self.data.rjust(self.quo)
                d = len(self.disp) - self.quo
                if d > 0:
                    self.disp = self.disp[d:]
        except:
            self.err = "Invalid Signed Decimal (SD)"

def clicked(*args):
    print "row", args[2], "col", args[3]

def quit(*args):
    print args

if __name__ == "__main__":
    heads = ("ABC Company (Pty) Limited", "",
        "Financial Statements for the Period Ending 2008-02-29")
    cols = (
        (
        "",
        "-------------", "-- Month-01 -","------------ ",
        "-------------", "-- Month-02 -","------------ ",
        "-------------", "-- Month-03 -","------------ ",
        "-------------", "-- Month-04 -","------------ ",
        "-------------", "-- Month-05 -","------------ ",
        "-------------", "-- Month-06 -","------------ ",
        "-------------", "-- Month-07 -","------------ ",
        "-------------", "-- Month-08 -","------------ ",
        "-------------", "-- Month-09 -","------------ ",
        "-------------", "-- Month-10 -","------------ ",
        "-------------", "-- Month-11 -","------------ ",
        "-------------", "-- Month-12 -","------------ ",
        "-------------", "--- Totals --","------------ "),
        (
        "Description",
        "Current-Year ", "   Last-Year ", "      Budget ",
        "Current-Year ", "   Last-Year ", "      Budget ",
        "Current-Year ", "   Last-Year ", "      Budget ",
        "Current-Year ", "   Last-Year ", "      Budget ",
        "Current-Year ", "   Last-Year ", "      Budget ",
        "Current-Year ", "   Last-Year ", "      Budget ",
        "Current-Year ", "   Last-Year ", "      Budget ",
        "Current-Year ", "   Last-Year ", "      Budget ",
        "Current-Year ", "   Last-Year ", "      Budget ",
        "Current-Year ", "   Last-Year ", "      Budget ",
        "Current-Year ", "   Last-Year ", "      Budget ",
        "Current-Year ", "   Last-Year ", "      Budget ",
        "Current-Year ", "   Last-Year ", "      Budget "))
    form = (
        ("NA", 30, False),
        ("SD", 13.2, True), ("SD", 13.2, False), ("SD", 13.2, False),
        ("SD", 13.2, True), ("SD", 13.2, False), ("SD", 13.2, False),
        ("SD", 13.2, True), ("SD", 13.2, False), ("SD", 13.2, False),
        ("SD", 13.2, True), ("SD", 13.2, False), ("SD", 13.2, False),
        ("SD", 13.2, True), ("SD", 13.2, False), ("SD", 13.2, False),
        ("SD", 13.2, True), ("SD", 13.2, False), ("SD", 13.2, False),
        ("SD", 13.2, True), ("SD", 13.2, False), ("SD", 13.2, False),
        ("SD", 13.2, True), ("SD", 13.2, False), ("SD", 13.2, False),
        ("SD", 13.2, True), ("SD", 13.2, False), ("SD", 13.2, False),
        ("SD", 13.2, True), ("SD", 13.2, False), ("SD", 13.2, False),
        ("SD", 13.2, True), ("SD", 13.2, False), ("SD", 13.2, False),
        ("SD", 13.2, True), ("SD", 13.2, False), ("SD", 13.2, False),
        ("SD", 13.2, True), ("SD", 13.2, False), ("SD", 13.2, False))
    data = [("One",100,100,100,200,200,200,300,300,300,400,400,400,500,500,500,
            600,600,600,700,700,700,800,800,800,900,900,900,1000,1000,1000,
            1100,1100,1100,1200,1200,1200,7800,7800,7800)] * 30

    win = gtk.Window()
    win.set_size_request(800, 600)
    win.get_settings().set_string_property('gtk-font-name', 'courier 10','')
    scrn = gtk.VBox()
    win.add(scrn)

    size = win.get_size()
    width = int(size[0] * .95)
    height = height=int(size[1] * .70)
    swin = ScrollGrid(scrn=scrn, width=width, height=height, heads=heads,
        rows=3, cols=cols, form=form, data=data, event=("button_release_event",
        clicked))

    win.show_all()
    gtk.main()

