def main(): root = Tk() # Use the if/else statement below if you want to have different window # behavior on smaller screens vs. larger. This will launch the application # fullscreen (no window close/minimize/etc. controls available) on screens # <= 800px wide (e.g. the 7" 800x480 touchscreen), or as a normal 800x480 # floating window on larger screens (e.g. over SSH with X-forwarding on # a desktop PC). Comment this block out if for some reason you want to # enforce a particular window behavior regardless of screen resolution. screen_width = root.winfo_screenwidth() if screen_width > 800: root.geometry('800x480') else: root.attributes('-fullscreen', True) # Use line below to always launch in fullscreen mode (no window close, # minimize or maximize controls available). #root.attributes('-fullscreen', True) # Use line below to launch as a normal 800x480px floating window. This # should not be used for normal tester operation since it would allow # the user to close the GUI and have full access to the underlying OS. #root.geometry('800x480') app = TopLevel(root) root.mainloop()
def main(): root = Tk() root.geometry("300x300+300+300") root.attributes("-fullscreen", True) app = Example(root) root.mainloop()
class VisualizerUI: def __init__(self, width, height, pixelSize, top=False): self._maxWindowWidth = 1024 self._master = Tk() self._q = Queue.Queue() self._hasFrame = False self.x = width self.y = height self._count = self.x * self.y self._values = [] self._leds = [] self._pixelSize = pixelSize self._pixelPad = int(pixelSize / 2) self._pixelSpace = 0 self.initUI() self.configure(self.x, self.y) self.checkQ() self._master.attributes("-topmost", top) def checkQ(self): if not self._q.empty(): data = self._q.get_nowait() self.updateUI(data) wait = 0 if "darwin" in platform.system().lower(): wait = 1 self._master.after(wait, self.checkQ) self._master.update_idletasks() def mainloop(self): self._master.mainloop() def updateUI(self, data): size = len(data) / 3 if size != self._count: log.warning("Bytecount mismatch") return for i in range(size): r = data[i * 3 + 0] g = data[i * 3 + 1] b = data[i * 3 + 2] self._values[i] = self.toHexColor(r, g, b) try: for i in range(self._count): self._canvas.itemconfig(self._leds[i], fill=self._values[i]) except TclError: # Looks like the UI closed! pass def toHexColor(self, r, g, b): return "#{0:02x}{1:02x}{2:02x}".format(r, g, b) def update(self, data): self._q.put(data) def hasFrame(self): return not self._q.empty() def configure(self, x, y): self._type = type self.x = x self.y = y self._count = x * y self._values = [] # init colors to all black (off) for i in range(self._count): self._values.append("#101010") c = self._canvas c.delete(ALL) self._leds = [] for i in range(self._count): index = c.create_rectangle( 0, 0, self._pixelSize, self._pixelSize, fill=self._values[i]) self._leds.append(index) self.layoutPixels() def layoutPixels(self): if len(self._leds) == 0: return x_off = 0 row = 0 count = 0 w = 0 h = 0 for y in range(self.y): for x in range(self.x): if y % 2 != 0: x = self.x - x - 1 _x = self._pixelPad + \ ((x - x_off) * (self._pixelSize + self._pixelSpace)) _y = self._pixelPad + \ ((y + row) * (self._pixelSize + self._pixelSpace)) if row > 0: _y += 3 * row _w = _x + self._pixelSize + self._pixelSpace + self._pixelPad if _w > w: w = _w _h = _y + self._pixelSize + self._pixelSpace + self._pixelPad if _h > h: h = _h if self.y == 1 and _x + ((self._pixelSize + self._pixelSpace) * 2) > self._maxWindowWidth: row += 1 x_off += (x - x_off + 1) self._canvas.coords( self._leds[count], _x, _y, _x + self._pixelSize, _y + self._pixelSize) count += 1 self._master.geometry("{0}x{1}".format(w, h)) self._master.update() self._canvas.config(width=w, height=h) def __CancelCommand(self, event=None): self._master.quit() self._master.destroy() sys.exit() # def __resizeEvent(self, event): # width = self._master.winfo_width() # height = self._master.winfo_height() # if width != self._width or height != self._height: # self._width = width # self._height = height # self._master.after_idle(self.layoutPixels) # def __handleResize(self): # width = self._master.winfo_width() # height = self._master.winfo_height() # if width != self._width or height != self._height: # self._width = width # self._height = height # self.layoutPixels() # self._master.after_idle(self.__handleResize) def initUI(self): m = self._master m.protocol('WM_DELETE_WINDOW', self.__CancelCommand) m.title("BiblioPixel Visualizer") m.geometry("10x10") m.update() self._width = m.winfo_width() self._height = m.winfo_height() m.minsize(self._width, self._height) self._canvas = Canvas(self._master, background="#000000") c = self._canvas c.pack(side=TOP) self.layoutPixels()
def __init__(self, container, img=None, p=None): root = Tk() root.attributes('-topmost', 1) hint = '(Enter - submit, Esc - abort)' if img is None: root.wm_title('Address') hint = 'Please enter your Bitcoin address.\n' + hint else: root.wm_title('Captcha {0:g}'.format(p)) img = ImageTk.PhotoImage(img) root.img_reference = img image = Label(root, image=img, text=hint, compound='top') image.pack() entry = Entry(root) entry.bind('<Escape>', lambda _: root.destroy()) entry.bind( '<Return>', lambda _: (container.setdefault(0, (entry.get())), root.destroy())) entry.pack() entry.focus_set() root.update_idletasks() xp = (root.winfo_screenwidth() / 2) - (root.winfo_width() / 2) - 8 yp = (root.winfo_screenheight() / 2) - (root.winfo_height() / 2) - 20 root.geometry('+%d+%d' % (xp, yp)) root.mainloop()
def show(text, background="#fff", timeout_ms=DEFAULT_TIMEOUT, font_size=100): root = Tk() root.attributes("-topmost", True) root.lift() # Set Timeout root.after(timeout_ms, root.destroy) # Create Frame frame = Frame(root) frame.pack(side=TOP, fill=BOTH, expand=YES) # Set frame size and position screen_width = frame.master.winfo_screenwidth() screen_heigh = frame.master.winfo_screenheight() w = screen_width * 0.8 h = screen_heigh * 0.6 # Center the window x = (screen_width/2) - (w/2) y = (screen_heigh/2) - (h/2) frame.master.geometry('%dx%d+%d+%d' % (w, h, x, y)) # Adjust frame properties frame.master.overrideredirect(True) # Set no border or title frame.config(bg=background) # Create text label label = Label(frame, text=text, wraplength=screen_width * 0.8) label.pack(side=TOP, expand=YES) label.config(bg=background, justify=CENTER, font=("calibri", font_size)) # Set transparency root.wait_visibility(root) # Needed for linux (and must come after overrideredirect) root.attributes('-alpha', 0.6) # Run Event loop root.mainloop()
def getFname(): bw = Tk() bw.attributes("-topmost", True) bw.withdraw() fname = askopenfilename() bw.destroy() return fname
class TokenInputGUI(object): def show_entry_fields(self, event=None): self.code = self.e1.get() self.master.withdraw() self.master.quit() def quit(self): self.master.quit() self.code = None def doGUI(self, hostname=None): self.master = Tk() self.master.title('Blessclient - MFA') textmsg = 'Enter your AWS MFA code: ' if hostname: textmsg = 'Enter your AWS MFA code to connect to {}: '.format( hostname) Label(self.master, text=textmsg).grid(row=0) self.e1 = Entry(self.master) self.e1.grid(row=0, column=1, padx=4) Button(self.master, text='OK', command=self.show_entry_fields, default=ACTIVE).grid(row=3, column=0, sticky=W, pady=4) Button(self.master, text='Cancel', command=self.quit).grid(row=3, column=1, sticky=W, pady=4) self.center() self.master.bind('<Return>', self.show_entry_fields) self.master.lift() self.master.attributes('-topmost', True) self.master.focus_force() self.e1.focus_set() if platform.system() == 'Darwin': try: from Cocoa import (NSRunningApplication, NSApplicationActivateIgnoringOtherApps) app = NSRunningApplication.runningApplicationWithProcessIdentifier_( os.getpid()) app.activateWithOptions_( NSApplicationActivateIgnoringOtherApps) except ImportError: pass mainloop() # http://stackoverflow.com/questions/3352918/how-to-center-a-window-on-the-screen-in-tkinter def center(self): self.master.update_idletasks() w = self.master.winfo_screenwidth() h = self.master.winfo_screenheight() size = tuple( int(_) for _ in self.master.geometry().split('+')[0].split('x')) x = w / 2 - size[0] / 2 y = h / 2 - size[1] / 2 self.master.geometry("%dx%d+%d+%d" % (size + (x, y)))
def getLoadPath(directory, extension): if int(sys.version[0]) < 3: from tkFileDialog import askopenfilename from Tkinter import Tk else: from tkinter.filedialog import askopenfilename from tkinter import Tk master = Tk() master.attributes("-topmost", True) path = askopenfilename(initialdir=directory,filetypes=['vehicle {*.'+extension+'}'],title="Open") master.destroy() return path
def getSavePath(directory, extension): if int(sys.version[0]) < 3: from tkFileDialog import asksaveasfilename from Tkinter import Tk else: from tkinter.filedialog import asksaveasfilename from tkinter import Tk master = Tk() master.attributes("-topmost", True) path = asksaveasfilename(initialdir=directory, filetypes=['MineFriff {*.' + extension + '}'], defaultextension="." + extension, title="Save") master.destroy() return path
def main(): root = Tk() def kludge(): root.after(100, kludge) root.after(100, kludge) def handle_sigusr1(signum, frame): root.quit() signal.signal(signal.SIGUSR1, handle_sigusr1) root.geometry("250x150+300+300") root.attributes("-fullscreen", True) app = Example(root) root.mainloop() print("Here we are cleaning up.")
class TokenInputGUI(object): def show_entry_fields(self, event=None): self.code = self.e1.get() self.master.withdraw() self.master.quit() def quit(self): self.master.quit() self.code = None def doGUI(self, hostname=None): self.master = Tk() self.master.title('Blessclient - MFA') textmsg = 'Enter your AWS MFA code: ' if hostname: textmsg = 'Enter your AWS MFA code to connect to {}: '.format(hostname) Label(self.master, text=textmsg).grid(row=0) self.e1 = Entry(self.master) self.e1.grid(row=0, column=1, padx=4) Button(self.master, text='OK', command=self.show_entry_fields, default=ACTIVE).grid(row=3, column=0, sticky=W, pady=4) Button(self.master, text='Cancel', command=self.quit).grid(row=3, column=1, sticky=W, pady=4) self.center() self.master.bind('<Return>', self.show_entry_fields) self.master.lift() self.master.attributes('-topmost', True) self.master.focus_force() self.e1.focus_set() if platform.system() == 'Darwin': # Hack to get the GUI dialog focused in OSX os.system('/usr/bin/osascript -e \'tell app "Finder" to set frontmost of process "python" to true\'') mainloop() # http://stackoverflow.com/questions/3352918/how-to-center-a-window-on-the-screen-in-tkinter def center(self): self.master.update_idletasks() w = self.master.winfo_screenwidth() h = self.master.winfo_screenheight() size = tuple(int(_) for _ in self.master.geometry().split('+')[0].split('x')) x = w / 2 - size[0] / 2 y = h / 2 - size[1] / 2 self.master.geometry("%dx%d+%d+%d" % (size + (x, y)))
def get_files(titlestring,filetype = ('.txt','*.txt')): # Make a top-level instance and hide since it is ugly and big. root = Tk() root.withdraw() # Make it almost invisible - no decorations, 0 size, top left corner. root.overrideredirect(True) root.geometry('0x0+0+0') # # Show window again and lift it to top so it can get focus, # otherwise dialogs will end up behind the terminal. root.deiconify() root.attributes("-topmost",1) root.focus_force() filenames = [] filenames = tkFileDialog.askopenfilename(title=titlestring, filetypes=[filetype],multiple='True') #do nothing if already a python list if filenames == "": print "You didn't open anything!" return root.destroy() if isinstance(filenames,list): result = filenames elif isinstance(filenames,tuple): result = list(filenames) else: #http://docs.python.org/library/re.html #the re should match: {text and white space in brackets} AND anynonwhitespacetokens #*? is a non-greedy match for any character sequence #\S is non white space #split filenames string up into a proper python list result = re.findall("{.*?}|\S+",filenames) #remove any {} characters from the start and end of the file names result = [ re.sub("^{|}$","",i) for i in result ] result.sort() return result
def main(): root = Tk() root.geometry("640x480") root.wm_title('PiMenu') root.attributes('-alpha',0.0) pabcf = open("/home/pi/pi-apps/pimenu/settings/Pi_apps_button_color") pabc = pabcf.read() if len(sys.argv) > 2 and sys.argv[2] == 'fs': root.wm_attributes('-fullscreen', True) btn_frame = Frame(root, bg=pabc) img = PhotoImage(file=os.path.dirname(os.path.dirname(os.path.realpath(sys.argv[0]))) + "/icons/proglogo.png") pi_apps_btn = SimpleFlatButton(btn_frame,text=sys.argv[1], image=img, command=pi_apps_mainpage ) pi_apps_btn.set_color(pabc) pi_apps_btn.pack() piframe = Frame(root, bg="#155CAA") btn_frame.pack(padx=1,pady=1, fill=TkC.BOTH) piframe.pack(fill=TkC.BOTH, expand=1) PiMenu(piframe) root.mainloop()
def run(player, args): root = Tk() # width, height = (root.winfo_screenwidth(), root.winfo_screenheight()) if args.max: root.attributes('-fullscreen', True) else: root.geometry('%dx%d' % (WIN_WIDTH, WIN_HEIGHT)) root.configure(bg='black', bd=0, highlightbackground='black') # root.attributes("-topmost", True) app = PlayerApp(root, player) # root.mainloop() while app.running: root.update() gevent.sleep(1.0 / FPS) gevent.killall( [obj for obj in gc.get_objects() if isinstance(obj, greenlet)])
def display(image_file): root = Tk() root.title("Dataflow Graph") screen_width = root.winfo_screenwidth() * 1.0 screen_height = root.winfo_screenheight() * 0.875 image1 = Image.open(image_file) width, height = image1.size if width > screen_width or height > screen_height: factor = max(width / screen_width, height / screen_height) image1 = image1.resize((int(width / factor), int(height / factor)), Image.ANTIALIAS) frame = Frame(root, width=image1.size[0], height=image1.size[1]) frame.grid(row=0, column=0) canvas = Canvas(frame, bg='#FFFFFF', width=image1.size[0], height=image1.size[1], scrollregion=(0, 0, image1.size[0], image1.size[1])) img = ImageTk.PhotoImage(image1) canvas.create_image(0, 0, image=img, anchor="nw") hbar = Scrollbar(frame, orient=HORIZONTAL) hbar.pack(side=BOTTOM, fill=Tkinter.X) hbar.config(command=canvas.xview) vbar = Scrollbar(frame, orient=VERTICAL) vbar.pack(side=RIGHT, fill=Tkinter.Y) vbar.config(command=canvas.yview) canvas.config(width=image1.size[0], height=image1.size[1]) canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set) canvas.pack(side=LEFT, expand=True, fill=BOTH) frame.pack() # added so that the windows pops up (and is not minimized) # --> see http://stackoverflow.com/questions/9083687/python-tkinter-gui-always-loads-minimized root.attributes('-topmost', 1) root.update() root.attributes('-topmost', 0) mainloop()
def display(image_file): root = Tk() root.title("Dataflow Graph") screen_width=root.winfo_screenwidth()*1.0 screen_height=root.winfo_screenheight()*0.875 image1 = Image.open(image_file) width,height=image1.size if width>screen_width or height>screen_height: factor=max(width/screen_width,height/screen_height) image1=image1.resize((int(width/factor),int(height/factor)), Image.ANTIALIAS) frame = Frame(root, width=image1.size[0],height=image1.size[1]) frame.grid(row=0,column=0) canvas=Canvas(frame,bg='#FFFFFF',width=image1.size[0],height=image1.size[1],scrollregion=(0,0,image1.size[0],image1.size[1])) img = ImageTk.PhotoImage(image1) canvas.create_image(0,0,image=img, anchor="nw") hbar=Scrollbar(frame,orient=HORIZONTAL) hbar.pack(side=BOTTOM,fill=Tkinter.X) hbar.config(command=canvas.xview) vbar=Scrollbar(frame,orient=VERTICAL) vbar.pack(side=RIGHT,fill=Tkinter.Y) vbar.config(command=canvas.yview) canvas.config(width=image1.size[0],height=image1.size[1]) canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set) canvas.pack(side=LEFT,expand=True,fill=BOTH) frame.pack() # added so that the windows pops up (and is not minimized) # --> see http://stackoverflow.com/questions/9083687/python-tkinter-gui-always-loads-minimized root.attributes('-topmost', 1) root.update() root.attributes('-topmost', 0) mainloop()
class UI(object): def __init__(self): self._root = Tk() self._root.title("^ NotiFire ^") self._name = StringVar() self._is_osx = which_system() == 'Darwin' self._version = None ########################################################################## #### Public methods ##### ########################################################################## def get_name(self): frame = DraggableFrame(self._root) frame.pack(side=TOP, fill=BOTH, expand=YES) frame.columnconfigure(0, weight=1) frame.columnconfigure(4, weight=1) frame.rowconfigure(0, weight=1) frame.rowconfigure(4, weight=1) w = self._set_frame_geo(frame, 0.3, 0.3)[2] self._set_x_button(frame, w, self._close_get_name) Label(frame, text="Name:").grid(column=1, row=1) entry_style = SUNKEN if self._is_osx else FLAT entry = Entry(frame, exportselection=0, relief=entry_style, textvariable=self._name) entry.grid(column=2, row=1) entry.focus_set() error_label = Label(frame, fg='red') error_label.grid(column=1, row=2, columnspan=3) ok_cmd = partial(self._validate_name, error_label) FlatButton(frame, text='OK', width=20, font=("calibri", 15), command=ok_cmd).grid(column=1, row=3, columnspan=3) self._root.bind('<Return>', ok_cmd) self._root.bind('<Escape>', self._close_get_name) self._run() return self._name.get() if self._name else self._name def main_window(self, name, ping_callback): self._name.set(name) self._ping_callback = ping_callback # Create Frame self.frame = DraggableFrame(self._root) self.frame.pack(side=TOP, fill=BOTH, expand=YES) w = self._set_frame_geo(self.frame, 0.5, 0.6)[2] self._set_x_button(self.frame, w, self._root.destroy) Label(self.frame, text="Name:").place(x=10, y=15) Label(self.frame, text=self._name.get(), fg='blue').place(x=80, y=15) self._version_label = Label(self.frame, text="Newer version detected, please restart the app", fg='#a00', font=("calibri", 25)) FlatButton(self.frame, text="Test", width=26, command=self._test_action).place(x=10, y=50) FlatButton(self.frame, text='Refresh', width=26, command=self._generate_ping_buttons).place(x=10, y=90) self.ping_buttons = [] self._auto_refresh() self._check_version() self._run() ########################################################################## #### Private methods ##### ########################################################################## def _run(self): # Set transparency self._root.wait_visibility(self._root) self._root.attributes('-alpha', 0.95) self._root.lift() # Run Event loop self._root.mainloop() def _close_get_name(self, event=None): self._name = None self._root.destroy() def _set_frame_geo(self, frame, wf, hf): # Set frame size and position screen_width = frame.master.winfo_screenwidth() screen_heigh = frame.master.winfo_screenheight() w = screen_width * wf h = screen_heigh * hf # Center the window x = (screen_width/2) - (w/2) y = (screen_heigh/2) - (h/2) frame.master.geometry('%dx%d+%d+%d' % (w, h, x, y)) if not self._is_osx: frame.master.overrideredirect(True) # Set no border or title return x, y, w, h def _set_x_button(self, frame, w, callback): x_button_x_coordinate = w-30 if self._is_osx else w-20 FlatButton(frame, text='×', no_bg=True, width=1, font=("calibri", 15), command=callback).place(x=x_button_x_coordinate, y=-10) def _validate_name(self, error_label, event=None): name = self._name.get() if not 0 < len(name) < 25: error_label.config(text="Name must be 1-25 chars long") logger.error("Invalid name: %s" % (name)) elif not all(ord(c) < 128 for c in name): error_label.config(text="Name must be ascii") logger.error("Invalid Name: %s" % (name)) else: self._root.destroy() def _test_action(self): self._ping_someone(self._name.get()) def _ping_someone(self, name): ret = self._ping_callback(name) if not ret: self._generate_ping_buttons() splash.error(name + ' is no longer available') def _generate_ping_buttons(self): logger.info("generating buttons") #TODO put in a frame with a scrollbar for button in self.ping_buttons: button.destroy() self.ping_buttons = [] next_y = 10 for name in sorted(NotiFireDb.get_all_names()): if self._name.get() == name: continue cmd = partial(self._ping_someone, name) button = FlatButton(self.frame, text="Ping " + name, width=20, command=cmd) self.ping_buttons.append(button) button.place(x=300, y=next_y) next_y += 40 def _auto_refresh(self): self._generate_ping_buttons() self._root.after(600000, self._auto_refresh) # Run again in 10 mintues def _check_version(self): with open("version.txt") as f: latest = StrictVersion(f.read()) if self._version is None: self._version = latest elif self._version < latest: self._version_label.place(x=80, y=255) return self._root.after(86400000, self._check_version) # Run again in 1 day
# TODO: entities return corner1, corner2 if __name__ == '__main__': if len(argv) >= 2: path = argv[1] else: if int(version[0]) < 3: from tkFileDialog import askopenfilename from Tkinter import Tk else: from tkinter.filedialog import askopenfilename from tkinter import Tk master = Tk() master.attributes("-topmost", True) path = askopenfilename(filetypes=['schematic {*.schematic}'], title="Open") master.destroy() if not path: exit() mc = Minecraft() pos = mc.player.getTilePos() (corner0, corner1) = importSchematic(mc, path, pos.x, pos.y, pos.z, centerX=True, centerZ=True)
class SpeakersCorner(): def __init__(self): self.video_length = 90 # seconds self.button = 17 # BCM (Broadcom SOC Channel) GPIO 17 is pin #11 on the board GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(self.button, GPIO.IN) self.window = Tk() self.window.attributes("-fullscreen", True) self.window.configure(cursor='none') def countdown(self): """ Display countdown on LED matrix, updatingn in 10 second intervals Determines video recording length :return: """ # Initialize display matrix = led.matrix() # Display message at beginning of recording. matrix.show_message("Seconds left:", font=proportional(CP437_FONT)) time.sleep(1) # Wait for message to display time_remaining = self.video_length while time_remaining > 0: matrix.show_message(str(time_remaining)) time_remaining -= 10 time.sleep(10) def parsegeometry(self, geometry): """ Parses window geometry """ x, y = geometry.split('+')[0].split('x') return (x, y) def poll_button(self): if (GPIO.input(self.button)): self.begin_recording() self.window.after(100, self.poll_button) def begin_recording(self): camera = picamera.PiCamera() camera.start_preview() time.sleep(10000) camera.stop_preview() # Start subprocess to record audio and video #pid = subprocess.Popen([ #'/home/pi/picam-1.3.0-binary/picam', #'--alsadev', #'hw:1,0', #'--preview', #'--volume', #'2' #]) #time.sleep(2) #use picam's start_record hook #self.touch('/home/pi/speakers-corner/hooks/start_record') #self.countdown() #time.sleep(1) #use picam's stop_record hook #self.touch('/home/pi/speakers-corner/hooks/stop_record') #time.sleep(2) #pid.kill() #self.remux_latest_video_file() def remux_latest_video_file(self): """ Repackage the latest MPEG-TS (Transport Stream) file in an MPEG-PS (Program Stream) container """ ts_file_dir = '/home/pi/speakers-corner/rec' #ts_file_dir = '/Users/jeffszusz/projects/hackf/speakerscorner/rec' (_, _, ts_files) = os.walk(ts_file_dir).next() ts_file_name = ts_files[-1] ts_file_path = os.path.join(ts_file_dir, ts_file_name) mpeg2_output_path = "{}{}".format(ts_file_path.split('.')[0], '.mpg') subprocess.Popen([ 'ffmpeg', '-i', ts_file_path, '-acodec', 'copy', '-vcodec', 'copy', mpeg2_output_path ]) def sponsor_images(self): """ returns a generator, provides the next image in the sponsor slideshow """ while True: for fname in glob.glob('images/*.jpg'): yield Image.open(fname) def start_sponsor_slideshow(self): images = self.sponsor_images() self.cycle_through_images(images, None) def cycle_through_images(self, images, label): image = images.next() size = self.parsegeometry(self.window.geometry()) # Grab screen size window_size = size[0], size[1] image.thumbnail(window_size, Image.ANTIALIAS) # Resize to fit screen tkimage = ImageTk.PhotoImage(image) if not label: label = Label(self.window, image=tkimage) label.pack(fill=BOTH, expand=YES) label.configure(image=tkimage) label.image = tkimage self.window.after(10000, self.cycle_through_images, images, label) def start(self): self.window.after(500, self.start_sponsor_slideshow) self.poll_button() self.window.mainloop()
class FullScreenWindow: def __init__(self, label_timeout, max_elements): self.count = 0 self.colors_count = 0 self.tk = Tk() self.max_elements = max_elements self.frame = Frame(self.tk) self.frame.bind("<Key>", self.key_press) self.frame.focus_set() self.state = False self.tk.attributes("-fullscreen", True) self.label_timeout = label_timeout self.screen_width = self.tk.winfo_screenwidth() self.screen_height = self.tk.winfo_screenheight() screen_resolution = str(self.screen_width) + 'x' + str(self.screen_height) self.tk.geometry(screen_resolution) self.canvas = Canvas(self.frame, height=self.screen_height, width=self.screen_width) self.canvas.pack(fill=BOTH) self.frame.pack() self.objects = deque() def key_press(self, key): self.draw_triangle() def draw_triangle(self): x1 = random.uniform(0, 1) * self.screen_width y1 = random.uniform(0, 1) * self.screen_height x2 = random.uniform(0, 1) * self.screen_width y2 = random.uniform(0, 1) * self.screen_height x3 = random.uniform(0, 1) * self.screen_width y3 = random.uniform(0, 1) * self.screen_height x4 = random.uniform(0, 1) * self.screen_width y4 = random.uniform(0, 1) * self.screen_height x5 = random.uniform(0, 1) * self.screen_width y5 = random.uniform(0, 1) * self.screen_height colors = ['black', 'red', 'green', 'blue', 'cyan', 'yellow', 'magenta'] if self.colors_count % 7 == 0: self.colors_count = 0 if self.count == 0: o = self.canvas.create_line(x1, y1, x2, y2, x3, y3, x1, y1) self.count = 1 elif self.count == 1: o = self.canvas.create_rectangle(x1, y1, x2, y2, fill=colors[self.colors_count]) self.colors_count += 1 self.count = 2 elif self.count == 2: o = self.canvas.create_oval(x1, y1, x2, y2, fill=colors[self.colors_count]) self.colors_count += 1 self.count = 3 elif self.count == 3: o = self.canvas.create_polygon(x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, fill=colors[self.colors_count]) self.colors_count += 1 self.count = 0 if len(self.objects) >= self.max_elements: obj_to_remove = self.objects.pop() self.canvas.delete(obj_to_remove) self.objects.appendleft(o) self.canvas.after(self.label_timeout,self.canvas.delete, o) self.frame.pack(fill=BOTH, expand=1)
else: grey = "light slate grey" green = "green" yellow = "yellow" red = "red" white = "white" black = "black" c_height = 476 #the border lines are approx 2px c_width = 316 #316 root = Tk() root.config(width=(c_width - 45), height=c_height, bg=black) if not testMode: root.config(cursor="none") root.attributes("-fullscreen", True) #if not in test mode switch to fullscreen textFont = tkFont.Font(family="Helvetica", size=36, weight="bold") # Declare Variables measuredItems = ["RPM", "Water TMP", "Oil Temp", "Oil Press", "EGT", "Fuel Flow", "Fuel(left)", "Voltage"] errorBoxItems = ["TEMP", "PRESS", "FUEL", "POWER", "ERROR"] errorBoxItemsColor = ["red", "green", "green", "yellow", "green"] measuredItemsColor = [red, green, yellow, green, green, green, green] measuredItemsValue = [1, 65, 89, 10, 768, 7.8, 65, 12.6] buttonPressed = ([0, 0, 0, 0, 0, 0, 0, 0]) #Flight Data# roll = 0; pitch = 0;
else: grey = "light slate grey" green = "green" yellow = "yellow" red = "red" white = "white" black = "black" c_height = 476 #the border lines are approx 2px c_width = 316 #316 root = Tk() root.config(width=(c_width - 45), height=c_height, bg=black) if not testMode: root.config(cursor="none") root.attributes("-fullscreen", True) #if not in test mode switch to fullscreen textFont = tkFont.Font(family="Helvetica", size=36, weight="bold") # Declare Variables measuredItems = [ "RPM", "Water TMP", "Oil Temp", "Oil Press", "EGT", "Fuel Flow", "Fuel(left)", "Voltage" ] errorBoxItems = ["TEMP", "PRESS", "FUEL", "POWER", "ERROR"] errorBoxItemsColor = ["red", "green", "green", "yellow", "green"] measuredItemsColor = [red, green, yellow, green, green, green, green] measuredItemsValue = [1, 65, 89, 10, 768, 7.8, 65, 12.6] buttonPressed = ([0, 0, 0, 0, 0, 0, 0, 0]) #Flight Data#
class GUI: """ This is a GUI. Nothing really special to see here """ def __init__(self): """ Initiation bits. Make buttons, give them handlers. You know, all the normal stuff. """ self.computer_first = 0 # randint(0, 1) self.app = Tk() self.app.attributes("-toolwindow", 1) self.app.title('Tic Tac Toe') self.app.resizable(width=False, height=False) self.board = Board() self.font = Font(family="Helvetica", size=32) self.buttons = {} for x, y in self.board.fields: handler = lambda x=x, y=y: self.move(x, y) button = Button(self.app, command=handler, font=self.font, width=2, height=1) button.grid(row=y, column=x) self.buttons[x, y] = button handler = lambda: self.reset() button = Button(self.app, text='reset', command=handler) button.grid(row=self.board.size + 1, column=0, columnspan=self.board.size, stick='WE') self.update() if self.computer_first: self.move(randint(0, self.board.size - 1), randint(0, self.board.size - 1)) def update(self): """ Updates the board. Deactivates played fields. Checks to see if the last turn won. If it did, lock the whole board, make the winning combination red. """ for (x, y) in self.board.fields: text = self.board.fields[x, y] self.buttons[x, y]['text'] = text self.buttons[x, y]['disabledforeground'] = 'black' if text == self.board.empty: self.buttons[x, y]['state'] = 'normal' else: self.buttons[x, y]['state'] = 'disabled' winning = self.board.won() if winning: for x, y in winning: self.buttons[x, y]['disabledforeground'] = 'red' for x, y in self.buttons: self.buttons[x, y]['state'] = 'disabled' for (x, y) in self.board.fields: self.buttons[x, y].update() def reset(self): """ Self-explanatory. This re-instantiates the board. Also throws a random binary to see if the computer drew the first move. """ self.board = Board() self.update() self.computer_first = randint(0, 1) if self.computer_first: self.move(randint(0, self.board.size - 1), randint(0, self.board.size - 1)) def move(self, x, y): """ The action. This allows the player to make a move, then instructs the computer to make a counter mover. """ if self.computer_first: self.app.config(cursor='watch') self.board = self.board.move(x, y) self.update() self.computer_first = 0 self.app.config(cursor='') else: self.board = self.board.move(x, y) self.update() self.app.config(cursor='watch') move = self.board.best() if move: self.board = self.board.move(*move) self.update() self.app.config(cursor='') def mainloop(self): """ All games have to have a loop. This GUI framework knows that. """ self.app.mainloop()
mc.setBlock(x0+x,y0+y,z0+z,b,d) print("done") # TODO: entities return corner1,corner2 if __name__=='__main__': if len(argv) >= 2: path = argv[1] else: if int(version[0]) < 3: from tkFileDialog import askopenfilename from Tkinter import Tk else: from tkinter.filedialog import askopenfilename from tkinter import Tk master = Tk() master.attributes("-topmost", True) path = askopenfilename(filetypes=['schematic {*.schematic}'],title="Open") master.destroy() if not path: exit() mc = Minecraft() pos = mc.player.getTilePos() (corner0,corner1)=importSchematic(mc,path,pos.x,pos.y,pos.z,centerX=True,centerZ=True) mc.postToChat("Done drawing, putting player on top") y = corner1[1] while y > -256 and mc.getBlock(pos.x,y-1,pos.z) == block.AIR.id: y -= 1 mc.player.setTilePos(pos.x,y,pos.z)
class PiPresents(object): def pipresents_version(self): vitems=self.pipresents_issue.split('.') if len(vitems)==2: # cope with 2 digit version numbers before 1.3.2 return 1000*int(vitems[0])+100*int(vitems[1]) else: return 1000*int(vitems[0])+100*int(vitems[1])+int(vitems[2]) def __init__(self): gc.set_debug(gc.DEBUG_UNCOLLECTABLE|gc.DEBUG_INSTANCES|gc.DEBUG_OBJECTS|gc.DEBUG_SAVEALL) self.pipresents_issue="1.3.2" self.pipresents_minorissue = '1.3.2a' # position and size of window without -f command line option self.nonfull_window_width = 0.45 # proportion of width self.nonfull_window_height= 0.7 # proportion of height self.nonfull_window_x = 0 # position of top left corner self.nonfull_window_y=0 # position of top left corner StopWatch.global_enable=False # set up the handler for SIGTERM signal.signal(signal.SIGTERM,self.handle_sigterm) # **************************************** # Initialisation # *************************************** # get command line options self.options=command_options() # get Pi Presents code directory pp_dir=sys.path[0] self.pp_dir=pp_dir if not os.path.exists(pp_dir+"/pipresents.py"): if self.options['manager'] is False: tkMessageBox.showwarning("Pi Presents","Bad Application Directory") exit(102) # Initialise logging and tracing Monitor.log_path=pp_dir self.mon=Monitor() # Init in PiPresents only self.mon.init() # uncomment to enable control of logging from within a class # Monitor.enable_in_code = True # enables control of log level in the code for a class - self.mon.set_log_level() # make a shorter list to log/trace only some classes without using enable_in_code. Monitor.classes = ['PiPresents', 'HyperlinkShow','RadioButtonShow','ArtLiveShow','ArtMediaShow','MediaShow','LiveShow','MenuShow', 'GapShow','Show','ArtShow', 'AudioPlayer','BrowserPlayer','ImagePlayer','MenuPlayer','MessagePlayer','VideoPlayer','Player', 'MediaList','LiveList','ShowList', 'PathManager','ControlsManager','ShowManager','PluginManager', 'MplayerDriver','OMXDriver','UZBLDriver', 'KbdDriver','GPIODriver','TimeOfDay','ScreenDriver','Animate','OSCDriver', 'Network','Mailer' ] # Monitor.classes=['PiPresents','MediaShow','GapShow','Show','VideoPlayer','Player','OMXDriver'] # get global log level from command line Monitor.log_level = int(self.options['debug']) Monitor.manager = self.options['manager'] # print self.options['manager'] self.mon.newline(3) self.mon.sched (self, "Pi Presents is starting, Version:"+self.pipresents_minorissue + ' at '+time.strftime("%Y-%m-%d %H:%M.%S")) self.mon.log (self, "Pi Presents is starting, Version:"+self.pipresents_minorissue+ ' at '+time.strftime("%Y-%m-%d %H:%M.%S")) # self.mon.log (self," OS and separator:" + os.name +' ' + os.sep) self.mon.log(self,"sys.path[0] - location of code: "+sys.path[0]) # log versions of Raspbian and omxplayer, and GPU Memory with open("/boot/issue.txt") as file: self.mon.log(self,'\nRaspbian: '+file.read()) self.mon.log(self,'\n'+check_output(["omxplayer", "-v"])) self.mon.log(self,'\nGPU Memory: '+check_output(["vcgencmd", "get_mem", "gpu"])) if "DESKTOP_SESSION" not in os.environ: print 'Pi Presents must be run from the Desktop' self.mon.log(self,'Pi Presents must be run from the Desktop') self.mon.finish() sys.exit(102) else: self.mon.log(self,'Desktop is '+ os.environ['DESKTOP_SESSION']) # optional other classes used self.root=None self.ppio=None self.tod=None self.animate=None self.gpiodriver=None self.oscdriver=None self.osc_enabled=False self.gpio_enabled=False self.tod_enabled=False self.email_enabled=False if os.geteuid() == 0: self.mon.err(self,'Do not run Pi Presents with sudo') self.end('error','Do not run Pi Presents with sudo') user=os.getenv('USER') self.mon.log(self,'User is: '+ user) # self.mon.log(self,"os.getenv('HOME') - user home directory (not used): " + os.getenv('HOME')) # does not work # self.mon.log(self,"os.path.expanduser('~') - user home directory: " + os.path.expanduser('~')) # does not work # check network is available self.network_connected=False self.network_details=False self.interface='' self.ip='' self.unit='' # sets self.network_connected and self.network_details self.init_network() # start the mailer and send email when PP starts self.email_enabled=False if self.network_connected is True: self.init_mailer() if self.email_enabled is True and self.mailer.email_at_start is True: subject= '[Pi Presents] ' + self.unit + ': PP Started on ' + time.strftime("%Y-%m-%d %H:%M") message = time.strftime("%Y-%m-%d %H:%M") + '\nUnit: ' + self.unit + ' Profile: '+ self.options['profile']+ '\n ' + self.interface + '\n ' + self.ip self.send_email('start',subject,message) # get profile path from -p option if self.options['profile'] != '': self.pp_profile_path="/pp_profiles/"+self.options['profile'] else: self.mon.err(self,"Profile not specified in command ") self.end('error','Profile not specified with the commands -p option') # get directory containing pp_home from the command, if self.options['home'] == "": home = os.sep+ 'home' + os.sep + user + os.sep+"pp_home" else: home = self.options['home'] + os.sep+ "pp_home" self.mon.log(self,"pp_home directory is: " + home) # check if pp_home exists. # try for 10 seconds to allow usb stick to automount found=False for i in range (1, 10): self.mon.log(self,"Trying pp_home at: " + home + " (" + str(i)+')') if os.path.exists(home): found=True self.pp_home=home break time.sleep (1) if found is True: self.mon.log(self,"Found Requested Home Directory, using pp_home at: " + home) else: self.mon.err(self,"Failed to find pp_home directory at " + home) self.end('error',"Failed to find pp_home directory at " + home) # check profile exists self.pp_profile=self.pp_home+self.pp_profile_path if os.path.exists(self.pp_profile): self.mon.sched(self,"Running profile: " + self.pp_profile_path) self.mon.log(self,"Found Requested profile - pp_profile directory is: " + self.pp_profile) else: self.mon.err(self,"Failed to find requested profile: "+ self.pp_profile) self.end('error',"Failed to find requested profile: "+ self.pp_profile) self.mon.start_stats(self.options['profile']) if self.options['verify'] is True: val =Validator() if val.validate_profile(None,pp_dir,self.pp_home,self.pp_profile,self.pipresents_issue,False) is False: self.mon.err(self,"Validation Failed") self.end('error','Validation Failed') # initialise and read the showlist in the profile self.showlist=ShowList() self.showlist_file= self.pp_profile+ "/pp_showlist.json" if os.path.exists(self.showlist_file): self.showlist.open_json(self.showlist_file) else: self.mon.err(self,"showlist not found at "+self.showlist_file) self.end('error',"showlist not found at "+self.showlist_file) # check profile and Pi Presents issues are compatible if self.showlist.profile_version() != self.pipresents_version(): self.mon.err(self,"Version of showlist " + self.showlist.profile_version_string + " is not same as Pi Presents") self.end('error',"Version of showlist " + self.showlist.profile_version_string + " is not same as Pi Presents") # get the 'start' show from the showlist index = self.showlist.index_of_show('start') if index >=0: self.showlist.select(index) self.starter_show=self.showlist.selected_show() else: self.mon.err(self,"Show [start] not found in showlist") self.end('error',"Show [start] not found in showlist") # ******************** # SET UP THE GUI # ******************** # turn off the screenblanking and saver if self.options['noblank'] is True: call(["xset","s", "off"]) call(["xset","s", "-dpms"]) self.root=Tk() self.title='Pi Presents - '+ self.pp_profile self.icon_text= 'Pi Presents' self.root.title(self.title) self.root.iconname(self.icon_text) self.root.config(bg=self.starter_show['background-colour']) self.mon.log(self, 'monitor screen dimensions are ' + str(self.root.winfo_screenwidth()) + ' x ' + str(self.root.winfo_screenheight()) + ' pixels') if self.options['screensize'] =='': self.screen_width = self.root.winfo_screenwidth() self.screen_height = self.root.winfo_screenheight() else: reason,message,self.screen_width,self.screen_height=self.parse_screen(self.options['screensize']) if reason =='error': self.mon.err(self,message) self.end('error',message) self.mon.log(self, 'forced screen dimensions (--screensize) are ' + str(self.screen_width) + ' x ' + str(self.screen_height) + ' pixels') # set window dimensions and decorations if self.options['fullscreen'] is False: self.window_width=int(self.root.winfo_screenwidth()*self.nonfull_window_width) self.window_height=int(self.root.winfo_screenheight()*self.nonfull_window_height) self.window_x=self.nonfull_window_x self.window_y=self.nonfull_window_y self.root.geometry("%dx%d%+d%+d" % (self.window_width,self.window_height,self.window_x,self.window_y)) else: self.window_width=self.screen_width self.window_height=self.screen_height self.root.attributes('-fullscreen', True) os.system('unclutter &') self.window_x=0 self.window_y=0 self.root.geometry("%dx%d%+d%+d" % (self.window_width,self.window_height,self.window_x,self.window_y)) self.root.attributes('-zoomed','1') # canvas cover the whole screen whatever the size of the window. self.canvas_height=self.screen_height self.canvas_width=self.screen_width # make sure focus is set. self.root.focus_set() # define response to main window closing. self.root.protocol ("WM_DELETE_WINDOW", self.handle_user_abort) # setup a canvas onto which will be drawn the images or text self.canvas = Canvas(self.root, bg=self.starter_show['background-colour']) if self.options['fullscreen'] is True: self.canvas.config(height=self.canvas_height, width=self.canvas_width, highlightthickness=0) else: self.canvas.config(height=self.canvas_height, width=self.canvas_width, highlightthickness=1, highlightcolor='yellow') self.canvas.place(x=0,y=0) # self.canvas.config(bg='black') self.canvas.focus_set() # **************************************** # INITIALISE THE INPUT DRIVERS # **************************************** # each driver takes a set of inputs, binds them to symboic names # and sets up a callback which returns the symbolic name when an input event occurs/ # use keyboard driver to bind keys to symbolic names and to set up callback kbd=KbdDriver() if kbd.read(pp_dir,self.pp_home,self.pp_profile) is False: self.end('error','cannot find, or error in keys.cfg') kbd.bind_keys(self.root,self.handle_input_event) self.sr=ScreenDriver() # read the screen click area config file reason,message = self.sr.read(pp_dir,self.pp_home,self.pp_profile) if reason == 'error': self.end('error','cannot find, or error in screen.cfg') # create click areas on the canvas, must be polygon as outline rectangles are not filled as far as find_closest goes # click areas are made on the Pi Presents canvas not the show canvases. reason,message = self.sr.make_click_areas(self.canvas,self.handle_input_event) if reason == 'error': self.mon.err(self,message) self.end('error',message) # **************************************** # INITIALISE THE APPLICATION AND START # **************************************** self.shutdown_required=False self.terminate_required=False self.exitpipresents_required=False # delete omxplayer dbus files # if os.path.exists("/tmp/omxplayerdbus.{}".format(user)): # os.remove("/tmp/omxplayerdbus.{}".format(user)) # if os.path.exists("/tmp/omxplayerdbus.{}.pid".format(user)): # os.remove("/tmp/omxplayerdbus.{}.pid".format(user)) # kick off GPIO if enabled by command line option self.gpio_enabled=False if os.path.exists(self.pp_profile + os.sep + 'pp_io_config'+os.sep+ 'gpio.cfg'): # initialise the GPIO self.gpiodriver=GPIODriver() reason,message=self.gpiodriver.init(pp_dir,self.pp_home,self.pp_profile,self.canvas,50,self.handle_input_event) if reason == 'error': self.end('error',message) else: self.gpio_enabled=True # and start polling gpio self.gpiodriver.poll() # kick off animation sequencer self.animate = Animate() self.animate.init(pp_dir,self.pp_home,self.pp_profile,self.canvas,200,self.handle_output_event) self.animate.poll() #create a showmanager ready for time of day scheduler and osc server show_id=-1 self.show_manager=ShowManager(show_id,self.showlist,self.starter_show,self.root,self.canvas,self.pp_dir,self.pp_profile,self.pp_home) # first time through set callback to terminate Pi Presents if all shows have ended. self.show_manager.init(self.canvas,self.all_shows_ended_callback,self.handle_command,self.showlist) # Register all the shows in the showlist reason,message=self.show_manager.register_shows() if reason == 'error': self.mon.err(self,message) self.end('error',message) # Init OSCDriver, read config and start OSC server self.osc_enabled=False if self.network_connected is True: if os.path.exists(self.pp_profile + os.sep + 'pp_io_config'+ os.sep + 'osc.cfg'): self.oscdriver=OSCDriver() reason,message=self.oscdriver.init(self.pp_profile,self.handle_command,self.handle_input_event,self.e_osc_handle_output_event) if reason == 'error': self.mon.err(self,message) self.end('error',message) else: self.osc_enabled=True self.root.after(1000,self.oscdriver.start_server()) # enable ToD scheduler if schedule exists if os.path.exists(self.pp_profile + os.sep + 'schedule.json'): self.tod_enabled = True else: self.tod_enabled=False # warn if the network not available when ToD required if self.tod_enabled is True and self.network_connected is False: self.mon.warn(self,'Network not connected so Time of Day scheduler may be using the internal clock') # warn about start shows and scheduler if self.starter_show['start-show']=='' and self.tod_enabled is False: self.mon.sched(self,"No Start Shows in Start Show and no shows scheduled") self.mon.warn(self,"No Start Shows in Start Show and no shows scheduled") if self.starter_show['start-show'] !='' and self.tod_enabled is True: self.mon.sched(self,"Start Shows in Start Show and shows scheduled - conflict?") self.mon.warn(self,"Start Shows in Start Show and shows scheduled - conflict?") # run the start shows self.run_start_shows() # kick off the time of day scheduler which may run additional shows if self.tod_enabled is True: self.tod=TimeOfDay() self.tod.init(pp_dir,self.pp_home,self.pp_profile,self.root,self.handle_command) self.tod.poll() # start Tkinters event loop self.root.mainloop( ) def parse_screen(self,size_text): fields=size_text.split('*') if len(fields)!=2: return 'error','do not understand --screensize comand option',0,0 elif fields[0].isdigit() is False or fields[1].isdigit() is False: return 'error','dimensions are not positive integers in --screensize',0,0 else: return 'normal','',int(fields[0]),int(fields[1]) # ********************* # RUN START SHOWS # ******************** def run_start_shows(self): self.mon.trace(self,'run start shows') # parse the start shows field and start the initial shows show_refs=self.starter_show['start-show'].split() for show_ref in show_refs: reason,message=self.show_manager.control_a_show(show_ref,'open') if reason == 'error': self.mon.err(self,message) # ********************* # User inputs # ******************** # handles one command provided as a line of text def handle_command(self,command_text,source='',show=''): # print 'PIPRESENTS ',command_text,source,'from',show self.mon.log(self,"command received: " + command_text) if command_text.strip()=="": return if command_text[0]=='/': if self.osc_enabled is True: self.oscdriver.send_command(command_text) return fields= command_text.split() show_command=fields[0] if len(fields)>1: show_ref=fields[1] else: show_ref='' if show_command in ('open','close'): self.mon.sched(self, command_text + ' received from show:'+show) if self.shutdown_required is False and self.terminate_required is False: reason,message=self.show_manager.control_a_show(show_ref,show_command) else: return elif show_command =='monitor': self.handle_monitor_command(show_ref) return elif show_command == 'event': self.handle_input_event(show_ref,'Show Control') return elif show_command == 'exitpipresents': self.exitpipresents_required=True if self.show_manager.all_shows_exited() is True: # need root.after to get out of st thread self.root.after(1,self.e_all_shows_ended_callback) return else: reason,message= self.show_manager.exit_all_shows() elif show_command == 'shutdownnow': # need root.after to get out of st thread self.root.after(1,self.e_shutdown_pressed) return else: reason='error' message = 'command not recognised: '+ show_command if reason=='error': self.mon.err(self,message) return def handle_monitor_command(self,command): if command == 'on': os.system('vcgencmd display_power 1 >/dev/null') elif command == 'off': os.system('vcgencmd display_power 0 >/dev/null') def e_all_shows_ended_callback(self): self.all_shows_ended_callback('normal','no shows running') def e_shutdown_pressed(self): self.shutdown_pressed('now') def e_osc_handle_output_event(self,line): #jump out of server thread self.root.after(1, lambda arg=line: self.osc_handle_output_event(arg)) def osc_handle_output_event(self,line): self.mon.log(self,"output event received: "+ line) #osc sends output events as a string reason,message,delay,name,param_type,param_values=self.animate.parse_animate_fields(line) if reason == 'error': self.mon.err(self,message) self.end(reason,message) self.handle_output_event(name,param_type,param_values,0) def handle_output_event(self,symbol,param_type,param_values,req_time): if self.gpio_enabled is True: reason,message=self.gpiodriver.handle_output_event(symbol,param_type,param_values,req_time) if reason =='error': self.mon.err(self,message) self.end(reason,message) else: self.mon.warn(self,'GPIO not enabled') # all input events call this callback with a symbolic name. # handle events that affect PP overall, otherwise pass to all active shows def handle_input_event(self,symbol,source): self.mon.log(self,"event received: "+symbol + ' from '+ source) if symbol == 'pp-terminate': self.handle_user_abort() elif symbol == 'pp-shutdown': self.shutdown_pressed('delay') elif symbol == 'pp-shutdownnow': # need root.after to grt out of st thread self.root.after(1,self.e_shutdown_pressed) return elif symbol == 'pp-exitpipresents': self.exitpipresents_required=True if self.show_manager.all_shows_exited() is True: # need root.after to grt out of st thread self.root.after(1,self.e_all_shows_ended_callback) return reason,message= self.show_manager.exit_all_shows() else: # events for shows affect the show and could cause it to exit. for show in self.show_manager.shows: show_obj=show[ShowManager.SHOW_OBJ] if show_obj is not None: show_obj.handle_input_event(symbol) def shutdown_pressed(self, when): if when == 'delay': self.root.after(5000,self.on_shutdown_delay) else: self.shutdown_required=True if self.show_manager.all_shows_exited() is True: self.all_shows_ended_callback('normal','no shows running') else: # calls exit method of all shows, results in all_shows_closed_callback self.show_manager.exit_all_shows() def on_shutdown_delay(self): # 5 second delay is up, if shutdown button still pressed then shutdown if self.gpiodriver.shutdown_pressed() is True: self.shutdown_required=True if self.show_manager.all_shows_exited() is True: self.all_shows_ended_callback('normal','no shows running') else: # calls exit method of all shows, results in all_shows_closed_callback self.show_manager.exit_all_shows() def handle_sigterm(self,signum,frame): self.mon.log(self,'SIGTERM received - '+ str(signum)) self.terminate() def handle_user_abort(self): self.mon.log(self,'User abort received') self.terminate() def terminate(self): self.mon.log(self, "terminate received") self.terminate_required=True needs_termination=False for show in self.show_manager.shows: # print show[ShowManager.SHOW_OBJ], show[ShowManager.SHOW_REF] if show[ShowManager.SHOW_OBJ] is not None: needs_termination=True self.mon.log(self,"Sent terminate to show "+ show[ShowManager.SHOW_REF]) # call shows terminate method # eventually the show will exit and after all shows have exited all_shows_callback will be executed. show[ShowManager.SHOW_OBJ].terminate() if needs_termination is False: self.end('killed','killed - no termination of shows required') # ****************************** # Ending Pi Presents after all the showers and players are closed # ************************** # callback from ShowManager when all shows have ended def all_shows_ended_callback(self,reason,message): self.canvas.config(bg=self.starter_show['background-colour']) if reason in ('killed','error') or self.shutdown_required is True or self.exitpipresents_required is True: self.end(reason,message) def end(self,reason,message): self.mon.log(self,"Pi Presents ending with reason: " + reason) if self.root is not None: self.root.destroy() self.tidy_up() # gc.collect() # print gc.garbage if reason == 'killed': if self.email_enabled is True and self.mailer.email_on_terminate is True: subject= '[Pi Presents] ' + self.unit + ': PP Exited with reason: Terminated' message = time.strftime("%Y-%m-%d %H:%M") + '\n ' + self.unit + '\n ' + self.interface + '\n ' + self.ip self.send_email(reason,subject,message) self.mon.sched(self, "Pi Presents Terminated, au revoir\n") self.mon.log(self, "Pi Presents Terminated, au revoir") # close logging files self.mon.finish() sys.exit(101) elif reason == 'error': if self.email_enabled is True and self.mailer.email_on_error is True: subject= '[Pi Presents] ' + self.unit + ': PP Exited with reason: Error' message_text = 'Error message: '+ message + '\n'+ time.strftime("%Y-%m-%d %H:%M") + '\n ' + self.unit + '\n ' + self.interface + '\n ' + self.ip self.send_email(reason,subject,message_text) self.mon.sched(self, "Pi Presents closing because of error, sorry\n") self.mon.log(self, "Pi Presents closing because of error, sorry") # close logging files self.mon.finish() sys.exit(102) else: self.mon.sched(self,"Pi Presents exiting normally, bye\n") self.mon.log(self,"Pi Presents exiting normally, bye") # close logging files self.mon.finish() if self.shutdown_required is True: # print 'SHUTDOWN' call (['sudo','shutdown','now','SHUTTING DOWN']) sys.exit(100) def init_network(self): timeout=int(self.options['nonetwork']) if timeout== 0: self.network_connected=False self.unit='' self.ip='' self.interface='' return self.network=Network() self.network_connected=False # try to connect to network self.mon.log (self, 'Waiting up to '+ str(timeout) + ' seconds for network') success=self.network.wait_for_network(timeout) if success is False: self.mon.warn(self,'Failed to connect to network after ' + str(timeout) + ' seconds') # tkMessageBox.showwarning("Pi Presents","Failed to connect to network so using fake-hwclock") return self.network_connected=True self.mon.sched (self, 'Time after network check is '+ time.strftime("%Y-%m-%d %H:%M.%S")) self.mon.log (self, 'Time after network check is '+ time.strftime("%Y-%m-%d %H:%M.%S")) # Get web configuration self.network_details=False network_options_file_path=self.pp_dir+os.sep+'pp_config'+os.sep+'pp_web.cfg' if not os.path.exists(network_options_file_path): self.mon.warn(self,"pp_web.cfg not found at "+network_options_file_path) return self.mon.log(self, 'Found pp_web.cfg in ' + network_options_file_path) self.network.read_config(network_options_file_path) self.unit=self.network.unit # get interface and IP details of preferred interface self.interface,self.ip = self.network.get_preferred_ip() if self.interface == '': self.network_connected=False return self.network_details=True self.mon.log (self, 'Network details ' + self.unit + ' ' + self.interface + ' ' +self.ip) def init_mailer(self): self.email_enabled=False email_file_path = self.pp_dir+os.sep+'pp_config'+os.sep+'pp_email.cfg' if not os.path.exists(email_file_path): self.mon.log(self,'pp_email.cfg not found at ' + email_file_path) return self.mon.log(self,'Found pp_email.cfg at ' + email_file_path) self.mailer=Mailer() self.mailer.read_config(email_file_path) # all Ok so can enable email if config file allows it. if self.mailer.email_allowed is True: self.email_enabled=True self.mon.log (self,'Email Enabled') def send_email(self,reason,subject,message): if self.try_connect() is False: return False else: success,error = self.mailer.send(subject,message) if success is False: self.mon.log(self, 'Failed to send email: ' + str(error)) success,error=self.mailer.disconnect() if success is False: self.mon.log(self,'Failed disconnect after send:' + str(error)) return False else: self.mon.log(self,'Sent email for ' + reason) success,error=self.mailer.disconnect() if success is False: self.mon.log(self,'Failed disconnect from email server ' + str(error)) return True def try_connect(self): tries=1 while True: success, error = self.mailer.connect() if success is True: return True else: self.mon.log(self,'Failed to connect to email SMTP server ' + str(tries) + '\n ' +str(error)) tries +=1 if tries >5: self.mon.log(self,'Failed to connect to email SMTP server after ' + str(tries)) return False # tidy up all the peripheral bits of Pi Presents def tidy_up(self): self.handle_monitor_command('on') self.mon.log(self, "Tidying Up") # turn screen blanking back on if self.options['noblank'] is True: call(["xset","s", "on"]) call(["xset","s", "+dpms"]) # tidy up animation and gpio if self.animate is not None: self.animate.terminate() if self.gpio_enabled==True: self.gpiodriver.terminate() if self.osc_enabled is True: self.oscdriver.terminate() # tidy up time of day scheduler if self.tod_enabled is True: self.tod.terminate()
labelv = Label(frame, textvariable=v2, font=("arial", 40)) labelv.grid(row=1, column=2) labell = Label(frame, textvariable=l2, font=("arial", 40)) labell.grid(row=2, column=2) labelz = Label(frame, textvariable=z2, font=("arial", 40)) labelz.grid(row=3, column=2) frame.grid() root.update() return def close(event): root.destroy() root.attributes("-fullscreen", True) root.bind("<Escape>", close) def Return(): return def serialC(): try: #list = serial.Serial(USB, 9600) #list= serial.Serial('/dev/ttyUSB0',9600) list.read() except: Arduino() serialC()
class MyGUI: def __init__(self): self.__mainWindow = Tk() self.outdoor = True self.indoor = False self.RWidth=self.__mainWindow.winfo_screenwidth() self.RHeight=self.__mainWindow.winfo_screenheight() self.__mainWindow.geometry(("%dx%d")%(self.RWidth,self.RHeight)) self.__mainWindow.maxsize(width=480, height=320) self.__mainWindow.attributes("-fullscreen", True) self.but_frame = Frame(self.__mainWindow, pady=5, padx=5, height=60, width=self.RWidth) self.but_frame.pack(side=BOTTOM, anchor=W) self.exitbtn = Button(self.but_frame, text="Quit", font=("Helvetica", 14), command=self.__mainWindow.destroy) self.outdoorbtn = Button(self.but_frame, text="Outdoor", font=("Helvetica", 14), command=self.show_hide_int) self.indoorbtn = Button(self.but_frame, text="Indoor", font=("Helvetica", 14), command=self.show_hide_int) self.but_frame.pack_propagate(0) self.exitbtn.pack(side=LEFT) self.outdoorbtn.pack(side=RIGHT) self.indoorbtn.pack(padx=5, side=RIGHT) self.ext_frame = Frame(self.__mainWindow) self.ext_frame.pack(side=LEFT) self.ext_title_label = Label(self.ext_frame, text = 'Outdoor Conditions', font=("Helvetica", 18), pady = 5) self.ext_title_label.pack(pady=5, side=TOP) self.ext_cond_frame = Frame(self.ext_frame, height=self.RHeight, width=self.RWidth/4) self.ext_cond_frame.pack_propagate(0) self.ext_cond_frame.pack(side=LEFT) self.ext_initlabelText = 'Temperature: ' self.ext_initLabel = Label(self.ext_cond_frame, text = self.ext_initlabelText, font=("Helvetica", 14)) self.ext_initLabel.pack(padx=5, pady=5, anchor= W) self.ext_initlabelText = 'Feels like: ' self.ext_initLabel = Label(self.ext_cond_frame, text = self.ext_initlabelText, font=("Helvetica", 14)) self.ext_initLabel.pack(padx=5, pady=5, anchor= W) self.ext_initlabelText = 'Humidity: ' self.ext_initLabel = Label(self.ext_cond_frame, text = self.ext_initlabelText, font=("Helvetica", 14)) self.ext_initLabel.pack(padx=5, pady=5, anchor= W) self.ext_cond2_frame = Frame(self.ext_frame, height=self.RHeight, width=self.RWidth/4) self.ext_cond2_frame.pack_propagate(0) self.ext_cond2_frame.pack(side=LEFT) self.ext_temp_labelText = 'Loading...' self.ext_temp_Label = Label(self.ext_cond2_frame, text = self.ext_temp_labelText, font=("Helvetica", 14)) self.ext_temp_Label.pack(padx=5, pady=5, anchor= W) self.ext_feels_labelText = 'Loading...' self.ext_feels_Label = Label(self.ext_cond2_frame, text = self.ext_feels_labelText, font=("Helvetica", 14)) self.ext_feels_Label.pack(padx=5, pady=5, anchor= W) self.ext_rh_labelText = 'Loading...' self.ext_rh_Label = Label(self.ext_cond2_frame, text = self.ext_rh_labelText, font=("Helvetica", 14)) self.ext_rh_Label.pack(padx=5, pady=5, anchor= W) print "Empiezo a mirar el tiempo" self.__mainWindow.after(1000, self.task) print "termino de mirar el tiempo" mainloop() print "despues del loop" def show_hide_int(self): if self.indoor==False: self.indoor = True self.draw_int() print 'indoor true' else: self.indoor = False self.int_frame.pack_forget() print 'indoor false' def draw_int(self): self.int_frame = Frame(self.__mainWindow, pady = 5) self.int_frame.pack(side=RIGHT) self.int_title_label = Label(self.int_frame, text = 'Indoor Conditions', font=("Helvetica", 18)) self.int_title_label.pack(pady=5, side=TOP) self.int_cond_frame = Frame(self.int_frame, height=self.RHeight, width=self.RWidth/4) self.int_cond_frame.pack_propagate(0) self.int_cond_frame.pack(side=LEFT) self.int_initlabelText = 'Temperature: ' self.int_initLabel = Label(self.int_cond_frame, text = self.int_initlabelText, font=("Helvetica", 14)) self.int_initLabel.pack(padx=5, pady=5, anchor= W) self.int_initlabelText = 'Humidity: ' self.int_initLabel = Label(self.int_cond_frame, text = self.int_initlabelText, font=("Helvetica", 14)) self.int_initLabel.pack(padx=5, pady=5, anchor= W) self.int_initlabelText = 'Pressure: ' self.int_initLabel = Label(self.int_cond_frame, text = self.int_initlabelText, font=("Helvetica", 14)) self.int_initLabel.pack(padx=5, pady=5, anchor= W) self.int_initlabelText = 'CO2: ' self.int_initLabel = Label(self.int_cond_frame, text = self.int_initlabelText, font=("Helvetica", 14)) self.int_initLabel.pack(padx=5, pady=5, anchor= W) self.int_cond2_frame = Frame(self.int_frame, height=self.RHeight, width=self.RWidth/4) self.int_cond2_frame.pack_propagate(0) self.int_cond2_frame.pack(side=LEFT) self.int_temp_labelText = str(self.conditions[4])+ u"\u00b0"+'C' self.int_temp_Label = Label(self.int_cond2_frame, text = self.int_temp_labelText, font=("Helvetica", 14)) self.int_temp_Label.pack(padx=5, pady=5, anchor= W) self.int_rh_labelText = str(self.conditions[5])+' %' self.int_rh_Label = Label(self.int_cond2_frame, text = self.int_rh_labelText, font=("Helvetica", 14)) self.int_rh_Label.pack(padx=5, pady=5, anchor= W) self.int_pressure_labelText = str(self.conditions[6])+ ' mbar' self.int_pressure_humidityLabel = Label(self.int_cond2_frame, text = self.int_pressure_labelText, font=("Helvetica", 14)) self.int_pressure_humidityLabel.pack(padx=5, pady=5, anchor= W) self.int_co2_labelText = str(self.conditions[7])+' ppm' self.int_co2_Label = Label(self.int_cond2_frame, text = self.int_co2_labelText, font=("Helvetica", 14)) self.int_co2_Label.pack(padx=5, pady=5, anchor= W) self.outdoorbtn.config(relief=RAISED) def task(self): print "Empiezo a mirar el tiempo dentro de task" self.conditions = [] authorization = lnetatmo.ClientAuth() devList = lnetatmo.DeviceList(authorization) print "Dispositivo autorizado" #print devList.lastData() location = "Shnzhen" #devList.lastData()['place']['geoip_city'] self.conditions.append(location) temp_c = devList.lastData()['Exterior']['Temperature'] ex_temp_c = temp_c temp_f = (5.0/9.0)*temp_c + 32 temp_f = round(temp_f,1) ex_rh = devList.lastData()['Exterior']['Humidity'] feelslike_f =-42.379 + (2.04901523 * temp_f) + (10.14333127 * ex_rh) - (0.22475541 * temp_f * ex_rh) - (6.83783 * 0.001 * temp_f*temp_f)-(5.481717*0.01*ex_rh*ex_rh)+(1.22874*0.001*temp_f*temp_f*ex_rh)+(8.5282*0.0001*temp_f*ex_rh*ex_rh)-(1.99*0.000001*temp_f*temp_f*ex_rh*ex_rh) feelslike_f = round(feelslike_f,1) feelslike_c = (5.0/9.0)*(feelslike_f - 32) ex_feelslike_c = round(feelslike_c, 1) int_pressure = devList.lastData()['Interior']['Pressure'] int_temp_c = devList.lastData()['Interior']['Temperature'] int_rh = devList.lastData()['Interior']['Humidity'] int_co2 = devList.lastData()['Interior']['CO2'] self.conditions.append(ex_temp_c) self.conditions.append(ex_feelslike_c) self.conditions.append(ex_rh) self.conditions.append(int_temp_c) self.conditions.append(int_rh) self.conditions.append(int_pressure) self.conditions.append(int_co2) print "Tiempo guardado" if self.outdoor==True: self.ext_temp_Label.config(text=str(self.conditions[1])+ u"\u00b0"+'C') self.ext_feels_Label.config(text=str(self.conditions[2])+ u"\u00b0"+'C') self.ext_rh_Label.config(text=str(self.conditions[3])+' %') self.__mainWindow.update() print "Ventana exterior actualizada" if self.indoor==True: self.int_temp_Label.config(text=str(self.conditions[4])+' mbar') self.int_rh_Label.config(text=str(self.conditions[5])+' ppm') self.int_pressure_Label.config(text=str(self.conditions[6])+' mbar') self.int_co2_Label.config(text=str(self.conditions[7])+' ppm') self.__mainWindow.update() print "Ventana interior actualizada" self.__mainWindow.after(3000000, self.task)
DOOR_KEYBOARDS = 3 DOOR_CABLES = 4 def end_fullscreen(self, event=None): win.state = False win.attributes("-fullscreen", False) win.geometry("200x200") return "break" logging.basicConfig(filename='logfile.log', level=logging.DEBUG, format='%(asctime)s %(message)s') win = Tk() win.attributes("-fullscreen", True) win.bind("<Escape>", end_fullscreen) myFont = tkFont.Font(family='Helvetica', size=24, weight='bold') #python don't have switch or case def decrement_stock(num_door): global STOCK_HEADSETS global STOCK_MOUSES global STOCK_KEYBOARDS global STOCK_CABLES if num_door == DOOR_HEADSETS: STOCK_HEADSETS -= 1 if STOCK_HEADSETS == 0: headsetButton.config(state="disabled") elif num_door == DOOR_MOUSES:
context = usb1.USBContext() for device in context.getDeviceList(skip_on_error=True): print 'ID %04x:%04x' % (device.getVendorID(), device.getProductID()), '->'.join(str(x) for x in ['Bus %03i' % (device.getBusNumber(), )] + device.getPortNumberList()), 'Device', device.getDeviceAddress() OPTIONS = dict(defaultextension='.jpg', title="Escolha o arquivo que deseja converter", filetypes=[('Imagens', ('*.jpg', '*.jpeg', '*.png', '*.bmp')), ('Todos Arquivos', '*.*')]) placeholder = None c_path = path.dirname(path.realpath(__file__))+sep root = Tk() root.geometry("450x450+200+200") root.attributes("-alpha", 0.9) root.title("Gravar Graficos na impressora") # the_file = None def select_file(): the_file = askopenfilename(**OPTIONS) if the_file: converted_name = "converted.bmp" file_entry.configure(text=the_file) c_img = Image.open(the_file, 'r') c_img = c_img.convert('1') c_img.thumbnail((110, 110)) c_img.save(converted_name, format="BMP") p_img = ImageTk.PhotoImage(Image.open(c_path+converted_name))
class PiPresents(object): def __init__(self): gc.set_debug(gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_INSTANCES | gc.DEBUG_OBJECTS | gc.DEBUG_SAVEALL) self.pipresents_issue = "1.3" self.pipresents_minorissue = '1.3.1g' # position and size of window without -f command line option self.nonfull_window_width = 0.45 # proportion of width self.nonfull_window_height = 0.7 # proportion of height self.nonfull_window_x = 0 # position of top left corner self.nonfull_window_y = 0 # position of top left corner self.pp_background = 'black' StopWatch.global_enable = False # set up the handler for SIGTERM signal.signal(signal.SIGTERM, self.handle_sigterm) # **************************************** # Initialisation # *************************************** # get command line options self.options = command_options() # get Pi Presents code directory pp_dir = sys.path[0] self.pp_dir = pp_dir if not os.path.exists(pp_dir + "/pipresents.py"): if self.options['manager'] is False: tkMessageBox.showwarning( "Pi Presents", "Bad Application Directory:\n{0}".format(pp_dir)) exit(103) # Initialise logging and tracing Monitor.log_path = pp_dir self.mon = Monitor() # Init in PiPresents only self.mon.init() # uncomment to enable control of logging from within a class # Monitor.enable_in_code = True # enables control of log level in the code for a class - self.mon.set_log_level() # make a shorter list to log/trace only some classes without using enable_in_code. Monitor.classes = [ 'PiPresents', 'pp_paths', 'HyperlinkShow', 'RadioButtonShow', 'ArtLiveShow', 'ArtMediaShow', 'MediaShow', 'LiveShow', 'MenuShow', 'PathManager', 'ControlsManager', 'ShowManager', 'PluginManager', 'MplayerDriver', 'OMXDriver', 'UZBLDriver', 'KbdDriver', 'GPIODriver', 'TimeOfDay', 'ScreenDriver', 'Animate', 'OSCDriver' ] # Monitor.classes=['PiPresents','ArtMediaShow','VideoPlayer','OMXDriver'] # get global log level from command line Monitor.log_level = int(self.options['debug']) Monitor.manager = self.options['manager'] # print self.options['manager'] self.mon.newline(3) self.mon.log( self, "Pi Presents is starting, Version:" + self.pipresents_minorissue) # self.mon.log (self," OS and separator:" + os.name +' ' + os.sep) self.mon.log(self, "sys.path[0] - location of code: " + sys.path[0]) if os.geteuid() != 0: user = os.getenv('USER') else: user = os.getenv('SUDO_USER') self.mon.log(self, 'User is: ' + user) # self.mon.log(self,"os.getenv('HOME') - user home directory (not used): " + os.getenv('HOME')) # does not work # self.mon.log(self,"os.path.expanduser('~') - user home directory: " + os.path.expanduser('~')) # does not work # optional other classes used self.root = None self.ppio = None self.tod = None self.animate = None self.gpiodriver = None self.oscdriver = None self.osc_enabled = False self.gpio_enabled = False self.tod_enabled = False # get home path from -o option self.pp_home = pp_paths.get_home(self.options['home']) if self.pp_home is None: self.end('error', 'Failed to find pp_home') # get profile path from -p option # pp_profile is the full path to the directory that contains # pp_showlist.json and other files for the profile self.pp_profile = pp_paths.get_profile_dir(self.pp_home, self.options['profile']) if self.pp_profile is None: self.end('error', 'Failed to find profile') # check profile exists if os.path.exists(self.pp_profile): self.mon.log( self, "Found Requested profile - pp_profile directory is: " + self.pp_profile) else: self.mon.err( self, "Failed to find requested profile: " + self.pp_profile) self.end('error', 'Failed to find profile') self.mon.start_stats(self.options['profile']) # check 'verify' option if self.options['verify'] is True: val = Validator() if val.validate_profile(None, pp_dir, self.pp_home, self.pp_profile, self.pipresents_issue, False) is False: self.mon.err(self, "Validation Failed") self.end('error', 'Validation Failed') # initialise and read the showlist in the profile self.showlist = ShowList() self.showlist_file = self.pp_profile + "/pp_showlist.json" if os.path.exists(self.showlist_file): self.showlist.open_json(self.showlist_file) else: self.mon.err(self, "showlist not found at " + self.showlist_file) self.end('error', 'showlist not found') # check profile and Pi Presents issues are compatible if float(self.showlist.sissue()) != float(self.pipresents_issue): self.mon.err( self, "Version of profile " + self.showlist.sissue() + " is not same as Pi Presents, must exit") self.end('error', 'wrong version of profile') # get the 'start' show from the showlist index = self.showlist.index_of_show('start') if index >= 0: self.showlist.select(index) self.starter_show = self.showlist.selected_show() else: self.mon.err(self, "Show [start] not found in showlist") self.end('error', 'start show not found') if self.starter_show['start-show'] == '': self.mon.warn(self, "No Start Shows in Start Show") # ******************** # SET UP THE GUI # ******************** # turn off the screenblanking and saver if self.options['noblank'] is True: call(["xset", "s", "off"]) call(["xset", "s", "-dpms"]) self.root = Tk() self.title = 'Pi Presents - ' + self.pp_profile self.icon_text = 'Pi Presents' self.root.title(self.title) self.root.iconname(self.icon_text) self.root.config(bg=self.pp_background) self.mon.log( self, 'native screen dimensions are ' + str(self.root.winfo_screenwidth()) + ' x ' + str(self.root.winfo_screenheight()) + ' pixcels') if self.options['screensize'] == '': self.screen_width = self.root.winfo_screenwidth() self.screen_height = self.root.winfo_screenheight() else: reason, message, self.screen_width, self.screen_height = self.parse_screen( self.options['screensize']) if reason == 'error': self.mon.err(self, message) self.end('error', message) self.mon.log( self, 'commanded screen dimensions are ' + str(self.screen_width) + ' x ' + str(self.screen_height) + ' pixcels') # set window dimensions and decorations if self.options['fullscreen'] is False: self.window_width = int(self.root.winfo_screenwidth() * self.nonfull_window_width) self.window_height = int(self.root.winfo_screenheight() * self.nonfull_window_height) self.window_x = self.nonfull_window_x self.window_y = self.nonfull_window_y self.root.geometry("%dx%d%+d%+d" % (self.window_width, self.window_height, self.window_x, self.window_y)) else: self.window_width = self.screen_width self.window_height = self.screen_height self.root.attributes('-fullscreen', True) os.system( 'unclutter 1>&- 2>&- &' ) # Suppress 'someone created a subwindow' complaints from unclutter self.window_x = 0 self.window_y = 0 self.root.geometry("%dx%d%+d%+d" % (self.window_width, self.window_height, self.window_x, self.window_y)) self.root.attributes('-zoomed', '1') # canvs cover the whole screen whatever the size of the window. self.canvas_height = self.screen_height self.canvas_width = self.screen_width # make sure focus is set. self.root.focus_set() # define response to main window closing. self.root.protocol("WM_DELETE_WINDOW", self.handle_user_abort) # setup a canvas onto which will be drawn the images or text self.canvas = Canvas(self.root, bg=self.pp_background) if self.options['fullscreen'] is True: self.canvas.config(height=self.canvas_height, width=self.canvas_width, highlightthickness=0) else: self.canvas.config(height=self.canvas_height, width=self.canvas_width, highlightthickness=1, highlightcolor='yellow') self.canvas.place(x=0, y=0) # self.canvas.config(bg='black') self.canvas.focus_set() # **************************************** # INITIALISE THE INPUT DRIVERS # **************************************** # each driver takes a set of inputs, binds them to symboic names # and sets up a callback which returns the symbolic name when an input event occurs/ # use keyboard driver to bind keys to symbolic names and to set up callback kbd = KbdDriver() if kbd.read(pp_dir, self.pp_home, self.pp_profile) is False: self.end('error', 'cannot find or error in keys.cfg') kbd.bind_keys(self.root, self.handle_input_event) self.sr = ScreenDriver() # read the screen click area config file reason, message = self.sr.read(pp_dir, self.pp_home, self.pp_profile) if reason == 'error': self.end('error', 'cannot find screen.cfg') # create click areas on the canvas, must be polygon as outline rectangles are not filled as far as find_closest goes # click areas are made on the Pi Presents canvas not the show canvases. reason, message = self.sr.make_click_areas(self.canvas, self.handle_input_event) if reason == 'error': self.mon.err(self, message) self.end('error', message) # **************************************** # INITIALISE THE APPLICATION AND START # **************************************** self.shutdown_required = False self.exitpipresents_required = False # kick off GPIO if enabled by command line option self.gpio_enabled = False if os.path.exists(self.pp_profile + os.sep + 'pp_io_config' + os.sep + 'gpio.cfg'): # initialise the GPIO self.gpiodriver = GPIODriver() reason, message = self.gpiodriver.init(pp_dir, self.pp_home, self.pp_profile, self.canvas, 50, self.handle_input_event) if reason == 'error': self.end('error', message) else: self.gpio_enabled = True # and start polling gpio self.gpiodriver.poll() # kick off animation sequencer self.animate = Animate() self.animate.init(pp_dir, self.pp_home, self.pp_profile, self.canvas, 200, self.handle_output_event) self.animate.poll() #create a showmanager ready for time of day scheduler and osc server show_id = -1 self.show_manager = ShowManager(show_id, self.showlist, self.starter_show, self.root, self.canvas, self.pp_dir, self.pp_profile, self.pp_home) # first time through set callback to terminate Pi Presents if all shows have ended. self.show_manager.init(self.canvas, self.all_shows_ended_callback, self.handle_command, self.showlist) # Register all the shows in the showlist reason, message = self.show_manager.register_shows() if reason == 'error': self.mon.err(self, message) self.end('error', message) # Init OSCDriver, read config and start OSC server self.osc_enabled = False if os.path.exists(self.pp_profile + os.sep + 'pp_io_config' + os.sep + 'osc.cfg'): self.oscdriver = OSCDriver() reason, message = self.oscdriver.init( self.pp_profile, self.handle_command, self.handle_input_event, self.e_osc_handle_output_event) if reason == 'error': self.end('error', message) else: self.osc_enabled = True self.root.after(1000, self.oscdriver.start_server()) # and run the start shows self.run_start_shows() # set up the time of day scheduler including catchup self.tod_enabled = False if os.path.exists(self.pp_profile + os.sep + 'schedule.json'): # kick off the time of day scheduler which may run additional shows self.tod = TimeOfDay() self.tod.init(pp_dir, self.pp_home, self.pp_profile, self.root, self.handle_command) self.tod_enabled = True # then start the time of day scheduler if self.tod_enabled is True: self.tod.poll() # start Tkinters event loop self.root.mainloop() def parse_screen(self, size_text): fields = size_text.split('*') if len(fields) != 2: return 'error', 'do not understand --fullscreen comand option', 0, 0 elif fields[0].isdigit() is False or fields[1].isdigit() is False: return 'error', 'dimensions are not positive integers in ---fullscreen', 0, 0 else: return 'normal', '', int(fields[0]), int(fields[1]) # ********************* # RUN START SHOWS # ******************** def run_start_shows(self): self.mon.trace(self, 'run start shows') # parse the start shows field and start the initial shows show_refs = self.starter_show['start-show'].split() for show_ref in show_refs: reason, message = self.show_manager.control_a_show( show_ref, 'open') if reason == 'error': self.mon.err(self, message) # ********************* # User inputs # ******************** # handles one command provided as a line of text def handle_command(self, command_text): self.mon.log(self, "command received: " + command_text) if command_text.strip() == "": return if command_text[0] == '/': if self.osc_enabled is True: self.oscdriver.send_command(command_text) return fields = command_text.split() show_command = fields[0] if len(fields) > 1: show_ref = fields[1] else: show_ref = '' if show_command in ('open', 'close'): if self.shutdown_required is False: reason, message = self.show_manager.control_a_show( show_ref, show_command) else: return elif show_command == 'exitpipresents': self.exitpipresents_required = True if self.show_manager.all_shows_exited() is True: # need root.after to get out of st thread self.root.after(1, self.e_all_shows_ended_callback) return else: reason, message = self.show_manager.exit_all_shows() elif show_command == 'shutdownnow': # need root.after to get out of st thread self.root.after(1, self.e_shutdown_pressed) return else: reason = 'error' message = 'command not recognised: ' + show_command if reason == 'error': self.mon.err(self, message) return def e_all_shows_ended_callback(self): self.all_shows_ended_callback('normal', 'no shows running') def e_shutdown_pressed(self): self.shutdown_pressed('now') def e_osc_handle_output_event(self, line): #jump out of server thread self.root.after(1, lambda arg=line: self.osc_handle_output_event(arg)) def osc_handle_output_event(self, line): self.mon.log(self, "output event received: " + line) #osc sends output events as a string reason, message, delay, name, param_type, param_values = self.animate.parse_animate_fields( line) if reason == 'error': self.mon.err(self, message) self.end(reason, message) self.handle_output_event(name, param_type, param_values, 0) def handle_output_event(self, symbol, param_type, param_values, req_time): if self.gpio_enabled is True: reason, message = self.gpiodriver.handle_output_event( symbol, param_type, param_values, req_time) if reason == 'error': self.mon.err(self, message) self.end(reason, message) else: self.mon.warn(self, 'GPIO not enabled') # all input events call this callback with a symbolic name. # handle events that affect PP overall, otherwise pass to all active shows def handle_input_event(self, symbol, source): self.mon.log(self, "event received: " + symbol + ' from ' + source) if symbol == 'pp-terminate': self.handle_user_abort() elif symbol == 'pp-shutdown': self.shutdown_pressed('delay') elif symbol == 'pp-shutdownnow': # need root.after to grt out of st thread self.root.after(1, self.e_shutdown_pressed) return elif symbol == 'pp-exitpipresents': self.exitpipresents_required = True if self.show_manager.all_shows_exited() is True: # need root.after to grt out of st thread self.root.after(1, self.e_all_shows_ended_callback) return reason, message = self.show_manager.exit_all_shows() else: # events for shows affect the show and could cause it to exit. for show in self.show_manager.shows: show_obj = show[ShowManager.SHOW_OBJ] if show_obj is not None: show_obj.handle_input_event(symbol) def shutdown_pressed(self, when): if when == 'delay': self.root.after(5000, self.on_shutdown_delay) else: self.shutdown_required = True if self.show_manager.all_shows_exited() is True: self.all_shows_ended_callback('normal', 'no shows running') else: # calls exit method of all shows, results in all_shows_closed_callback self.show_manager.exit_all_shows() def on_shutdown_delay(self): # 5 second delay is up, if shutdown button still pressed then shutdown if self.gpiodriver.shutdown_pressed() is True: self.shutdown_required = True if self.show_manager.all_shows_exited() is True: self.all_shows_ended_callback('normal', 'no shows running') else: # calls exit method of all shows, results in all_shows_closed_callback self.show_manager.exit_all_shows() def handle_sigterm(self, signum, frame): self.mon.log(self, 'SIGTERM received - ' + str(signum)) self.terminate() def handle_user_abort(self): self.mon.log(self, 'User abort received') self.terminate() def terminate(self): self.mon.log(self, "terminate received") needs_termination = False for show in self.show_manager.shows: # print show[ShowManager.SHOW_OBJ], show[ShowManager.SHOW_REF] if show[ShowManager.SHOW_OBJ] is not None: needs_termination = True self.mon.log( self, "Sent terminate to show " + show[ShowManager.SHOW_REF]) # call shows terminate method # eventually the show will exit and after all shows have exited all_shows_callback will be executed. show[ShowManager.SHOW_OBJ].terminate() if needs_termination is False: self.end('killed', 'killed - no termination of shows required') # ****************************** # Ending Pi Presents after all the showers and players are closed # ************************** # callback from ShowManager when all shows have ended def all_shows_ended_callback(self, reason, message): self.canvas.config(bg=self.pp_background) if reason in ( 'killed', 'error' ) or self.shutdown_required is True or self.exitpipresents_required is True: self.end(reason, message) def end(self, reason, message): self.mon.log(self, "Pi Presents ending with reason: " + reason) if self.root is not None: self.root.destroy() self.tidy_up() # gc.collect() # print gc.garbage if reason == 'killed': self.mon.log(self, "Pi Presents Aborted, au revoir") # close logging files self.mon.finish() sys.exit(101) elif reason == 'error': self.mon.log(self, "Pi Presents closing because of error, sorry") # close logging files self.mon.finish() sys.exit(102) else: self.mon.log(self, "Pi Presents exiting normally, bye") # close logging files self.mon.finish() if self.shutdown_required is True: # print 'SHUTDOWN' call(['sudo', 'shutdown', '-h', '-t 5', 'now']) sys.exit(100) else: sys.exit(100) # tidy up all the peripheral bits of Pi Presents def tidy_up(self): self.mon.log(self, "Tidying Up") # turn screen blanking back on if self.options['noblank'] is True: call(["xset", "s", "on"]) call(["xset", "s", "+dpms"]) # tidy up animation and gpio if self.animate is not None: self.animate.terminate() if self.gpio_enabled == True: self.gpiodriver.terminate() if self.osc_enabled is True: self.oscdriver.terminate() # tidy up time of day scheduler if self.tod_enabled is True: self.tod.terminate()
class PiPresents(object): def __init__(self): gc.set_debug(gc.DEBUG_UNCOLLECTABLE|gc.DEBUG_INSTANCES|gc.DEBUG_OBJECTS|gc.DEBUG_SAVEALL) self.pipresents_issue="1.3" self.pipresents_minorissue = '1.3.1g' # position and size of window without -f command line option self.nonfull_window_width = 0.45 # proportion of width self.nonfull_window_height= 0.7 # proportion of height self.nonfull_window_x = 0 # position of top left corner self.nonfull_window_y=0 # position of top left corner self.pp_background='black' StopWatch.global_enable=False # set up the handler for SIGTERM signal.signal(signal.SIGTERM,self.handle_sigterm) # **************************************** # Initialisation # *************************************** # get command line options self.options=command_options() # get Pi Presents code directory pp_dir=sys.path[0] self.pp_dir=pp_dir if not os.path.exists(pp_dir+"/pipresents.py"): if self.options['manager'] is False: tkMessageBox.showwarning("Pi Presents","Bad Application Directory:\n{0}".format(pp_dir)) exit(103) # Initialise logging and tracing Monitor.log_path=pp_dir self.mon=Monitor() # Init in PiPresents only self.mon.init() # uncomment to enable control of logging from within a class # Monitor.enable_in_code = True # enables control of log level in the code for a class - self.mon.set_log_level() # make a shorter list to log/trace only some classes without using enable_in_code. Monitor.classes = ['PiPresents', 'pp_paths', 'HyperlinkShow','RadioButtonShow','ArtLiveShow','ArtMediaShow','MediaShow','LiveShow','MenuShow', 'PathManager','ControlsManager','ShowManager','PluginManager', 'MplayerDriver','OMXDriver','UZBLDriver', 'KbdDriver','GPIODriver','TimeOfDay','ScreenDriver','Animate','OSCDriver' ] # Monitor.classes=['PiPresents','ArtMediaShow','VideoPlayer','OMXDriver'] # get global log level from command line Monitor.log_level = int(self.options['debug']) Monitor.manager = self.options['manager'] # print self.options['manager'] self.mon.newline(3) self.mon.log (self, "Pi Presents is starting, Version:"+self.pipresents_minorissue) # self.mon.log (self," OS and separator:" + os.name +' ' + os.sep) self.mon.log(self,"sys.path[0] - location of code: "+sys.path[0]) if os.geteuid() !=0: user=os.getenv('USER') else: user = os.getenv('SUDO_USER') self.mon.log(self,'User is: '+ user) # self.mon.log(self,"os.getenv('HOME') - user home directory (not used): " + os.getenv('HOME')) # does not work # self.mon.log(self,"os.path.expanduser('~') - user home directory: " + os.path.expanduser('~')) # does not work # optional other classes used self.root=None self.ppio=None self.tod=None self.animate=None self.gpiodriver=None self.oscdriver=None self.osc_enabled=False self.gpio_enabled=False self.tod_enabled=False # get home path from -o option self.pp_home = pp_paths.get_home(self.options['home']) if self.pp_home is None: self.end('error','Failed to find pp_home') # get profile path from -p option # pp_profile is the full path to the directory that contains # pp_showlist.json and other files for the profile self.pp_profile = pp_paths.get_profile_dir(self.pp_home, self.options['profile']) if self.pp_profile is None: self.end('error','Failed to find profile') # check profile exists if os.path.exists(self.pp_profile): self.mon.log(self,"Found Requested profile - pp_profile directory is: " + self.pp_profile) else: self.mon.err(self,"Failed to find requested profile: "+ self.pp_profile) self.end('error','Failed to find profile') self.mon.start_stats(self.options['profile']) # check 'verify' option if self.options['verify'] is True: val =Validator() if val.validate_profile(None,pp_dir,self.pp_home,self.pp_profile,self.pipresents_issue,False) is False: self.mon.err(self,"Validation Failed") self.end('error','Validation Failed') # initialise and read the showlist in the profile self.showlist=ShowList() self.showlist_file= self.pp_profile+ "/pp_showlist.json" if os.path.exists(self.showlist_file): self.showlist.open_json(self.showlist_file) else: self.mon.err(self,"showlist not found at "+self.showlist_file) self.end('error','showlist not found') # check profile and Pi Presents issues are compatible if float(self.showlist.sissue()) != float(self.pipresents_issue): self.mon.err(self,"Version of profile " + self.showlist.sissue() + " is not same as Pi Presents, must exit") self.end('error','wrong version of profile') # get the 'start' show from the showlist index = self.showlist.index_of_show('start') if index >=0: self.showlist.select(index) self.starter_show=self.showlist.selected_show() else: self.mon.err(self,"Show [start] not found in showlist") self.end('error','start show not found') if self.starter_show['start-show']=='': self.mon.warn(self,"No Start Shows in Start Show") # ******************** # SET UP THE GUI # ******************** # turn off the screenblanking and saver if self.options['noblank'] is True: call(["xset","s", "off"]) call(["xset","s", "-dpms"]) self.root=Tk() self.title='Pi Presents - '+ self.pp_profile self.icon_text= 'Pi Presents' self.root.title(self.title) self.root.iconname(self.icon_text) self.root.config(bg=self.pp_background) self.mon.log(self, 'native screen dimensions are ' + str(self.root.winfo_screenwidth()) + ' x ' + str(self.root.winfo_screenheight()) + ' pixcels') if self.options['screensize'] =='': self.screen_width = self.root.winfo_screenwidth() self.screen_height = self.root.winfo_screenheight() else: reason,message,self.screen_width,self.screen_height=self.parse_screen(self.options['screensize']) if reason =='error': self.mon.err(self,message) self.end('error',message) self.mon.log(self, 'commanded screen dimensions are ' + str(self.screen_width) + ' x ' + str(self.screen_height) + ' pixcels') # set window dimensions and decorations if self.options['fullscreen'] is False: self.window_width=int(self.root.winfo_screenwidth()*self.nonfull_window_width) self.window_height=int(self.root.winfo_screenheight()*self.nonfull_window_height) self.window_x=self.nonfull_window_x self.window_y=self.nonfull_window_y self.root.geometry("%dx%d%+d%+d" % (self.window_width,self.window_height,self.window_x,self.window_y)) else: self.window_width=self.screen_width self.window_height=self.screen_height self.root.attributes('-fullscreen', True) os.system('unclutter 1>&- 2>&- &') # Suppress 'someone created a subwindow' complaints from unclutter self.window_x=0 self.window_y=0 self.root.geometry("%dx%d%+d%+d" % (self.window_width,self.window_height,self.window_x,self.window_y)) self.root.attributes('-zoomed','1') # canvs cover the whole screen whatever the size of the window. self.canvas_height=self.screen_height self.canvas_width=self.screen_width # make sure focus is set. self.root.focus_set() # define response to main window closing. self.root.protocol ("WM_DELETE_WINDOW", self.handle_user_abort) # setup a canvas onto which will be drawn the images or text self.canvas = Canvas(self.root, bg=self.pp_background) if self.options['fullscreen'] is True: self.canvas.config(height=self.canvas_height, width=self.canvas_width, highlightthickness=0) else: self.canvas.config(height=self.canvas_height, width=self.canvas_width, highlightthickness=1, highlightcolor='yellow') self.canvas.place(x=0,y=0) # self.canvas.config(bg='black') self.canvas.focus_set() # **************************************** # INITIALISE THE INPUT DRIVERS # **************************************** # each driver takes a set of inputs, binds them to symboic names # and sets up a callback which returns the symbolic name when an input event occurs/ # use keyboard driver to bind keys to symbolic names and to set up callback kbd=KbdDriver() if kbd.read(pp_dir,self.pp_home,self.pp_profile) is False: self.end('error','cannot find or error in keys.cfg') kbd.bind_keys(self.root,self.handle_input_event) self.sr=ScreenDriver() # read the screen click area config file reason,message = self.sr.read(pp_dir,self.pp_home,self.pp_profile) if reason == 'error': self.end('error','cannot find screen.cfg') # create click areas on the canvas, must be polygon as outline rectangles are not filled as far as find_closest goes # click areas are made on the Pi Presents canvas not the show canvases. reason,message = self.sr.make_click_areas(self.canvas,self.handle_input_event) if reason == 'error': self.mon.err(self,message) self.end('error',message) # **************************************** # INITIALISE THE APPLICATION AND START # **************************************** self.shutdown_required=False self.exitpipresents_required=False # kick off GPIO if enabled by command line option self.gpio_enabled=False if os.path.exists(self.pp_profile + os.sep + 'pp_io_config'+os.sep+ 'gpio.cfg'): # initialise the GPIO self.gpiodriver=GPIODriver() reason,message=self.gpiodriver.init(pp_dir,self.pp_home,self.pp_profile,self.canvas,50,self.handle_input_event) if reason == 'error': self.end('error',message) else: self.gpio_enabled=True # and start polling gpio self.gpiodriver.poll() # kick off animation sequencer self.animate = Animate() self.animate.init(pp_dir,self.pp_home,self.pp_profile,self.canvas,200,self.handle_output_event) self.animate.poll() #create a showmanager ready for time of day scheduler and osc server show_id=-1 self.show_manager=ShowManager(show_id,self.showlist,self.starter_show,self.root,self.canvas,self.pp_dir,self.pp_profile,self.pp_home) # first time through set callback to terminate Pi Presents if all shows have ended. self.show_manager.init(self.canvas,self.all_shows_ended_callback,self.handle_command,self.showlist) # Register all the shows in the showlist reason,message=self.show_manager.register_shows() if reason == 'error': self.mon.err(self,message) self.end('error',message) # Init OSCDriver, read config and start OSC server self.osc_enabled=False if os.path.exists(self.pp_profile + os.sep + 'pp_io_config'+ os.sep + 'osc.cfg'): self.oscdriver=OSCDriver() reason,message=self.oscdriver.init(self.pp_profile,self.handle_command,self.handle_input_event,self.e_osc_handle_output_event) if reason == 'error': self.end('error',message) else: self.osc_enabled=True self.root.after(1000,self.oscdriver.start_server()) # and run the start shows self.run_start_shows() # set up the time of day scheduler including catchup self.tod_enabled=False if os.path.exists(self.pp_profile + os.sep + 'schedule.json'): # kick off the time of day scheduler which may run additional shows self.tod=TimeOfDay() self.tod.init(pp_dir,self.pp_home,self.pp_profile,self.root,self.handle_command) self.tod_enabled = True # then start the time of day scheduler if self.tod_enabled is True: self.tod.poll() # start Tkinters event loop self.root.mainloop( ) def parse_screen(self,size_text): fields=size_text.split('*') if len(fields)!=2: return 'error','do not understand --fullscreen comand option',0,0 elif fields[0].isdigit() is False or fields[1].isdigit() is False: return 'error','dimensions are not positive integers in ---fullscreen',0,0 else: return 'normal','',int(fields[0]),int(fields[1]) # ********************* # RUN START SHOWS # ******************** def run_start_shows(self): self.mon.trace(self,'run start shows') # parse the start shows field and start the initial shows show_refs=self.starter_show['start-show'].split() for show_ref in show_refs: reason,message=self.show_manager.control_a_show(show_ref,'open') if reason == 'error': self.mon.err(self,message) # ********************* # User inputs # ******************** # handles one command provided as a line of text def handle_command(self,command_text): self.mon.log(self,"command received: " + command_text) if command_text.strip()=="": return if command_text[0]=='/': if self.osc_enabled is True: self.oscdriver.send_command(command_text) return fields= command_text.split() show_command=fields[0] if len(fields)>1: show_ref=fields[1] else: show_ref='' if show_command in ('open','close'): if self.shutdown_required is False: reason,message=self.show_manager.control_a_show(show_ref,show_command) else: return elif show_command == 'exitpipresents': self.exitpipresents_required=True if self.show_manager.all_shows_exited() is True: # need root.after to get out of st thread self.root.after(1,self.e_all_shows_ended_callback) return else: reason,message= self.show_manager.exit_all_shows() elif show_command == 'shutdownnow': # need root.after to get out of st thread self.root.after(1,self.e_shutdown_pressed) return else: reason='error' message = 'command not recognised: '+ show_command if reason=='error': self.mon.err(self,message) return def e_all_shows_ended_callback(self): self.all_shows_ended_callback('normal','no shows running') def e_shutdown_pressed(self): self.shutdown_pressed('now') def e_osc_handle_output_event(self,line): #jump out of server thread self.root.after(1, lambda arg=line: self.osc_handle_output_event(arg)) def osc_handle_output_event(self,line): self.mon.log(self,"output event received: "+ line) #osc sends output events as a string reason,message,delay,name,param_type,param_values=self.animate.parse_animate_fields(line) if reason == 'error': self.mon.err(self,message) self.end(reason,message) self.handle_output_event(name,param_type,param_values,0) def handle_output_event(self,symbol,param_type,param_values,req_time): if self.gpio_enabled is True: reason,message=self.gpiodriver.handle_output_event(symbol,param_type,param_values,req_time) if reason =='error': self.mon.err(self,message) self.end(reason,message) else: self.mon.warn(self,'GPIO not enabled') # all input events call this callback with a symbolic name. # handle events that affect PP overall, otherwise pass to all active shows def handle_input_event(self,symbol,source): self.mon.log(self,"event received: "+symbol + ' from '+ source) if symbol == 'pp-terminate': self.handle_user_abort() elif symbol == 'pp-shutdown': self.shutdown_pressed('delay') elif symbol == 'pp-shutdownnow': # need root.after to grt out of st thread self.root.after(1,self.e_shutdown_pressed) return elif symbol == 'pp-exitpipresents': self.exitpipresents_required=True if self.show_manager.all_shows_exited() is True: # need root.after to grt out of st thread self.root.after(1,self.e_all_shows_ended_callback) return reason,message= self.show_manager.exit_all_shows() else: # events for shows affect the show and could cause it to exit. for show in self.show_manager.shows: show_obj=show[ShowManager.SHOW_OBJ] if show_obj is not None: show_obj.handle_input_event(symbol) def shutdown_pressed(self, when): if when == 'delay': self.root.after(5000,self.on_shutdown_delay) else: self.shutdown_required=True if self.show_manager.all_shows_exited() is True: self.all_shows_ended_callback('normal','no shows running') else: # calls exit method of all shows, results in all_shows_closed_callback self.show_manager.exit_all_shows() def on_shutdown_delay(self): # 5 second delay is up, if shutdown button still pressed then shutdown if self.gpiodriver.shutdown_pressed() is True: self.shutdown_required=True if self.show_manager.all_shows_exited() is True: self.all_shows_ended_callback('normal','no shows running') else: # calls exit method of all shows, results in all_shows_closed_callback self.show_manager.exit_all_shows() def handle_sigterm(self,signum,frame): self.mon.log(self,'SIGTERM received - '+ str(signum)) self.terminate() def handle_user_abort(self): self.mon.log(self,'User abort received') self.terminate() def terminate(self): self.mon.log(self, "terminate received") needs_termination=False for show in self.show_manager.shows: # print show[ShowManager.SHOW_OBJ], show[ShowManager.SHOW_REF] if show[ShowManager.SHOW_OBJ] is not None: needs_termination=True self.mon.log(self,"Sent terminate to show "+ show[ShowManager.SHOW_REF]) # call shows terminate method # eventually the show will exit and after all shows have exited all_shows_callback will be executed. show[ShowManager.SHOW_OBJ].terminate() if needs_termination is False: self.end('killed','killed - no termination of shows required') # ****************************** # Ending Pi Presents after all the showers and players are closed # ************************** # callback from ShowManager when all shows have ended def all_shows_ended_callback(self,reason,message): self.canvas.config(bg=self.pp_background) if reason in ('killed','error') or self.shutdown_required is True or self.exitpipresents_required is True: self.end(reason,message) def end(self,reason,message): self.mon.log(self,"Pi Presents ending with reason: " + reason) if self.root is not None: self.root.destroy() self.tidy_up() # gc.collect() # print gc.garbage if reason == 'killed': self.mon.log(self, "Pi Presents Aborted, au revoir") # close logging files self.mon.finish() sys.exit(101) elif reason == 'error': self.mon.log(self, "Pi Presents closing because of error, sorry") # close logging files self.mon.finish() sys.exit(102) else: self.mon.log(self,"Pi Presents exiting normally, bye") # close logging files self.mon.finish() if self.shutdown_required is True: # print 'SHUTDOWN' call(['sudo', 'shutdown', '-h', '-t 5','now']) sys.exit(100) else: sys.exit(100) # tidy up all the peripheral bits of Pi Presents def tidy_up(self): self.mon.log(self, "Tidying Up") # turn screen blanking back on if self.options['noblank'] is True: call(["xset","s", "on"]) call(["xset","s", "+dpms"]) # tidy up animation and gpio if self.animate is not None: self.animate.terminate() if self.gpio_enabled==True: self.gpiodriver.terminate() if self.osc_enabled is True: self.oscdriver.terminate() # tidy up time of day scheduler if self.tod_enabled is True: self.tod.terminate()
class VisualizerUI: def __init__(self, width, height, pixelSize, top=False): self._maxWindowWidth = 1500 self._master = Tk() self._q = Queue.Queue() self._hasFrame = False self.x = width self.y = height self._count = self.x * self.y self._values = [] self._leds = [] self._pixelSize = pixelSize self._pixelPad = int(pixelSize / 2) self._pixelSpace = 0 self.initUI() self.configure(self.x, self.y) self.checkQ() self._master.attributes("-topmost", top) def checkQ(self): if not self._q.empty(): data = self._q.get_nowait() self.updateUI(data) wait = 0 if "darwin" in platform.system().lower(): wait = 1 self._master.after(wait, self.checkQ) self._master.update_idletasks() def mainloop(self): self._master.mainloop() def updateUI(self, data): size = len(data) / 3 if size != self._count: log.warning("Bytecount mismatch") return for i in range(size): r = data[i * 3 + 0] g = data[i * 3 + 1] b = data[i * 3 + 2] self._values[i] = self.toHexColor(r, g, b) try: for i in range(self._count): self._canvas.itemconfig(self._leds[i], fill=self._values[i]) except TclError: # Looks like the UI closed! pass def toHexColor(self, r, g, b): return "#{0:02x}{1:02x}{2:02x}".format(r, g, b) def update(self, data): self._q.put(data) def hasFrame(self): return not self._q.empty() def configure(self, x, y): self._type = type self.x = x self.y = y self._count = x * y self._values = [] # init colors to all black (off) for i in range(self._count): self._values.append("#101010") c = self._canvas c.delete(ALL) self._leds = [] for i in range(self._count): index = c.create_rectangle(0, 0, self._pixelSize, self._pixelSize, fill=self._values[i]) self._leds.append(index) self.layoutPixels() def layoutPixels(self): if len(self._leds) == 0: return x_off = 0 row = 0 count = 0 w = 0 h = 0 for y in range(self.y): for x in range(self.x): if y % 2 != 0: x = self.x - x - 1 _x = self._pixelPad + \ ((x - x_off) * (self._pixelSize + self._pixelSpace)) _y = self._pixelPad + \ ((y + row) * (self._pixelSize + self._pixelSpace)) if row > 0: _y += 3 * row _w = _x + self._pixelSize + self._pixelSpace + self._pixelPad if _w > w: w = _w _h = _y + self._pixelSize + self._pixelSpace + self._pixelPad if _h > h: h = _h if self.y == 1 and _x + ((self._pixelSize + self._pixelSpace) * 2) > self._maxWindowWidth: row += 1 x_off += (x - x_off + 1) self._canvas.coords(self._leds[count], _x, _y, _x + self._pixelSize, _y + self._pixelSize) count += 1 self._master.geometry("{0}x{1}".format(w, h)) self._master.update() self._canvas.config(width=w, height=h) def __CancelCommand(self, event=None): self._master.quit() self._master.destroy() sys.exit() # def __resizeEvent(self, event): # width = self._master.winfo_width() # height = self._master.winfo_height() # if width != self._width or height != self._height: # self._width = width # self._height = height # self._master.after_idle(self.layoutPixels) # def __handleResize(self): # width = self._master.winfo_width() # height = self._master.winfo_height() # if width != self._width or height != self._height: # self._width = width # self._height = height # self.layoutPixels() # self._master.after_idle(self.__handleResize) def initUI(self): m = self._master m.protocol('WM_DELETE_WINDOW', self.__CancelCommand) m.title("BiblioPixel Visualizer") m.geometry("10x10") m.update() self._width = m.winfo_width() self._height = m.winfo_height() m.minsize(self._width, self._height) self._canvas = Canvas(self._master, background="#000000") c = self._canvas c.pack(side=TOP) self.layoutPixels()
else: self.go_to_up.set(True) def toggle_focus_left(self, _event=None): pyautogui.click(self.left_scroller_position) def toggle_focus_righ(self, _event=None): pyautogui.click(self.right_scroller_position) def scrolling(self, scorll_gap, left=True, right=True): if left == True: pyautogui.click(self.left_scroller_position) pyautogui.scroll(scorll_gap) # time.sleep(0.2) if right == True: pyautogui.click(self.right_scroller_position) pyautogui.scroll(scorll_gap) # time.sleep(0.2) pyautogui.click(app.winfo_screenwidth()-200, app.winfo_y()+30) app = Tk() Scroller(app) app.geometry('%dx%d+%d+%d' % (app.winfo_screenwidth(), 40, (app.winfo_screenwidth()/2)-110 , app.winfo_screenheight()-40)) app.title("Scroller") app.lift() app.attributes("-topmost", True) app.resizable(0,0) app.mainloop() # pyautogui.click((app.winfo_screenwidth()/2)-120 , app.winfo_screenheight()-240)
def initializeGui(results): root = Tk() root.attributes('-fullscreen', True) ex = ResultsWindow(root, results) root.geometry("420x250+300+300") root.mainloop()
def setFname(self): bw = Tk() bw.attributes("-topmost", True) bw.withdraw() self.fname = askopenfilename() bw.destroy()
self.midi_check.select() self.file_label.grid(row=1, column=2, sticky=W) self.folder_label.grid(row=2, column=2, sticky=W) self.file_button.grid(row=1, column=1, sticky=W) self.folder_button.grid(row=2, column=1, sticky=W) self.gen_button.grid(row=3, column=1) self.exit_button.grid(row=3, column=2) self.build_check.grid(row=4, column=1) self.midi_check.grid(row=4, column=2) def pick_file(self): param.infile = tkFileDialog.askopenfilename( initialdir=".", title="Select scores", filetypes=(("png files", "*.png"), ("all files", "*.*"))) self.file_text.set(param.infile) def pick_folder(self): param.outdir = tkFileDialog.askdirectory(initialdir=".") self.folder_text.set(param.outdir) root = Tk() root.geometry("600x120") root.eval('tk::PlaceWindow %s center' % root.winfo_pathname(root.winfo_id())) my_gui = MainGui(root) root.lift() root.attributes('-topmost', True) root.after_idle(root.attributes, '-topmost', False) root.mainloop()
def set_dir(titlestring): # Make a top-level instance and hide since it is ugly and big. root = Tk() root.withdraw() # Make it almost invisible - no decorations, 0 size, top left corner. root.overrideredirect(True) root.geometry('0x0+0+0') # # Show window again and lift it to top so it can get focus, # otherwise dialogs will end up behind the terminal. root.deiconify() root.attributes("-topmost",1) root.focus_force() file_path = tkFileDialog.askdirectory(parent=root,title=titlestring) if file_path != "": return str(file_path) else: print "you didn't open anything!" # Get rid of the top-level instance once to make it actually invisible. root.destroy()
class PiPresents(object): def pipresents_version(self): vitems=self.pipresents_issue.split('.') if len(vitems)==2: # cope with 2 digit version numbers before 1.3.2 return 1000*int(vitems[0])+100*int(vitems[1]) else: return 1000*int(vitems[0])+100*int(vitems[1])+int(vitems[2]) def __init__(self): # gc.set_debug(gc.DEBUG_UNCOLLECTABLE|gc.DEBUG_INSTANCES|gc.DEBUG_OBJECTS|gc.DEBUG_SAVEALL) gc.set_debug(gc.DEBUG_UNCOLLECTABLE|gc.DEBUG_SAVEALL) self.pipresents_issue="1.3.5" self.pipresents_minorissue = '1.3.5d' # position and size of window without -f command line option self.nonfull_window_width = 0.45 # proportion of width self.nonfull_window_height= 0.7 # proportion of height self.nonfull_window_x = 0 # position of top left corner self.nonfull_window_y=0 # position of top left corner StopWatch.global_enable=False # set up the handler for SIGTERM signal.signal(signal.SIGTERM,self.handle_sigterm) # **************************************** # Initialisation # *************************************** # get command line options self.options=command_options() # get Pi Presents code directory pp_dir=sys.path[0] self.pp_dir=pp_dir if not os.path.exists(pp_dir+"/pipresents.py"): if self.options['manager'] is False: tkMessageBox.showwarning("Pi Presents","Bad Application Directory") exit(102) # Initialise logging and tracing Monitor.log_path=pp_dir self.mon=Monitor() # Init in PiPresents only self.mon.init() # uncomment to enable control of logging from within a class # Monitor.enable_in_code = True # enables control of log level in the code for a class - self.mon.set_log_level() # make a shorter list to log/trace only some classes without using enable_in_code. Monitor.classes = ['PiPresents', 'HyperlinkShow','RadioButtonShow','ArtLiveShow','ArtMediaShow','MediaShow','LiveShow','MenuShow', 'GapShow','Show','ArtShow', 'AudioPlayer','BrowserPlayer','ImagePlayer','MenuPlayer','MessagePlayer','VideoPlayer','Player', 'MediaList','LiveList','ShowList', 'PathManager','ControlsManager','ShowManager','PluginManager','IOPluginManager', 'MplayerDriver','OMXDriver','UZBLDriver', 'TimeOfDay','ScreenDriver','Animate','OSCDriver','CounterManager', 'Network','Mailer' ] # Monitor.classes=['PiPresents','MediaShow','GapShow','Show','VideoPlayer','Player','OMXDriver'] # Monitor.classes=['OSCDriver'] # get global log level from command line Monitor.log_level = int(self.options['debug']) Monitor.manager = self.options['manager'] # print self.options['manager'] self.mon.newline(3) self.mon.sched (self,None, "Pi Presents is starting, Version:"+self.pipresents_minorissue + ' at '+time.strftime("%Y-%m-%d %H:%M.%S")) self.mon.log (self, "Pi Presents is starting, Version:"+self.pipresents_minorissue+ ' at '+time.strftime("%Y-%m-%d %H:%M.%S")) # self.mon.log (self," OS and separator:" + os.name +' ' + os.sep) self.mon.log(self,"sys.path[0] - location of code: "+sys.path[0]) # log versions of Raspbian and omxplayer, and GPU Memory with open("/boot/issue.txt") as ifile: self.mon.log(self,'\nRaspbian: '+ifile.read()) self.mon.log(self,'\n'+check_output(["omxplayer", "-v"])) self.mon.log(self,'\nGPU Memory: '+check_output(["vcgencmd", "get_mem", "gpu"])) if os.geteuid() == 0: print 'Do not run Pi Presents with sudo' self.mon.log(self,'Do not run Pi Presents with sudo') self.mon.finish() sys.exit(102) if "DESKTOP_SESSION" not in os.environ: print 'Pi Presents must be run from the Desktop' self.mon.log(self,'Pi Presents must be run from the Desktop') self.mon.finish() sys.exit(102) else: self.mon.log(self,'Desktop is '+ os.environ['DESKTOP_SESSION']) # optional other classes used self.root=None self.ppio=None self.tod=None self.animate=None self.ioplugin_manager=None self.oscdriver=None self.osc_enabled=False self.tod_enabled=False self.email_enabled=False user=os.getenv('USER') if user is None: tkMessageBox.showwarning("You must be logged in to run Pi Presents") exit(102) if user !='pi': self.mon.warn(self,"You must be logged as pi to use GPIO") self.mon.log(self,'User is: '+ user) # self.mon.log(self,"os.getenv('HOME') - user home directory (not used): " + os.getenv('HOME')) # does not work # self.mon.log(self,"os.path.expanduser('~') - user home directory: " + os.path.expanduser('~')) # does not work # check network is available self.network_connected=False self.network_details=False self.interface='' self.ip='' self.unit='' # sets self.network_connected and self.network_details self.init_network() # start the mailer and send email when PP starts self.email_enabled=False if self.network_connected is True: self.init_mailer() if self.email_enabled is True and self.mailer.email_at_start is True: subject= '[Pi Presents] ' + self.unit + ': PP Started on ' + time.strftime("%Y-%m-%d %H:%M") message = time.strftime("%Y-%m-%d %H:%M") + '\nUnit: ' + self.unit + ' Profile: '+ self.options['profile']+ '\n ' + self.interface + '\n ' + self.ip self.send_email('start',subject,message) # get profile path from -p option if self.options['profile'] != '': self.pp_profile_path="/pp_profiles/"+self.options['profile'] else: self.mon.err(self,"Profile not specified in command ") self.end('error','Profile not specified with the commands -p option') # get directory containing pp_home from the command, if self.options['home'] == "": home = os.sep+ 'home' + os.sep + user + os.sep+"pp_home" else: home = self.options['home'] + os.sep+ "pp_home" self.mon.log(self,"pp_home directory is: " + home) # check if pp_home exists. # try for 10 seconds to allow usb stick to automount found=False for i in range (1, 10): self.mon.log(self,"Trying pp_home at: " + home + " (" + str(i)+')') if os.path.exists(home): found=True self.pp_home=home break time.sleep (1) if found is True: self.mon.log(self,"Found Requested Home Directory, using pp_home at: " + home) else: self.mon.err(self,"Failed to find pp_home directory at " + home) self.end('error',"Failed to find pp_home directory at " + home) # check profile exists self.pp_profile=self.pp_home+self.pp_profile_path if os.path.exists(self.pp_profile): self.mon.sched(self,None,"Running profile: " + self.pp_profile_path) self.mon.log(self,"Found Requested profile - pp_profile directory is: " + self.pp_profile) else: self.mon.err(self,"Failed to find requested profile: "+ self.pp_profile) self.end('error',"Failed to find requested profile: "+ self.pp_profile) self.mon.start_stats(self.options['profile']) if self.options['verify'] is True: self.mon.err(self,"Validation option not supported - use the editor") self.end('error','Validation option not supported - use the editor') # initialise and read the showlist in the profile self.showlist=ShowList() self.showlist_file= self.pp_profile+ "/pp_showlist.json" if os.path.exists(self.showlist_file): self.showlist.open_json(self.showlist_file) else: self.mon.err(self,"showlist not found at "+self.showlist_file) self.end('error',"showlist not found at "+self.showlist_file) # check profile and Pi Presents issues are compatible if self.showlist.profile_version() != self.pipresents_version(): self.mon.err(self,"Version of showlist " + self.showlist.profile_version_string + " is not same as Pi Presents") self.end('error',"Version of showlist " + self.showlist.profile_version_string + " is not same as Pi Presents") # get the 'start' show from the showlist index = self.showlist.index_of_start_show() if index >=0: self.showlist.select(index) self.starter_show=self.showlist.selected_show() else: self.mon.err(self,"Show [start] not found in showlist") self.end('error',"Show [start] not found in showlist") # ******************** # SET UP THE GUI # ******************** # turn off the screenblanking and saver if self.options['noblank'] is True: call(["xset","s", "off"]) call(["xset","s", "-dpms"]) self.root=Tk() self.title='Pi Presents - '+ self.pp_profile self.icon_text= 'Pi Presents' self.root.title(self.title) self.root.iconname(self.icon_text) self.root.config(bg=self.starter_show['background-colour']) self.mon.log(self, 'monitor screen dimensions are ' + str(self.root.winfo_screenwidth()) + ' x ' + str(self.root.winfo_screenheight()) + ' pixels') if self.options['screensize'] =='': self.screen_width = self.root.winfo_screenwidth() self.screen_height = self.root.winfo_screenheight() else: reason,message,self.screen_width,self.screen_height=self.parse_screen(self.options['screensize']) if reason =='error': self.mon.err(self,message) self.end('error',message) self.mon.log(self, 'forced screen dimensions (--screensize) are ' + str(self.screen_width) + ' x ' + str(self.screen_height) + ' pixels') # set window dimensions and decorations if self.options['fullscreen'] is False: self.window_width=int(self.root.winfo_screenwidth()*self.nonfull_window_width) self.window_height=int(self.root.winfo_screenheight()*self.nonfull_window_height) self.window_x=self.nonfull_window_x self.window_y=self.nonfull_window_y self.root.geometry("%dx%d%+d%+d" % (self.window_width,self.window_height,self.window_x,self.window_y)) else: self.window_width=self.screen_width self.window_height=self.screen_height self.root.attributes('-fullscreen', True) os.system('unclutter &') self.window_x=0 self.window_y=0 self.root.geometry("%dx%d%+d%+d" % (self.window_width,self.window_height,self.window_x,self.window_y)) self.root.attributes('-zoomed','1') # canvas cover the whole screen whatever the size of the window. self.canvas_height=self.screen_height self.canvas_width=self.screen_width # make sure focus is set. self.root.focus_set() # define response to main window closing. self.root.protocol ("WM_DELETE_WINDOW", self.handle_user_abort) # setup a canvas onto which will be drawn the images or text self.canvas = Canvas(self.root, bg=self.starter_show['background-colour']) if self.options['fullscreen'] is True: self.canvas.config(height=self.canvas_height, width=self.canvas_width, highlightthickness=0) else: self.canvas.config(height=self.canvas_height, width=self.canvas_width, highlightthickness=1, highlightcolor='yellow') self.canvas.place(x=0,y=0) # self.canvas.config(bg='black') self.canvas.focus_set() # **************************************** # INITIALISE THE TOUCHSCREEN DRIVER # **************************************** # each driver takes a set of inputs, binds them to symboic names # and sets up a callback which returns the symbolic name when an input event occurs self.sr=ScreenDriver() # read the screen click area config file reason,message = self.sr.read(pp_dir,self.pp_home,self.pp_profile) if reason == 'error': self.end('error','cannot find, or error in screen.cfg') # create click areas on the canvas, must be polygon as outline rectangles are not filled as far as find_closest goes # click areas are made on the Pi Presents canvas not the show canvases. reason,message = self.sr.make_click_areas(self.canvas,self.handle_input_event) if reason == 'error': self.mon.err(self,message) self.end('error',message) # **************************************** # INITIALISE THE APPLICATION AND START # **************************************** self.shutdown_required=False self.reboot_required=False self.terminate_required=False self.exitpipresents_required=False # initialise the I/O plugins by importing their drivers self.ioplugin_manager=IOPluginManager() reason,message=self.ioplugin_manager.init(self.pp_dir,self.pp_profile,self.root,self.handle_input_event) if reason == 'error': # self.mon.err(self,message) self.end('error',message) # kick off animation sequencer self.animate = Animate() self.animate.init(pp_dir,self.pp_home,self.pp_profile,self.canvas,200,self.handle_output_event) self.animate.poll() #create a showmanager ready for time of day scheduler and osc server show_id=-1 self.show_manager=ShowManager(show_id,self.showlist,self.starter_show,self.root,self.canvas,self.pp_dir,self.pp_profile,self.pp_home) # first time through set callback to terminate Pi Presents if all shows have ended. self.show_manager.init(self.canvas,self.all_shows_ended_callback,self.handle_command,self.showlist) # Register all the shows in the showlist reason,message=self.show_manager.register_shows() if reason == 'error': self.mon.err(self,message) self.end('error',message) # Init OSCDriver, read config and start OSC server self.osc_enabled=False if self.network_connected is True: if os.path.exists(self.pp_profile + os.sep + 'pp_io_config'+ os.sep + 'osc.cfg'): self.oscdriver=OSCDriver() reason,message=self.oscdriver.init(self.pp_profile, self.unit,self.interface,self.ip, self.handle_command,self.handle_input_event,self.e_osc_handle_animate) if reason == 'error': self.mon.err(self,message) self.end('error',message) else: self.osc_enabled=True self.root.after(1000,self.oscdriver.start_server()) # initialise ToD scheduler calculating schedule for today self.tod=TimeOfDay() reason,message,self.tod_enabled = self.tod.init(pp_dir,self.pp_home,self.pp_profile,self.showlist,self.root,self.handle_command) if reason == 'error': self.mon.err(self,message) self.end('error',message) # warn if the network not available when ToD required if self.tod_enabled is True and self.network_connected is False: self.mon.warn(self,'Network not connected so Time of Day scheduler may be using the internal clock') # init the counter manager self.counter_manager=CounterManager() self.counter_manager.init() # warn about start shows and scheduler if self.starter_show['start-show']=='' and self.tod_enabled is False: self.mon.sched(self,None,"No Start Shows in Start Show and no shows scheduled") self.mon.warn(self,"No Start Shows in Start Show and no shows scheduled") if self.starter_show['start-show'] !='' and self.tod_enabled is True: self.mon.sched(self,None,"Start Shows in Start Show and shows scheduled - conflict?") self.mon.warn(self,"Start Shows in Start Show and shows scheduled - conflict?") # run the start shows self.run_start_shows() # kick off the time of day scheduler which may run additional shows if self.tod_enabled is True: self.tod.poll() # start the I/O plugins input event generation self.ioplugin_manager.start() # start Tkinters event loop self.root.mainloop( ) def parse_screen(self,size_text): fields=size_text.split('*') if len(fields)!=2: return 'error','do not understand --screensize comand option',0,0 elif fields[0].isdigit() is False or fields[1].isdigit() is False: return 'error','dimensions are not positive integers in --screensize',0,0 else: return 'normal','',int(fields[0]),int(fields[1]) # ********************* # RUN START SHOWS # ******************** def run_start_shows(self): self.mon.trace(self,'run start shows') # parse the start shows field and start the initial shows show_refs=self.starter_show['start-show'].split() for show_ref in show_refs: reason,message=self.show_manager.control_a_show(show_ref,'open') if reason == 'error': self.mon.err(self,message) # ********************* # User inputs # ******************** def e_osc_handle_animate(self,line): #jump out of server thread self.root.after(1, lambda arg=line: self.osc_handle_animate(arg)) def osc_handle_animate(self,line): self.mon.log(self,"animate command received: "+ line) #osc sends output events as a string reason,message,delay,name,param_type,param_values=self.animate.parse_animate_fields(line) if reason == 'error': self.mon.err(self,message) self.end(reason,message) self.handle_output_event(name,param_type,param_values,0) # output events are animate commands def handle_output_event(self,symbol,param_type,param_values,req_time): reason,message=self.ioplugin_manager.handle_output_event(symbol,param_type,param_values,req_time) if reason =='error': self.mon.err(self,message) self.end(reason,message) # all input events call this callback providing a symbolic name. # handle events that affect PP overall, otherwise pass to all active shows def handle_input_event(self,symbol,source): self.mon.log(self,"event received: "+symbol + ' from '+ source) if symbol == 'pp-terminate': self.handle_user_abort() elif symbol == 'pp-shutdown': self.mon.err(self,'pp-shutdown removed in version 1.3.3a, see Release Notes') self.end('error','pp-shutdown removed in version 1.3.3a, see Release Notes') elif symbol == 'pp-shutdownnow': # need root.after to grt out of st thread self.root.after(1,self.shutdownnow_pressed) return elif symbol == 'pp-exitpipresents': self.exitpipresents_required=True if self.show_manager.all_shows_exited() is True: # need root.after to grt out of st thread self.root.after(1,self.e_all_shows_ended_callback) return reason,message= self.show_manager.exit_all_shows() else: # pass the input event to all registered shows for show in self.show_manager.shows: show_obj=show[ShowManager.SHOW_OBJ] if show_obj is not None: show_obj.handle_input_event(symbol) # commands are generaed by tracks and shows # they can open or close shows, generate input events and do special tasks # commands also generate osc outputs to other computers # handles one command provided as a line of text def handle_command(self,command_text,source='',show=''): # print 'PIPRESENTS ',command_text,'\n Source',source,'from',show self.mon.log(self,"command received: " + command_text) if command_text.strip()=="": return fields= command_text.split() if fields[0] in ('osc','OSC'): if self.osc_enabled is True: status,message=self.oscdriver.parse_osc_command(fields[1:]) if status=='warn': self.mon.warn(self,message) if status=='error': self.mon.err(self,message) self.end('error',message) return if fields[0] =='counter': status,message=self.counter_manager.parse_counter_command(fields[1:]) if status=='error': self.mon.err(self,message) self.end('error',message) return show_command=fields[0] if len(fields)>1: show_ref=fields[1] else: show_ref='' if show_command in ('open','close','closeall','openexclusive'): self.mon.sched(self, TimeOfDay.now,command_text + ' received from show:'+show) if self.shutdown_required is False and self.terminate_required is False: reason,message=self.show_manager.control_a_show(show_ref,show_command) else: return elif show_command =='monitor': self.handle_monitor_command(show_ref) return elif show_command =='cec': self.handle_cec_command(show_ref) return elif show_command == 'event': self.handle_input_event(show_ref,'Show Control') return elif show_command == 'exitpipresents': self.exitpipresents_required=True if self.show_manager.all_shows_exited() is True: # need root.after to get out of st thread self.root.after(1,self.e_all_shows_ended_callback) return else: reason,message= self.show_manager.exit_all_shows() elif show_command == 'shutdownnow': # need root.after to get out of st thread self.root.after(1,self.shutdownnow_pressed) return elif show_command == 'reboot': # need root.after to get out of st thread self.root.after(1,self.reboot_pressed) return else: reason='error' message = 'command not recognised: '+ show_command if reason=='error': self.mon.err(self,message) return def handle_monitor_command(self,command): if command == 'on': os.system('vcgencmd display_power 1 >/dev/null') elif command == 'off': os.system('vcgencmd display_power 0 >/dev/null') def handle_cec_command(self,command): if command == 'on': os.system('echo "on 0" | cec-client -s') elif command == 'standby': os.system('echo "standby 0" | cec-client -s') elif command == 'scan': os.system('echo scan | cec-client -s -d 1') # deal with differnt commands/input events def shutdownnow_pressed(self): self.shutdown_required=True if self.show_manager.all_shows_exited() is True: self.all_shows_ended_callback('normal','no shows running') else: # calls exit method of all shows, results in all_shows_closed_callback self.show_manager.exit_all_shows() def reboot_pressed(self): self.reboot_required=True if self.show_manager.all_shows_exited() is True: self.all_shows_ended_callback('normal','no shows running') else: # calls exit method of all shows, results in all_shows_closed_callback self.show_manager.exit_all_shows() def handle_sigterm(self,signum,fframe): self.mon.log(self,'SIGTERM received - '+ str(signum)) self.terminate() def handle_user_abort(self): self.mon.log(self,'User abort received') self.terminate() def terminate(self): self.mon.log(self, "terminate received") self.terminate_required=True needs_termination=False for show in self.show_manager.shows: # print show[ShowManager.SHOW_OBJ], show[ShowManager.SHOW_REF] if show[ShowManager.SHOW_OBJ] is not None: needs_termination=True self.mon.log(self,"Sent terminate to show "+ show[ShowManager.SHOW_REF]) # call shows terminate method # eventually the show will exit and after all shows have exited all_shows_callback will be executed. show[ShowManager.SHOW_OBJ].terminate() if needs_termination is False: self.end('killed','killed - no termination of shows required') # ****************************** # Ending Pi Presents after all the showers and players are closed # ************************** def e_all_shows_ended_callback(self): self.all_shows_ended_callback('normal','no shows running') # callback from ShowManager when all shows have ended def all_shows_ended_callback(self,reason,message): self.canvas.config(bg=self.starter_show['background-colour']) if reason in ('killed','error') or self.shutdown_required is True or self.exitpipresents_required is True or self.reboot_required is True: self.end(reason,message) def end(self,reason,message): self.mon.log(self,"Pi Presents ending with reason: " + reason) if self.root is not None: self.root.destroy() self.tidy_up() if reason == 'killed': if self.email_enabled is True and self.mailer.email_on_terminate is True: subject= '[Pi Presents] ' + self.unit + ': PP Exited with reason: Terminated' message = time.strftime("%Y-%m-%d %H:%M") + '\n ' + self.unit + '\n ' + self.interface + '\n ' + self.ip self.send_email(reason,subject,message) self.mon.sched(self, None,"Pi Presents Terminated, au revoir\n") self.mon.log(self, "Pi Presents Terminated, au revoir") # close logging files self.mon.finish() print 'Uncollectable Garbage',gc.collect() # objgraph.show_backrefs(objgraph.by_type('Monitor')) sys.exit(101) elif reason == 'error': if self.email_enabled is True and self.mailer.email_on_error is True: subject= '[Pi Presents] ' + self.unit + ': PP Exited with reason: Error' message_text = 'Error message: '+ message + '\n'+ time.strftime("%Y-%m-%d %H:%M") + '\n ' + self.unit + '\n ' + self.interface + '\n ' + self.ip self.send_email(reason,subject,message_text) self.mon.sched(self,None, "Pi Presents closing because of error, sorry\n") self.mon.log(self, "Pi Presents closing because of error, sorry") # close logging files self.mon.finish() print 'uncollectable garbage',gc.collect() sys.exit(102) else: self.mon.sched(self,None,"Pi Presents exiting normally, bye\n") self.mon.log(self,"Pi Presents exiting normally, bye") # close logging files self.mon.finish() if self.reboot_required is True: # print 'REBOOT' call (['sudo','reboot']) if self.shutdown_required is True: # print 'SHUTDOWN' call (['sudo','shutdown','now','SHUTTING DOWN']) print 'uncollectable garbage',gc.collect() sys.exit(100) # tidy up all the peripheral bits of Pi Presents def tidy_up(self): self.handle_monitor_command('on') self.mon.log(self, "Tidying Up") # turn screen blanking back on if self.options['noblank'] is True: call(["xset","s", "on"]) call(["xset","s", "+dpms"]) # tidy up animation if self.animate is not None: self.animate.terminate() # tidy up i/o plugins if self.ioplugin_manager != None: self.ioplugin_manager.terminate() if self.osc_enabled is True: self.oscdriver.terminate() # tidy up time of day scheduler if self.tod_enabled is True: self.tod.terminate() # ******************************* # Connecting to network and email # ******************************* def init_network(self): timeout=int(self.options['nonetwork']) if timeout== 0: self.network_connected=False self.unit='' self.ip='' self.interface='' return self.network=Network() self.network_connected=False # try to connect to network self.mon.log (self, 'Waiting up to '+ str(timeout) + ' seconds for network') success=self.network.wait_for_network(timeout) if success is False: self.mon.warn(self,'Failed to connect to network after ' + str(timeout) + ' seconds') # tkMessageBox.showwarning("Pi Presents","Failed to connect to network so using fake-hwclock") return self.network_connected=True self.mon.sched (self, None,'Time after network check is '+ time.strftime("%Y-%m-%d %H:%M.%S")) self.mon.log (self, 'Time after network check is '+ time.strftime("%Y-%m-%d %H:%M.%S")) # Get web configuration self.network_details=False network_options_file_path=self.pp_dir+os.sep+'pp_config'+os.sep+'pp_web.cfg' if not os.path.exists(network_options_file_path): self.mon.warn(self,"pp_web.cfg not found at "+network_options_file_path) return self.mon.log(self, 'Found pp_web.cfg in ' + network_options_file_path) self.network.read_config(network_options_file_path) self.unit=self.network.unit # get interface and IP details of preferred interface self.interface,self.ip = self.network.get_preferred_ip() if self.interface == '': self.network_connected=False return self.network_details=True self.mon.log (self, 'Network details ' + self.unit + ' ' + self.interface + ' ' +self.ip) def init_mailer(self): self.email_enabled=False email_file_path = self.pp_dir+os.sep+'pp_config'+os.sep+'pp_email.cfg' if not os.path.exists(email_file_path): self.mon.log(self,'pp_email.cfg not found at ' + email_file_path) return self.mon.log(self,'Found pp_email.cfg at ' + email_file_path) self.mailer=Mailer() self.mailer.read_config(email_file_path) # all Ok so can enable email if config file allows it. if self.mailer.email_allowed is True: self.email_enabled=True self.mon.log (self,'Email Enabled') def try_connect(self): tries=1 while True: success, error = self.mailer.connect() if success is True: return True else: self.mon.log(self,'Failed to connect to email SMTP server ' + str(tries) + '\n ' +str(error)) tries +=1 if tries >5: self.mon.log(self,'Failed to connect to email SMTP server after ' + str(tries)) return False def send_email(self,reason,subject,message): if self.try_connect() is False: return False else: success,error = self.mailer.send(subject,message) if success is False: self.mon.log(self, 'Failed to send email: ' + str(error)) success,error=self.mailer.disconnect() if success is False: self.mon.log(self,'Failed disconnect after send:' + str(error)) return False else: self.mon.log(self,'Sent email for ' + reason) success,error=self.mailer.disconnect() if success is False: self.mon.log(self,'Failed disconnect from email server ' + str(error)) return True