from Tkinter import *

class App:
    __NOOP  = -1
    __PLUS  =  0
    __MINUS =  1
    __TIMES =  2
    __DIV   =  3

    def __init__(self, master):
        self.master = master

        # Create a Tkinter variable to hold the displayed text
        # and set it to "0"
        self.display = StringVar(master)
        self.display.set("0")
        # Also keep the previous result (initially 0)
        self.prevRes = 0.0
        # Flag which indicates next digit starts a new number
        self.cleardisp = TRUE
        # Flag to indicate that the number is < 0
        self.isneg = FALSE

        # Keep track of the current operation
        self.currop = App.__NOOP

        # Keep track of presence of dot in the number
        self.seendot = FALSE

        # Create and arrange widgets
        self.createWidgets(master)

        # Standardize button sizes, since the default
        # behaviour is to accomodate the caption
        # (also make the buttons resize with the form)
        xsize, ysize = master.grid_size()
        for i in range(0, ysize):
          master.grid_rowconfigure(i, minsize=30, weight=1)

        for i in range(xsize):
          master.grid_columnconfigure(i, minsize=45, weight=1)

        # Bind Events to Widgets
        self.bindWidgets()

    def createWidgets(self, master):
        # Create the necessary widgets
        self.btn0     = Button(master, text='0')
        self.btn1     = Button(master, text='1')
        self.btn2     = Button(master, text='2')
        self.btn3     = Button(master, text='3')
        self.btn4     = Button(master, text='4')
        self.btn5     = Button(master, text='5')
        self.btn6     = Button(master, text='6')
        self.btn7     = Button(master, text='7')
        self.btn8     = Button(master, text='8')
        self.btn9     = Button(master, text='9')
        self.btnDot   = Button(master, text='.', command=self.btnDotClick)
        self.btnDigits = (self.btn0, self.btn1, self.btn2, self.btn3, self.btn4,
                          self.btn5, self.btn6, self.btn7, self.btn8, self.btn9)
        self.btnPlus  = Button(master, text='+')
        self.btnMinus = Button(master, text='-')
        self.btnTimes = Button(master, text='x')
        self.btnDiv   = Button(master, text='/')
        self.btnOps = (self.btnPlus, self.btnMinus, self.btnTimes, self.btnDiv)
        self.btnNeg   = Button(master, text='(-)', command=self.btnNegClick)
        self.btnRes   = Button(master, text='=', command=self.btnResClick)
        self.btnCE    = Button(master, text="CE", command=self.btnCEClick)
        self.btnC     = Button(master, text="C", bg="gold", command=self.btnCClick)
        self.lblDisp  = Label(master, textvariable=self.display, anchor=E, relief=SUNKEN, bg="white")

        # Use the Grid Geomatry manager to arrange the widgets
        self.lblDisp.grid(row=0, column=0, columnspan=5, sticky=NSEW)
        self.btnC.grid(row=1, column=0, sticky=NSEW)
        self.btnCE.grid(row=1, column=1, sticky=NSEW)
        self.btnNeg.grid(row=1, column=4, sticky=NSEW)
        self.btn7.grid(row=2, column=0, sticky=NSEW)
        self.btn8.grid(row=2, column=1, sticky=NSEW)
        self.btn9.grid(row=2, column=2, sticky=NSEW)
        self.btnTimes.grid(row=2, column=3, sticky=NSEW)
        self.btnDiv.grid(row=2, column=4, sticky=NSEW)
        self.btn4.grid(row=3, column=0, sticky=NSEW)
        self.btn5.grid(row=3, column=1, sticky=NSEW)
        self.btn6.grid(row=3, column=2, sticky=NSEW)
        self.btnPlus.grid(row=3, column=3, rowspan=3, sticky=NSEW)
        self.btnMinus.grid(row=3, column=4, sticky=NSEW)
        self.btn1.grid(row=4, column=0, sticky=NSEW)
        self.btn2.grid(row=4, column=1, sticky=NSEW)
        self.btn3.grid(row=4, column=2, sticky=NSEW)
        self.btnRes.grid(row=4, column=4, rowspan=2, sticky=NSEW)
        self.btn0.grid(row=5, column=0, columnspan=2, sticky=NSEW)
        self.btnDot.grid(row=5, column=2, sticky=NSEW)

    def bindWidgets(self):
        for w in self.btnDigits:
            w.bind('<1>', self.btnDigitClick)

        for w in self.btnOps:
            w.bind('<1>', self.btnOpClick)

    def btnDigitClick(self, event):
        if self.cleardisp:
            if self.isneg:
                self.display.set('-' + event.widget.cget('text'))
            else:
                self.display.set(event.widget.cget('text'))

        else:
            self.display.set(self.display.get() + event.widget.cget('text'))
        if not (self.cleardisp and event.widget == self.btn0):
            self.cleardisp = FALSE

    def btnDotClick(self):
        if not self.seendot:
            self.display.set(self.display.get() + '.')
            self.seendot = TRUE
        self.cleardisp = FALSE

    def btnOpClick(self, event):
        self.btnResClick()
        if event.widget == self.btnPlus:
            self.currop = App.__PLUS
        elif event.widget == self.btnMinus:
            self.currop = App.__MINUS
        elif event.widget == self.btnTimes:
            self.currop = App.__TIMES
        elif event.widget == self.btnDiv:
            self.currop = App.__DIV


    def btnNegClick(self):
        disp = self.display.get()
        if disp[0] == '-':
           self.display.set(disp[1:])
        else:
            self.display.set('-' + disp)
        self.isneg = not self.isneg

    def btnResClick(self):
        try:
            f = float(self.display.get())
            if self.currop == App.__PLUS:
                self.prevRes = self.prevRes + f
            elif self.currop == App.__MINUS:
                self.prevRes = self.prevRes - f
            elif self.currop == App.__TIMES:
                self.prevRes = self.prevRes * f
            elif self.currop == App.__DIV:
                self.prevRes = self.prevRes / f
            else:
                self.prevRes = f
            if self.prevRes == int(self.prevRes):
                self.prevRes = int(self.prevRes)
            self.display.set(str(self.prevRes))
        except:
            # An error has occured
            self.display.set("ERR")
            self.prevRes = 0.0
        self.currop = App.__NOOP
        self.cleardisp = TRUE
        self.seendot = FALSE
        self.isneg = FALSE

    def btnCEClick(self):
        self.isneg = FALSE
        self.cleardisp = TRUE
        self.seendot = FALSE
        self.display.set('0')

    def btnCClick(self):
        self.isneg = FALSE
        self.cleardisp = TRUE
        self.seendot = FALSE
        self.display.set('0')
        self.currop = App.__NOOP
        self.prevResult = 0.0

if __name__ == '__main__':
    root = Tk()
    app = App(root)
    root.mainloop()