#!/usr/bin/env python # example helloworld.py from sugar.activity import activity import pygtk pygtk.require('2.0') import gtk import os import time import rsvg import cairo X = 1200 Y = 900 class LogicCircuitsActivity(activity.Activity): def __init__(self,handle): activity.Activity.__init__(self,handle) self.set_title('Logic Circuits Activity') #begin the program self.build_GUI() self.graphics = graphicsDriver() self.mouse_move = 0 self.clicked = 0 self.buffer = gtk.gdk.Pixmap(self.draw_area.window, 900, 900) self.gc = gtk.gdk.GC(self.buffer) gtk.main() def delete_event(self, widget, event, data=None): print "delete event occurred" return False def destroy(self, widget, data=None): print "destroy signal occurred" gtk.main_quit() def set_placement(self, widget, data=None): self.InputLightButton.set_relief(gtk.RELIEF_NORMAL) self.OutputLightButton.set_relief(gtk.RELIEF_NORMAL) self.AndButton.set_relief(gtk.RELIEF_NORMAL) self.NotButton.set_relief(gtk.RELIEF_NORMAL) self.OrButton.set_relief(gtk.RELIEF_NORMAL) self.XorButton.set_relief(gtk.RELIEF_NORMAL) widget.set_relief(gtk.RELIEF_NONE) self.graphics.changeDrawingType(widget.get_label()) def set_connection(self, widget, data=None): self.input_button.set_relief(gtk.RELIEF_NORMAL) self.output_button.set_relief(gtk.RELIEF_NORMAL) widget.set_relief(gtk.RELIEF_NONE) self.graphics.changeConnectionType(widget.get_label()) def expose(self, widget, event): self.update() def update(self,pos=(0,0)): #update the screen self.context = self.buffer.cairo_create() self.context.rectangle(0, 0, *self.draw_area.window.get_size()) self.context.clip() self.context.set_source_rgb(1, 1, 1) self.context.rectangle(0, 0, *self.draw_area.window.get_size()) self.context.fill() self.context.set_source_rgb(0, 0, 0) self.graphics.update(self.context,pos) self.draw_area.window.draw_drawable(self.gc,self.buffer,0,0,0,0,-1,-1,) def build_GUI(self): #build the GUI self.hpaned = gtk.HPaned() self.draw_area = gtk.DrawingArea() self.v = gtk.VPaned() self.hpaned.add1(self.v) self.v.show() self.v2 = gtk.VPaned() self.v.add1(self.draw_area) self.draw_area.set_size_request(3*X/4, Y) self.draw_area.show() self.draw_area.set_events(gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.KEY_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK ) self.draw_area.connect("motion_notify_event", self.mouse_move) self.draw_area.connect('button-press-event', self.mouse_press) self.draw_area.connect('button-release-event', self.mouse_release) self.draw_area.connect("expose_event", self.expose) self.filechooser = gtk.FileChooserWidget(gtk.FILE_CHOOSER_ACTION_OPEN) self.v.add2(self.filechooser) self.filechooser.set_size_request(3*X/4, Y) self.filechooser.connect("file-activated",self.fileChoosen) self.filechooser.set_current_folder("saves") self.filter = gtk.FileFilter() self.filter.set_name("txt files") self.filter.add_pattern("*.lc") self.filechooser.add_filter(self.filter) self.vpaned = gtk.VPaned() self.hpaned.add2(self.vpaned) self.vpaned.show() self.Frame1 = gtk.Frame("Select an Object to Place") self.vpaned.add1(self.Frame1) self.Frame1.show() self.Frame2 = gtk.Frame("Select a Connection Type") self.vpaned2 = gtk.VPaned() self.vpaned.add2(self.vpaned2) self.vpaned2.show() self.vpaned2.add1(self.Frame2) self.Frame2.show() self.Frame3 = gtk.Frame("Save and Load") self.vpaned2.add2(self.Frame3) self.Frame3.show() self.save_table = gtk.Table(2, 3, False) self.Frame3.add(self.save_table) self.save_table.show() self.filename = gtk.Label("File Name:") self.save_table.attach(self.filename,0,1,0,1) self.filename.show() self.file_text = gtk.Entry(15) self.save_table.attach(self.file_text,1,2,0,1) self.file_text.show() self.SaveButton = gtk.Button(stock = gtk.STOCK_SAVE) self.save_table.attach(self.SaveButton,0,2,1,2) self.SaveButton.show() self.SaveButton.connect("clicked", self.saveFile, None) self.OpenButton = gtk.Button(stock = gtk.STOCK_OPEN) self.save_table.attach(self.OpenButton,0,2,2,3) self.OpenButton.show() self.OpenButton.connect("clicked", self.loadFile, None) and_image = gtk.image_new_from_pixbuf(rsvg.Handle("data/AND.svg").get_pixbuf()) not_image = gtk.image_new_from_pixbuf(rsvg.Handle("data/NOT.svg").get_pixbuf()) or_image = gtk.image_new_from_pixbuf(rsvg.Handle("data/OR.svg").get_pixbuf()) xor_image = gtk.image_new_from_pixbuf(rsvg.Handle("data/XOR.svg").get_pixbuf()) inputlight_image = gtk.image_new_from_pixbuf(rsvg.Handle("data/redlight.svg").get_pixbuf()) outputlight_image = gtk.image_new_from_pixbuf(rsvg.Handle("data/redlight.svg").get_pixbuf()) self.object_table = gtk.Table(1, 6, False) self.Frame1.add(self.object_table) self.object_table.show() self.object_table.set_size_request(X/4,2*Y/4) self.InputLightButton = gtk.Button("Input Light") self.OutputLightButton = gtk.Button("Output Light") self.AndButton = gtk.Button("And") self.NotButton = gtk.Button("Not") self.OrButton = gtk.Button("Or") self.XorButton = gtk.Button("Xor") self.InputLightButton.connect("clicked", self.set_placement, None) self.OutputLightButton.connect("clicked", self.set_placement, None) self.AndButton.connect("clicked", self.set_placement, None) self.NotButton.connect("clicked", self.set_placement, None) self.OrButton.connect("clicked", self.set_placement, None) self.XorButton.connect("clicked", self.set_placement, None) self.InputLightButton.set_relief(gtk.RELIEF_NONE) self.AndButton.set_image(and_image) self.NotButton.set_image(not_image) self.OrButton.set_image(or_image) self.XorButton.set_image(xor_image) self.InputLightButton.set_image(inputlight_image) self.OutputLightButton.set_image(outputlight_image) self.object_table.attach(self.InputLightButton,0,1,0,1) self.object_table.attach(self.OutputLightButton,0,1,1,2) self.object_table.attach(self.AndButton,0,1,2,3) self.object_table.attach(self.NotButton,0,1,3,4) self.object_table.attach(self.OrButton,0,1,4,5) self.object_table.attach(self.XorButton,0,1,5,6) self.InputLightButton.show() self.OutputLightButton.show() self.AndButton.show() self.NotButton.show() self.OrButton.show() self.XorButton.show() self.connection_table = gtk.Table(1,2,False) self.Frame2.add(self.connection_table) self.connection_table.show() self.connection_table.set_size_request(X/4,Y/4) self.input_button = gtk.Button("Input") self.output_button = gtk.Button("Output") self.input_button.connect("clicked", self.set_connection, None) self.output_button.connect("clicked", self.set_connection, None) self.connection_table.attach(self.input_button,0,1,0,1) self.connection_table.attach(self.output_button,0,1,1,2) self.input_button.set_relief(gtk.RELIEF_NONE) self.input_button.show() self.output_button.show() self.set_canvas(self.hpaned) self.show_all() def mouse_press(self, widget, event): if self.clicked + .1 < time.time(): if event.button == 1: self.graphics.button1((event.x,event.y)) if event.button == 2: self.graphics.button2((event.x,event.y)) if event.button == 3: self.graphics.button3((event.x,event.y)) self.update((event.x,event.y)) self.clicked=time.time() def mouse_release(self, widget, event): if event.button == 1: if self.graphics.pressed != None: self.graphics.pressed.clicked = False self.graphics.pressed = None def mouse_move(self, widget, event): if self.mouse_move == 3: if self.graphics.pressed != None: self.graphics.pressed.move((event.x,event.y)) self.update((event.x,event.y)) self.mouse_move = 0 self.mouse_move += 1 self.mousePositions = (event.x,event.y) def saveFile(self, widget, event): text = self.file_text.get_text() save(text) def loadFile(self, widget, event): self.draw_area.hide() self.filechooser.show() def fileChoosen(self, widget): filename = widget.get_filename() load(filename) self.draw_area.show() self.filechooser.hide() class Light: def __init__(self, position): self.color = "red" self.svg = rsvg.Handle("data/" +self.color+"light.svg") self.pos = position self.mousePos = (0,0) self.clicked = False def change_color(self): if self.color == "red": self.color = "green" elif self.color == "green": self.color = "red" self.update_image() calculate() def set_color(self, color): if color == "red": self.color = "red" elif color == "green": self.color = "green" def is_clicked(self, pos): self.mousePos = pos self.clicked = True def get(self): if self.color == "red": return 0 return 1 def move(self, pos): x = pos[0]-self.pos[0] y = pos[1]-self.pos[1] if int(x + self.pos[0]) in range(0,900): x = x + self.pos[0] else: x = self.pos[0] if int(y + self.pos[1]) in range(0,900): y = y + self.pos[1] else: y = self.pos[1] self.pos = (x,y) #self.mousePos = pos for i in connections: i.update() def update_image(self): self.svg = rsvg.Handle("data/" +self.color+"light.svg") def draw(self, context): context.translate(self.pos[0]-self.svg.props.width/2, self.pos[1]-self.svg.props.height/2) self.svg.render_cairo(context) context.translate(-1*(self.pos[0]-self.svg.props.width/2), -1*(self.pos[1]-self.svg.props.height/2)) class Circuit: def __init__(self, pos, max_inputs, text,input_pos, output_pos): self.input_positions = input_pos self.output_positions = output_pos self.svg = rsvg.Handle("data/" +text+".svg") self.text = text self.pos = pos self.inputs = [] self.outputs = [] self.max_inputs = max_inputs self.clicked = False self.mousePos = (0,0) def add_input(self, input_object): if len(self.inputs) > 0 and self.inputs[0].pos[1] > input_object.pos[1]: self.inputs = [input_object,self.inputs[0]] else: self.inputs.append(input_object) def is_clicked(self, pos): self.mousePos = pos self.clicked = True def add_output(self, output_object): self.outputs.append(output_object) def draw(self, context): i = 0 context.translate(self.pos[0]-self.svg.props.width/2, self.pos[1]-self.svg.props.height/2) self.svg.render_cairo(context) context.translate(-1*(self.pos[0]-self.svg.props.width/2), -1*(self.pos[1]-self.svg.props.height/2)) context.set_source_rgb(1,0,0) while i < len(self.inputs): context.move_to(self.pos[0]+self.input_positions[i][0],self.pos[1]+self.input_positions[i][1]) context.line_to(*self.inputs[i].pos) context.stroke() i += 1 context.set_source_rgb(0,0,1) for i in self.outputs: context.move_to(self.pos[0]+self.output_positions[0],self.pos[1]+self.output_positions[1]) context.line_to(*i.pos) context.stroke() def move(self, pos): x = pos[0]-self.mousePos[0] y = pos[1]-self.mousePos[1] mpx = pos[0] mpy = pos[1] if int(x + self.pos[0]) in range(0,900): x = x + self.pos[0] else: x = self.pos[0] mpx = self.mousePos[0] if int(y + self.pos[1]) in range(0,900): y = y + self.pos[1] else: y = self.pos[1] mpy = self.mousePos[1] self.pos = (x,y) self.mousePos = (mpx,mpy) for i in connections: i.update() def calculate(self): pass class Not(Circuit): def __init__(self, pos): Circuit.__init__(self, pos, 1, "NOT",[(-45,0)],(45,0)) self.name = "not" def calculate(self): if not self.inputs[0].get(): self.outputs[0].set_color("green") else: self.outputs[0].set_color("red") class And(Circuit): def __init__(self, pos): Circuit.__init__(self, pos, 2, "AND", [(-45,-10),(-45,10)],(45,0)) self.name = "and" def calculate(self): if self.inputs[0].get() and self.inputs[1].get(): self.outputs[0].set_color("green") else: self.outputs[0].set_color("red") class Or(Circuit): def __init__(self, pos): Circuit.__init__(self, pos, 2, "OR", [(-45,-10),(-45,10)],(45,0)) self.name = "or" def calculate(self): if self.inputs[0].get() or self.inputs[1].get(): self.outputs[0].set_color("green") else: self.outputs[0].set_color("red") class Xor(Circuit): def __init__(self, pos): Circuit.__init__(self, pos, 2, "XOR", [(-45,-10),(-45,10)],(45,0)) self.name = "xor" def calculate(self): if not self.inputs[0].get() == self.inputs[1].get(): self.outputs[0].set_color("green") else: self.outputs[0].set_color("red") class connection: def __init__(self, circuit, light): self.light = light self.circuit = circuit x1 = light.pos[0] y1 = light.pos[1] if self.light in self.circuit.inputs: i = self.circuit.inputs.index(self.light) x2 = self.circuit.pos[0]+self.circuit.input_positions[i][0] y2 = self.circuit.pos[1]+self.circuit.input_positions[i][1] else: x2 = self.circuit.pos[0]+self.circuit.output_positions[0] y2 = self.circuit.pos[1]+self.circuit.output_positions[1] if x1-x2 == 0: self.slope = 0 elif x1x2: self.range = (x2,x1) self.slope = 1.0*(y2-y1)/(x2-x1) self.intercept = y1 - self.slope*x1 calculate() def update(self): x1 = self.light.pos[0] y1 = self.light.pos[1] if self.light in self.circuit.inputs: i = self.circuit.inputs.index(self.light) x2 = self.circuit.pos[0]+self.circuit.input_positions[i][0] y2 = self.circuit.pos[1]+self.circuit.input_positions[i][1] else: x2 = self.circuit.pos[0]+self.circuit.output_positions[0] y2 = self.circuit.pos[1]+self.circuit.output_positions[1] if x1-x2 == 0: self.slope = 0 elif x1x2: self.range = (x2,x1) self.slope = 1.0*(y2-y1)/(x2-x1) self.intercept = y1 - self.slope*x1 def in_range(self,x): if x > self.range[0] and x < self.range[1]: return True return False def get_error(self, (x, y)): return self.intercept + self.slope*x - y def destroy(self): if self.light in self.circuit.inputs: del self.circuit.inputs[self.circuit.inputs.index(self.light)] elif self.light in self.circuit.outputs: del self.circuit.outputs[self.circuit.outputs.index(self.light)] del connections[connections.index(self)] def add_circuit(pos, string): if string.lower() == "not": circuits.append(Not(pos)) if string.lower() == "or": circuits.append(Or(pos)) if string.lower() == "and": circuits.append(And(pos)) if string.lower() == "xor": circuits.append(Xor(pos)) def is_over(pos, item): if item.pos[0]-item.svg.props.width/2 < pos[0] < item.pos[0]+item.svg.props.width/2 and \ item.pos[1]-item.svg.props.height/2 < pos[1] < item.pos[1]+item.svg.props.height/2: return True return False def connect(light, circuit): if input_or_output == "Output": if not circuit.outputs and light not in circuit.inputs: connected = False for i in circuits: if light in i.outputs: connected = True if not connected: circuit.add_output(light) connections.append(connection(circuit,light)) elif input_or_output == "Input": if len(circuit.inputs) != circuit.max_inputs \ and light not in circuit.inputs and light not in circuit.outputs: circuit.add_input(light) connections.append(connection(circuit,light)) def calculate(): for item in xrange(55): for i in circuits: if i.outputs and len(i.inputs) == i.max_inputs: i.calculate() for i in circuits: for item in i.outputs: item.update_image() class graphicsDriver: def __init__(self, input_size=(900,900)): global pressing_lights, non_pressing_lights, clock, size global circuits, drawing, font, input_or_output, connections size = input_size connections = [] pressing_lights = [] non_pressing_lights = [] pos = 10 circuits = [] drawing = "Input Light" self.selected = None input_or_output = "Input" self.pressed = None def changeDrawingType(self, text): global drawing drawing = text def changeConnectionType(self, text): global input_or_output input_or_output = text def button1(self,pos): clicked = [] for i in pressing_lights: if is_over(pos, i): i.change_color() clicked.append(i) for i in non_pressing_lights: if is_over(pos, i): clicked.append(i) moused_over = False for i in circuits: if is_over(pos,i): clicked.append(i) if len(clicked) > 0: clicked[-1].is_clicked(pos) self.pressed = clicked[-1] over = False for i in circuits: if is_over(pos,i): over = True for i in pressing_lights: if is_over(pos,i): over = True for i in non_pressing_lights: if is_over(pos,i): over = True if drawing.lower() in ("or", "and", "not", "xor"): temp = Not(pos) if not over: add_circuit(temp.pos, drawing) if "light" in drawing.lower(): temp = Light(pos) if not over: if "input" in drawing.lower(): pressing_lights.append(temp) elif "output" in drawing.lower(): non_pressing_lights.append(temp) def button2(self,pos): deleted = False for i in non_pressing_lights: if is_over(pos, i): del non_pressing_lights[non_pressing_lights.index(i)] if self.selected == i: self.selected = None for item in circuits: if i in item.inputs: del item.inputs[item.inputs.index(i)] deleted = True if i in item.outputs: del item.outputs[item.outputs.index(i)] deleted = True for i in pressing_lights: if is_over(pos, i): del pressing_lights[pressing_lights.index(i)] if self.selected == i: self.selected = None for item in circuits: if i in item.inputs: del item.inputs[item.inputs.index(i)] deleted = True if i in item.outputs: del item.outputs[item.outputs.index(i)] deleted = True for i in circuits: if is_over(pos, i): circuits.remove(i) deleted = True if self.selected == i: self.selected = None if not deleted: connects = [] for i in connections: if i.in_range(pos[0]): connects.append(i) if len(connects) > 0: closest = connects[0] for i in connects: if abs(i.get_error(pos)) < abs(closest.get_error(pos)): closest = i distance = closest.get_error(pos) if abs(distance) < 12: closest.destroy() def button3(self, pos): over = False for i in pressing_lights: if is_over(pos, i): if self.selected and self.selected in circuits: connect(i, self.selected) self.selected = None elif self.selected == i: self.selected = None elif not self.selected: self.selected = i over = True for i in non_pressing_lights: if is_over(pos, i): if self.selected and self.selected in circuits: connect(i, self.selected) self.selected = None elif self.selected == i: self.selected = None elif not self.selected: self.selected = i over = True for i in circuits: if is_over(pos, i): if self.selected in non_pressing_lights or \ self.selected in pressing_lights and self.selected: connect(self.selected, i) self.selected = None elif self.selected == i: self.selected = None elif not self.selected: self.selected = i over = True if not over: self.selected = None def update(self, context,pos): if self.selected: context.set_source_rgb(1, 1, 0) context.rectangle(self.selected.pos[0]-self.selected.svg.props.width/2-2, self.selected.pos[1]-self.selected.svg.props.height/2-2, self.selected.svg.props.width+4,self.selected.svg.props.height+4) context.fill() for i in circuits: i.draw(context) for i in pressing_lights: i.draw(context) for i in non_pressing_lights: i.draw(context) context.set_font_size(20) moused_over = False context.set_source_rgb(0,0,0) for i in circuits: if is_over(pos,i) and not moused_over: context.move_to(pos[0]+10,pos[1]-10) context.show_text(i.name) moused_over=True def save(name): if name == "": files = [] for i in os.listdir(os.path.join("saves", "")): if ".lc" in i: item = i.split(".lc")[0] if "save" in item: item = item.split("save")[1] files.append(int(item)) try: name = "save" + str(max(files) + 1) except: name = "save1" open_file = open(os.path.join("saves", name + ".lc"), "w") list1 = {} for i in pressing_lights: list1[i.pos[0]] = i.pos[1] list2 = {} for i in non_pressing_lights: list2[i.pos[0]] = i.pos[1] circuit_list = "" for i in circuits: circuit_list += str(i.pos[0]) + ":" + str(i.pos[1]) circuit_list += ":" + i.name circuit_list += "," input_connect = "" for i in circuits: for item in i.inputs: input_connect += str(item.pos[0]) + ":" + \ str(item.pos[1]) input_connect += ";" input_connect += str(i.pos[0])+":"+str(i.pos[1]) input_connect += "," output_connect = "" for i in circuits: for item in i.outputs: output_connect += str(item.pos[0]) + ":" + \ str(item.pos[1]) output_connect += ";" output_connect += str(i.pos[0])+":"+str(i.pos[1]) output_connect += "," open_file.write(str(list1) + "\n") open_file.write(str(list2) + "\n") open_file.write(circuit_list + "\n") open_file.write(input_connect + "\n") open_file.write(str(output_connect) + "\n") def load(name): global circuits, pressing_lights, non_pressing_lights, input_or_output try: open_file = open(os.path.join(name), "r").readlines() except: return circuits = [] pressing_lights = [] non_pressing_lights = [] for i in open_file[0][1:-2].split(","): if i: pressing_lights.append(Light((float(i.split(":")[0].strip()), float(i.split(":")[1].strip())))) for i in open_file[1][1:-2].split(","): if i: non_pressing_lights.append(Light((float(i.split(":")[0].strip()), float(i.split(":")[1].strip())))) for i in open_file[2].strip().split(","): if i: add_circuit((float(i.split(":")[0]), float(i.split(":")[1])), i.split(":")[2]) input_or_output = "Input" for l in open_file[3].split(","): i = l.strip() if i: for item in pressing_lights: if item.pos == (float(i.split(";")[0].split(":")[0]), float(i.split(";")[0].split(":")[1])): light = item for item in non_pressing_lights: if item.pos == (float(i.split(";")[0].split(":")[0]), float(i.split(";")[0].split(":")[1])): light = item for item in circuits: if item.pos == (float(i.split(";")[1].split(":")[0]), float(i.split(";")[1].split(":")[1])): circuit = item connect(light, circuit) input_or_output = "Output" for l in open_file[4].split(","): i = l.strip() if i: for item in pressing_lights: if item.pos == (float(i.split(";")[0].split(":")[0]), float(i.split(";")[0].split(":")[1])): light = item for item in non_pressing_lights: if item.pos == (float(i.split(";")[0].split(":")[0]), float(i.split(";")[0].split(":")[1])): light = item for item in circuits: if item.pos == (float(i.split(";")[1].split(":")[0]), float(i.split(";")[1].split(":")[1])): circuit = item connect(light, circuit) input_or_output = "Input"