from tkinter import * from ButtonCreator import * from SpeciesDatabase import * import Direction import SpeciesSetup import Species import Rule import Instruction def run (specdb, spec, dbsbsize = 0, rule = None, event = None): root = Tk() RuleEditor = SetupFrame(root, rule, spec, dbsbsize) root.mainloop() class SetupFrame: """A class to create the base GUI for Rule Editor""" def __init__(self, parent, rule, spec, dbsbsize, width=700, height=600): self.parent = parent self.width = width self.height = height self.rule = rule self.isNew = False self.specdb = SpeciesDatabase.getInstance() self.spec = spec self.instructions = [] self.pred = None self.dbsbsize = dbsbsize self.predText = StringVar() """Checks if the species is already in the database, if not adds it""" if not self.spec.kind in self.specdb.species: self.specdb.addSpecies(self.spec) self.isNew = True self.parent.geometry(str(width)+"x"+str(height)) self.frame = Frame(self.parent, width=width, height=height) self.frame.pack() """Add the title""" title = Label(self.frame, text="Rule Editor",fg="black") title.pack(fill=X) """If non-null rule, display rule""" if rule != None: ruleLabel = Label(self.frame, text = "Current Rule: " + str(rule)) ruleLabel.pack(fill = X, pady = 10) self.buttonBox(self.frame) self.createPredicate(self.frame) self.speciesBox(self.frame) self.createInstruction(self.frame) def buttonBox(self, parent): """Buttons to save or cancel""" buttonFrame = Frame(parent) buttonFrame.pack(side = BOTTOM, pady = 10) ButtonCreator(buttonFrame, "Cancel", self.cancel,\ width = 8, packOption = LEFT) ButtonCreator(buttonFrame, "Done", self.done,\ width = 8, packOption = RIGHT) def createPredicate(self,parent): """Creates and fills the predicate frame""" predFrame = Frame(parent, width = 200, height = 500) predFrame.pack(side = LEFT) Label(predFrame, text = "Edit Predicate").pack(pady = 5) """Not CheckButton: Will negate whole predicate""" self.notButton = IntVar() Checkbutton(predFrame, text = "Not",\ variable = self.notButton).pack(side = TOP) """Creates radiobuttons to specify quantity or directional""" radioFrame = Frame(predFrame, width = 10, height = 20).pack(side = LEFT) self.predType = IntVar() ButtonCreator(radioFrame, "Quantity", radio=1,radiovar=self.predType, \ radioval = 0, radioind = 1, width = 10, packOption = LEFT) ButtonCreator(radioFrame, "Directional", radio = 1, \ radiovar = self.predType, radioval = 1, radioind = 1, \ width = 10, packOption = LEFT) """Creates radiobuttons to specify AND or OR""" self.prepType = IntVar() ButtonCreator(predFrame, "And", radio=1,radiovar=self.prepType, \ radioval = 0, radioind = 1, width = 10) ButtonCreator(predFrame, "Or", radio = 1, \ radiovar = self.prepType, radioval = 1, radioind = 1, \ width = 10) """For Quantity Predicate, will implement =, <, or > check""" self.compType = IntVar() ButtonCreator(predFrame, "==", radio=1,radiovar=self.compType, \ radioval = 0, radioind = 1, width = 10, packOption = BOTTOM) ButtonCreator(predFrame, "<", radio = 1, \ radiovar = self.compType, radioval = 1, radioind = 1, \ width = 10, packOption = BOTTOM) ButtonCreator(predFrame, ">", radio = 1, \ radiovar = self.compType, radioval = 2, radioind = 1, \ width = 10, packOption = BOTTOM) """Creates a canvas to design a predicate.""" self.predCanvas = Canvas(predFrame, bg = "white",\ width=75, height=75) self.predColors = [["light grey" for y in range(3)] for x in range(3)] self.predClear() self.predCanvas.bind("", self.predCanvasClick) self.predCanvas.bind("", self.predCanvasClick) self.predCanvas.pack(pady = 5) """Clear button for the canvas""" ButtonCreator(predFrame, "Clear", self.predClear, width = 10) """Adds the predicate to the predicate tree""" ButtonCreator(predFrame, "Save", self.predAdd, width = 10) def speciesBox(self, parent): """Creates listbox from species database""" self.listContainer = Frame(parent, bg="darkblue") listLabel = Label(self.listContainer, text="Species Selection",\ bg = "darkblue", fg = "white") listLabel.pack(fill=Y, side=TOP) self.speciesList = Listbox(self.listContainer, height=5) """Creates scrollbar""" scroll = Scrollbar(self.listContainer) scroll.pack(side = RIGHT, fill = Y) scroll.config(command = self.speciesList.yview) l = self.specdb.allSpeciesNames() for name in l: self.speciesList.insert(END, name) self.speciesList.insert(END, "Do Nothing") self.speciesList.insert(END, "Any Dead (pred only)") self.speciesList.insert(END, "Any Live (pred only)") self.speciesList.config(yscrollcommand = scroll.set) self.speciesList.pack(side=TOP) self.listContainer.pack(side = LEFT, padx = 75) def createInstruction(self,parent): """Creates and fills the instruction frame""" instrucFrame = Frame(parent, height = 500) instrucFrame.pack(side = LEFT, pady = 75) Label(instrucFrame, text = "Edit Instruction").pack(pady = 5) """Creates a canvas to design an instruction.""" self.instCanvas = Canvas(instrucFrame, bg = "white",\ width=75, height=75) self.instCanvas.bind("", self.instCanvasClick) self.instCanvas.bind("", self.instCanvasClick) self.instCanvas.pack(pady = 5, side = TOP) self.instColors = [["light grey" for y in range(3)] for x in range(3)] self.instClear() buttonFrame = Frame(instrucFrame) buttonFrame.pack(side = TOP) """Creates a clear button for the canvas""" ButtonCreator(buttonFrame, "Clear", self.instClear, width = 3,\ packOption = RIGHT) """Saves the instruction""" ButtonCreator(buttonFrame, "Add", self.saveInst, width = 3,\ packOption = RIGHT) """A listbox displaying all the saved instructions""" iListFrame = Frame(instrucFrame, width = 15) iListFrame.pack(side = TOP) self.instructionList = Listbox(iListFrame, height=5) """Creates scrollbar""" scroll = Scrollbar(iListFrame) scroll.pack(side = RIGHT, fill = Y) scroll.config(command = self.instructionList.yview) self.instructionList.config(yscrollcommand = scroll.set) self.instructionList.pack(side = TOP, pady = 15) """Remove button removes selected instructions from instructionlist""" ButtonCreator(instrucFrame, "Remove", self.removeInst, width = 3,\ packOption = TOP) def canvasClick(self, canvas, list, event = None): """When the mouse is clicked on the canvas the closest grid square is set to the selected color.""" if self.speciesList.get(ACTIVE) == "Any Dead (pred only)": color = "black" elif self.speciesList.get(ACTIVE) == "Any Live (pred only)": color = "white" elif self.speciesList.get(ACTIVE) == "Do Nothing": color = "light grey" else: color = self.specdb.getColorfromName(self.speciesList.get(ACTIVE)) canvas.itemconfigure(canvas.find_closest(event.x, event.y),\ fill = color) xdir = int(event.x / 25) ydir = int(event.y /25) list[xdir][ydir] = color def clearCanvas(self, canvas, list, event = None): for j in range(3): for i in range(3): canvas.create_rectangle(i*25, j*25,(i+1)*25, (j+1)*25,\ fill="light grey") list[i][j] = "light grey" canvas.itemconfigure(canvas.find_closest(26, 26),\ fill = self.spec.color) list[1][1] = self.spec.color def predClear(self, event = None): self.predText.set("(") self.clearCanvas(self.predCanvas, self.predColors, event) def instClear(self, event = None): self.clearCanvas(self.instCanvas, self.instColors, event) def predCanvasClick(self, event = None): if not (event.x > 25 and event.x < 50 and event.y > 25 and event.y< 50): self.canvasClick(self.predCanvas, self.predColors, event) def instCanvasClick(self, event = None): current = self.speciesList.get(ACTIVE) if current != "Any Dead (pred only)"\ and current != "Any Live (pred only)": self.canvasClick(self.instCanvas, self.instColors, event) def saveInst(self, event = None): """Saves the instruction/s displayed on the instruction canvas""" for j in range(3): for i in range(3): color = self.instColors[i][j] if color != "light grey": spec = self.specdb.getSpeciesfromColor(color) direct = Direction.Direction.getDirection(j, i) instruct = Instruction.Instruction(direct, spec) self.instructions.append(instruct) self.instructionList.insert(END, str(instruct)) print(str(instruct)) print() def removeInst(self, event = None): """Removes an instruction from the list of saved instructions""" self.instructionList.delete(ACTIVE) def predAdd(self, event = None): """Adds the predicate displayed on the predicate canvas to the tree""" count = -1 pred = [] if self.predType.get() == 0: """If the radio button quantity is selected""" count = 0 if self.predType.get() == 1: """If the radio button direction is selected""" pred = [] for i in range(3): for j in range(3): color = self.predColors[j][i] if color != "light grey": if i == 1 and j == 1: pass else: if count == -1: """If the predType is directional""" self.doDirectional(pred, color, i, j) else: """The predicate type is quantity""" count +=1 if count > -1: """Predicate type is quantity""" if self.compType.get() == 2: comp = int.__lt__ elif self.compType.get() == 1: comp = int.__gt__ else: comp = int.__eq__ self.pred = LiveNeighbors(count, comp) else: """Predicate type is directional""" if pred != []: if self.prepType.get() == 0: """an And Predicate""" self.pred = AndPredicate(pred) elif self.prepType.get() == 1: """An OR Predicate""" self.pred = OrPredicate(pred) if self.notButton.get() == 1: """If we want to NOT the whole expression""" self.pred = NotPredicate(self.pred) print("Predicate Added" + str(self.pred)) self.predClear() def doDirectional(self, temp, color, i, j): """The steps to add a directional predcate to temp""" s = self.specdb.getSpeciesfromColor(color) d = Direction.Direction.getDirection(i,j) temp.append(DirectionalTestPredicate(s,d)) def removeSpec(self): """Removes a species from the database that was put there temporarily""" if self.isNew: self.specdb.species.pop(self.spec.kind) self.specdb.speciesByColor.pop(self.spec.color) def cancel(self, event = None): """Loads the Species Selector and destroys this window""" self.removeSpec() self.parent.destroy() SpeciesSetup.run(self.spec) def done(self, event = None): """Saves new rule, Loads the Species Selector,destroys window""" self.removeSpec() #Create a rule and add it to self.spec if self.pred != None and self.instructions != []: rule = Rule.Rule(self.pred, self.instructions) print("Adding a rule: " + str(rule)) self.spec.addRule(rule) self.parent.destroy() print(self.dbsbsize) SpeciesSetup.run(self.spec, self.dbsbsize)