#
# $Id: editorApp.py,v 1.1.1.1 2003/03/22 05:15:49 dbelan2 Exp $
#
# Model Editor
#
# first prototype Chak Wai So
# second prototype Steven Van Hoof and Sofie Verbrugge
#
# Modified by David Bélanger
# Code added/modified is identified by comments.
#
# $Log: editorApp.py,v $
# Revision 1.1.1.1  2003/03/22 05:15:49  dbelan2
# Initial import of all public_html on www.cs.mcgill.ca.
#
# Revision 1.2  2001/09/20 15:54:39  dbelan2
# Menu item 'Export to exp env' and its action added.
#
#
#


from Tkinter import *
from simclasses import *
import tkMessageBox
import tkFileDialog
import MySimpleDialog

class Editor:
    def __init__(self):


        # root window
        self.root = Tk()
        #self.root.protocol("WM_DELETE_WINDOW", self.Quit)

        self.toolMode = StringVar()

        #  Some variables used for linking
        self.link_mode = 0
        self.linkObj = None
        self.linkHandle = None
	self.drag_mode = 0

        self.BuildToolBox()
        self.BuildPopupMenu()
        self.BuildMenu()

        # Canvas
        self.drawing = Canvas(self.root, bg="white")
        self.drawing.bind("<Button-3>", self.popup)
        self.drawing.bind("<Button-1>", self.left_click)
        self.drawing.bind("<B1-Motion>", self.drag)
        self.drawing.bind("<ButtonRelease-1>", self.end_drag)
        self.drawing.bind("<Motion>", self.mouse_move)
        self.drawing.pack(fill=BOTH, expand = 1)

        # the model
        self.model = Model(self.drawing)

	self.title = 'Visual model editor'
        self.root.title(self.title)
        self.root.mainloop()

    def BuildToolBox(self):
        toolbox = Frame(self.root)

        w = Label(toolbox, text="Toolbox")
        w.pack(side=TOP, padx = 2, pady=2)

        MODES = [ ("Select", 1),("Adder", 2), ("Constant", 3), ("Negator", 4), ("Multiplier", 5), ("Divider", 6), ("Integrator", 9), ("Link", 8)  ]

        self.toolMode.set("Select")

        for text, mode in MODES:
            b = Radiobutton(toolbox, text=text, variable=self.toolMode, value=text, indicatoron = 0, width = 10, wraplength = 60)
            b.pack(side=TOP , padx = 2, pady = 2)

        toolbox.pack(side=LEFT, fill=Y)

    def BuildMenu(self):
        menu = Menu(self.root)
        self.root.config(menu=menu)

        self.filemenu = Menu(menu, tearoff = 0)
        menu.add_cascade(label="File", menu=self.filemenu)
        self.filemenu.add_command(label="New", command=self.ClearAll)
        self.filemenu.add_command(label="Open...", command=self.Open)
        self.filemenu.add_command(label="Save", command=self.Save, state = 'disabled')
        self.filemenu.add_command(label="Save as", command=self.SaveAs)
        self.filemenu.add_separator()
        self.filemenu.add_command(label="Export to ps", command=self.Print)
        self.filemenu.add_separator()


        # next 2 lines added by David
        self.filemenu.add_command(label="Export to exp env", command=self.Export)
        self.filemenu.add_separator()
        # end code added


        self.filemenu.add_command(label="Exit", command = self.Quit)

    def BuildPopupMenu(self):
        self.popup_menu = Menu(self.root , tearoff = 0)

        self.popup_menu.add_command(label = "Delete Object", command = self.Delete)
        self.popup_menu.add_separator()
        self.popup_menu.add_command(label = "Link Output To...", command = self.LinkOutput)
        self.popup_menu.add_command(label = "Delete Output Link", command = self.DeleteLink)
        self.popup_menu.add_separator()
        self.popup_menu.add_command(label = "Set Name", command = self.SetDescription)
        self.popup_menu.add_separator()
        self.popup_menu.add_command(label = "Set Value...", command = self.SetValue)
        self.popup_menu.add_command(label = "Set Output Adjustment Value...", command = self.SetShowAdjustment)
        self.popup_menu.add_command(label = "Toggle Simulator Output", command = self.ToggleSimOut)

    def Delete(self):
        obj = self.model.Coord2obj(self.pop_x, self.pop_y)
        if obj != None:
            self.model.Remove(obj)
        
    def DeleteLink(self):
        obj = self.model.Coord2obj(self.pop_x, self.pop_y)
        if obj != None:
            obj.DeleteAllOutputLink()
        
    def LinkOutput(self):
        self.linkObj = self.model.Coord2obj(pop_x, pop_y)
        if self.linkObj == None:
            return
        out_pos = LinkObj.GetOutputCoord()
        self.linkHandle = drawing.create_line(out_pos[0], out_pos[1], pop_x, pop_y, tags = "LINK")
        link_mode = 1
    
    def SetValue(self):
        obj = self.model.Coord2obj(self.pop_x, self.pop_y)
        if obj == None or obj.__class__.__name__ != 'Constant':
            return
        rtr = MySimpleDialog.askfloat("Set Value", "Enter the new value for this constant:", minvalue=-1000, maxvalue=1000)
        if rtr != None:
            obj.SetValue(rtr)
        
    def SetDescription(self):
        obj = self.model.Coord2obj(self.pop_x, self.pop_y)
        if obj == None:
            return
        rtr = MySimpleDialog.askstring("Set name", "Enter the name for this component:", initialvalue= obj.tag)
        if rtr != None:
        	if self.model.SetTag(obj , rtr):
                    tkMessageBox.showwarning("Error", "Name exists already")
        
    def SetShowAdjustment(self):
        obj = self.model.Coord2obj(self.pop_x, self.pop_y)
        if obj == None:
            return
        rtr = MySimpleDialog.askfloat("Set Value", "Enter the new value for output adjustment:", minvalue=-1000, maxvalue=1000)
        if rtr != None:
            obj.SetShowAdjustment(rtr)
                
    def ToggleSimOut(self):
        obj = self.model.Coord2obj(self.pop_x, self.pop_y)
        if obj != None:
            obj.ToggleShowOutput()
        
    def popup(self, event):
        self.pop_x = event.x
        self.pop_y = event.y
        #svh only show pop-up menu if we can do something
        temp = self.model.Coord2obj(event.x, event.y)
        if temp == None:
            return
        #svh
        self.popup_menu.post(event.x_root, event.y_root)
   
    def left_click(self, event):
        self.pop_x = event.x
        self.pop_y = event.y

        if self.toolMode.get() == "Select":
		self.moving = self.model.Coord2obj(event.x, event.y)
		if self.moving != None:
            		self.oldx = event.x
	                self.oldy = event.y
        	        self.drag_mode = 1
		return

	if self.toolMode.get() == "Link":
		temp = self.model.Coord2obj(event.x, event.y)
		if self.link_mode == 0:
		        self.linkObj = temp
		        if self.linkObj != None:
			        out_pos = self.linkObj.GetOutputCoord()
			        self.linkHandle = self.drawing.create_line(out_pos[0], out_pos[1], self.pop_x, self.pop_y, tags = "LINK")
				self.link_mode = 1
		else:
			if temp == None:
				relay = Relay(self.pop_x, self.pop_y)
		               	self.model.AddObject(relay)
				channel = self.linkObj.SetOutputLink(relay, self.linkHandle)
				self.linkObj = relay
				out_pos = relay.GetOutputCoord()
				self.linkHandle = self.drawing.create_line(out_pos[0], out_pos[1], self.pop_x, self.pop_y, tags = "LINK")
			else:
				self.link_mode = 0
				if temp == self.linkObj:
					self.drawing.delete(self.linkHandle)
				else:
					channel = self.linkObj.SetOutputLink(temp, self.linkHandle)
					if channel == None:
						self.drawing.delete(self.linkHandle)
		return

	if self.toolMode.get() != "Select" and self.toolMode.get() != "Link":
		self.model.Add(self.toolMode.get(), self.pop_x, self.pop_y)
		return
  
    def drag(self, event):
        if self.drag_mode == 1:
            self.moving.Move(event.x - self.oldx, event.y - self.oldy)
            self.oldx = event.x
            self.oldy = event.y

    def end_drag(self, event):
        self.drag_mode = 0
    
    def mouse_move(self, event):
        if self.link_mode == 1:
            temp = self.drawing.coords(self.linkHandle)
            temp[2] = event.x
            temp[3] = event.y
            self.drawing.coords(self.linkHandle, temp[0], temp[1], temp[2], temp[3])

    def Quit(self):
        if tkMessageBox.askokcancel("Quit", "Do you really wish to quit?"):
            self.root.destroy()

    def Open(self):
        name = tkFileDialog.askopenfilename(filetypes=[("All Files", "*")])
        if name == '':
            return
	self.filemenu.entryconfig(2,state='normal')
	
	self.root.title(self.title + ' ' + name)
        self.model.Open(name)

    def Save(self):
        res = self.model.Save()
	if res:
		tkMessageBox.showwarning("Error", "Model has an algebraic loop, this cannot be simulated")

    def SaveAs(self):
        # fill in values
        f = tkFileDialog.asksaveasfile()
        if (f == None):
            return

	self.filemenu.entryconfig(2,state='normal')
	self.root.title(self.title + ' ' + f.name)
        self.model.Save(f)


    def ClearAll(self):
	self.filemenu.entryconfig(2,state='disabled')
	
	self.root.title(self.title)
        self.model.Clear()

    def Print(self):
        psfile = tkFileDialog.asksaveasfile(filetypes=[("Postscript", ".ps")])
        if (psfile != None):
            self.drawing.postscript(file=psfile.name)

    # code added by David
    def Export(self):
        f = tkFileDialog.asksaveasfile()
        if (f == None):
            return
        else:
            self.model.Export(f)
    # end code added by David


e = Editor()
