#!/usr/bin/python

# calc.py SJ
# simple calculator with DnD memory

import pygtk
import gtk
import calc_mem


class Calc:
    def __init__(self):
        self.bstrings = [ 
                ['+', '-', '*', '/'],
                ['1', '2', '3', '('],
                ['4', '5', '6', ')'],
                ['7', '8', '9', '<-'],
                ['.', '0', '=', 'C'],
                ['', '', '', 'M']
                ]
        self.cols = 4
        self.rows = len(self.bstrings)
        self.draw()
        self.mem = None
        

    def draw(self):
        """Main window layout setup."""
        self.win = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.win.connect("delete_event", self.delete)
        self.win.set_title("Calculator example")
        self.win.set_size_request(200, 200)
        box = gtk.VBox()
        self.win.add(box)
        #box.show()

        # output display
        textV = gtk.TextView()
        box.pack_start(textV)
        #textV.show()
        textV.set_editable(True)
        textV.set_cursor_visible(True)
        textV.set_accepts_tab(False)
        textV.grab_focus()
        textV.set_wrap_mode(gtk.WRAP_NONE)

        # text buffer to update
        self.textBuffer = textV.get_buffer()

        # DnD drop setup
        textV.drag_dest_set(gtk.DEST_DEFAULT_DROP,
            [("text", 0, 80)], gtk.gdk.ACTION_COPY)
        textV.connect('drag_motion', self.motion_cb)
        #textV.connect('drag_drop', self.dropCallBack)
        textV.connect('drag_data_received', self.receiveCallBack)

        # DnD drag setup
        textV.drag_source_set(gtk.gdk.BUTTON1_MASK,
            [("text", 0, 80)], gtk.gdk.ACTION_COPY)
        textV.connect("drag_data_get", self.sendCallBack)

        table = gtk.Table(self.cols, self.rows, False)
        box.pack_start(table)

        # create buttons
        for r in range(self.rows):
            sRow = self.bstrings[r]
            for c in range(len(sRow)):
                buttonString = sRow[c]
                but = gtk.Button(buttonString)
                but.connect("clicked", self.handlePress, buttonString)
                table.attach(but, c, c+1, r+1, r+2) 
                but.unset_flags(gtk.CAN_FOCUS)
                #but.show()
        #table.show()
        # show all recursively
        self.win.show_all()


    # DnD handlers
    def sendCallBack(self, widget, context, selection, targetType, eventTime):
        # print 'CsendCallBack'
        selection.set(selection.target, 8, self.textBuffer.get_text(
                                    self.textBuffer.get_start_iter(),
                                    self.textBuffer.get_end_iter()))

    def receiveCallBack(self, widget, context, x, y, selection, targetType, time):
        # print 'CreceiveCallBack'
        tBuf = widget.get_buffer()
        #tBuf.insert_at_cursor(selection.data)
        tBuf.set_text(selection.data)

    # setupd DnD context at drag gesture
    def motion_cb(self, wid, context, x, y, time):
        #print 'Cmotion_cb'
        context.drag_status(gtk.gdk.ACTION_COPY, time)
        return True


    # button handler
    def handlePress(self, widget, data):
        if data == '=':
            try:
                res = str(eval(self.textBuffer.get_text(
                                    self.textBuffer.get_start_iter(),
                                    self.textBuffer.get_end_iter())))
            except:
                res = "error"
            self.textBuffer.set_text(res)

        elif data == '<-':
            removeEnd = self.textBuffer.get_end_iter()
            removeStart = removeEnd.copy()
            if removeStart.backward_char():
                self.textBuffer.delete(removeStart, removeEnd)

        elif data == 'C':
            self.textBuffer.set_text("")

        elif data == 'M':
            if self.mem == None:
                # create new memory window next to this
                x, y = self.win.get_position()
                h, w = self.win.get_size()
                self.mem = calc_mem.Memory(5, x + w + 20, y)
                # widget.set_sensitive(False)

        else:
            self.textBuffer.insert_at_cursor(data)
        
    def delete(self, widget, event=None):
        """Main program quit callback."""
        gtk.main_quit()
        return False

    def main(self):
        gtk.main()


# call main metkod
if __name__ == "__main__":
    calc_object = Calc()
    calc_object.main()

