from Tkinter import *
from ttk import *


# Customized Toplevel window
class Window(Tk,Toplevel):
    window_title = "Example PyTk window"

    # Named widgets
    w = {}

    # Nested list of menu entries
    menu_struct = [
        # (widget_id, Tk.Widget, submenu_struct[])
        ("file", Menu, dict(label="File", background="#654"), [
            ("save", Menu, dict(label="Save", command=None, background="#543"), []),
            ("quit", Menu, dict(label="Quit", command=lambda:main.destroy()), []),
        ]),
        ("edit", Menu, dict(label="Edit"), []),
        ("options", Menu, dict(label="Options"), [])
    ]

    # Structuring default widgets
    layout = [
        # (widget_id, Tk.Widget, Tk.**args, coord_props, prop_calls(), subwidgets[])
        ("frame", Frame, dict(padding=(5,5,1,1), borderwidth=1, relief="sunken", width=200, height=100),
        (0,0,"NESW",1,1), {"columnconfigure":{"index":0,"weight":1}, "rowconfigure":{"index":1,"weight":1}},
        [
            ("label_1", Label, dict(text="Label 1"), (1,0,"NW"), {}, []),
            ("label_2", Label, dict(text="Label 2"), (1,1,"ES"), {}, []),
            ("label_3", Label, dict(text="Label 3"), (2,0), {}, []),
            ("sizegrip", Sizegrip, dict(), (3,5,"SE"), {}, []),
        ]),
    ]
    coord_props = ("row", "column", "sticky", "rowspan", "columnspan")

    # Create window and widgets
    def __init__(self, super=Tk):
        super.__init__(self)
        self.title(string=self.window_title)
        self.option_add("*tearOff", FALSE)
        self.geometry("300x200")
        
        #help(Style)
        #help(Menu)
        s=Style()
        s.configure(".", background="#ccddff", font=("Ubuntu", 10))
        
        # add menu
        self.menu = Menu(self, tearoff=FALSE, relief=FLAT, background="#665544", foreground="#ffffff")
        self["menu"] = self.menu
        self.menu_construct(self.menu, self.menu_struct)

        # pack widgets
        self.widget_construct(self, self.layout)
        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)

    # Construct submenus
    def menu_construct(self, parent, menu_struct):
        for (id, tkwidget, args, sub_struct) in menu_struct:
            self.w[id] = tkwidget(parent)
            if "command" in args:
                parent.add_command(**args)
            else:
                parent.add_cascade(menu=self.w[id], **args)
            self.menu_construct(self.w[id], sub_struct)

    # Instantiate widgets, add options
    def widget_construct(self, parent, layout_struct):
        for (id, tkwidget, args, coord, calls, sub_struct) in layout_struct:
            self.w[id] = tkwidget(parent, **args)
            self.widget_pack(self.w[id], coord)
            self.widget_calls(self.w[id], calls)
            self.widget_construct(self.w[id], sub_struct)

    # Grid packing
    def widget_pack(self, widget, coord):
        if type(coord) is not dict:
           coord = dict(zip(self.coord_props[0:len(coord)], coord))
        if not "sticky" in coord:
           coord["sticky"] = (N,S,E,W)
        widget.grid(**coord)

    # Call property methods
    def widget_calls(self, widget, calls):
        for func,args in calls.items():
            getattr(widget, func)(**args)


main = Window()
main.mainloop()

