def unmount_OP_1(): if getMountPath("OP1") != "": unmountDisplay = Image.new('1', (128, 64)) draw = ImageDraw.Draw(unmountDisplay) draw.text((30, 25), "Ejecting!", font=getFont(), fill='white') displayImage(unmountDisplay) unmountdevice(config["OP_1_Mounted_Dir"]) config["OP_1_Mounted_Dir"] = "" config["USB_Mount_Path"] = "" unmountDisplay = Image.new('1', (128, 64)) draw = ImageDraw.Draw(unmountDisplay) draw.text((30, 25), "Ejected", font=getFont(), fill='white') displayImage(unmountDisplay) time.sleep(1) return True elif os.path.isdir(config["OP_Z_Mounted_Dir"]): unmountdevice(config["OP_Z_Mounted_Dir"]) unmountDisplay = Image.new('1', (128, 64)) draw = ImageDraw.Draw(unmountDisplay) draw.text((15, 25), "Ejected", font=getFont(), fill='white') displayImage(unmountDisplay) time.sleep(1) return True else: unmountDisplay = Image.new('1', (128, 64)) draw = ImageDraw.Draw(unmountDisplay) draw.text((15, 25), "No Device to Eject", font=getFont(), fill='white') displayImage(unmountDisplay) time.sleep(1) return False
def RenderOptionsMenu(lst): """ Renders items in given list, and return the string whatever user chooses :param lst: list of strings to render Example: ["Upload", "Rename", "Delete"] :return: String the user choose """ cursor = 1 while True: image = Image.new('1', (128, 64)) draw = ImageDraw.Draw(image) draw.rectangle([(0, 0), (128, 10)], 'white') draw.text((0, 2), "Actions", fill='black', font=getFont()) for i in range(0, len(lst)): draw.text((10, (i + 1) * 10), str(lst[i]), fill='white', font=getFont()) draw.text((2, cursor * 10), ">", fill='white', font=getFont()) displayImage(image) time.sleep(0.1) key = getKeyStroke() if key == "UP": if not cursor - 1 < 1: cursor -= 1 if key == "DOWN": if not cursor + 1 > len(lst): cursor += 1 if key == "A": return "RETURN" if key == "B": return lst[cursor - 1]
def check_OP_1_Connection(): # if config["USB_Mount_Path"] == "": # image = Image.new('1', (128, 64)) # image.paste(Image.open(workDir + "/Assets/Img/ConnectOP_1.png").convert("1")) # displayImage(image) connected = Image.new('1', (128, 64)) draw = ImageDraw.Draw(connected) draw.text((0, 25), "Connecting.....", font=getFont(), fill='white') displayImage(connected) if is_connected(): do_mount() connected = Image.new('1', (128, 64)) draw = ImageDraw.Draw(connected) draw.text((0, 25), "Connected", font=getFont(), fill='white') displayImage(connected) return True else: connected = Image.new('1', (128, 64)) draw = ImageDraw.Draw(connected) draw.text((0, 25), "No Connection!", font=getFont(), fill='white') displayImage(connected) config["USB_Mount_Path"] = "" config["OP_1_Mounted_Dir"] = "" time.sleep(1) return False
def RenderOptionsMenu(lst, title="action"): """ Renders items in given list, and return the string whatever user chooses :param title: :param lst: list of strings to render Example: ["Upload", "Rename", "Delete"] :return: String the user choose """ actualFilePointer = 1 currentCursor = 1 shortArray = [] while True: image = Image.new('1', (128, 64)) draw = ImageDraw.Draw(image) draw.rectangle([(0, 0), (128, 10)], 'white') draw.text((0, 2), title, fill='black', font=getFont()) shortArray = shiftArray(lst, shortArray, 0) for i in range(0, len(shortArray)): draw.text((10, (i + 1) * 10), str(shortArray[i]), fill='white', font=getFont()) # Render Scroll Bar if len(lst) > 5: scrollBarLength = int(getScrollBarSize(lst)) offset = getOffset(lst, actualFilePointer - 1, scrollBarLength) draw.line((127, 10 + offset, 127, 10 + scrollBarLength + offset), fill="white", width=1) draw.text((2, currentCursor * 10), ">", fill='white', font=getFont()) displayImage(image) key = getKeyStroke() if key == "UP": if currentCursor - 1 < 1: temp = shortArray shortArray = shiftArray(lst, shortArray, -1) if temp != shortArray: actualFilePointer -= 1 else: currentCursor -= 1 actualFilePointer -= 1 if key == "DOWN": if currentCursor + 1 > len(shortArray): temp = shortArray shortArray = shiftArray(lst, shortArray, 1) if temp != shortArray: actualFilePointer += 1 else: currentCursor += 1 actualFilePointer += 1 if key == "LEFT": return "RETURN" if key == "RIGHT": return lst[actualFilePointer - 1] if key == "A": return "RETURN" if key == "B": return lst[actualFilePointer - 1]
def _showCurrentConnectedDevice(self): if not self.in_Midi_tool_screen_flag: image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/Midi.png").convert("1")) draw = ImageDraw.Draw(image) if batteryConfig["enable"]: # Battery Level in percentage # draw.text((105, 0), readCapacity(), fill='black', font=self.smallFont) # Battery Level Icon icon = Image.open( os.path.join(workDir, getBatteryImagePath( readCapacity()))).convert("L") inverted_image = ImageOps.invert(icon) image.paste(inverted_image, (117, 0)) if self.in_out_device_selector_flag == 1: # Top Device Highlighted draw.rectangle(((15, 5), (120, 15)), 'white') draw.text( (20, 5), str(self._strip_Midi_Name(self.currentInDevice, maxLen=16)), fill='black', font=getFont()) else: draw.text( (20, 5), str(self._strip_Midi_Name(self.currentInDevice, maxLen=16)), fill='white', font=getFont()) if self.in_out_device_selector_flag == -1: # Bottom Device Highlighted draw.rectangle(((15, 50), (120, 60)), 'white') draw.text( (20, 50), str(self._strip_Midi_Name(self.currentOutDevice, maxLen=16)), fill='black', font=getFont()) else: draw.text( (20, 50), str(self._strip_Midi_Name(self.currentOutDevice, maxLen=16)), fill='white', font=getFont()) displayImage(image)
def _showParamAdjust(self, title="", message=""): self.in_Midi_tool_screen_flag = True image = Image.new('1', (128, 64)) draw = ImageDraw.Draw(image) draw.rectangle(((0, 0), (128, 64)), 'black') draw.rectangle(((0, 0), (128, 10)), 'white') # Title draw.text((0, 0), str(title), fill='black', font=getFont()) if "\n" in message: draw.text((30, 20), str(message), fill='white', font=getFont()) else: draw.text((30, 30), str(message), fill='white', font=getFont()) displayImage(image) time.sleep(1) self.in_Midi_tool_screen_flag = False
def fileTransferHelper(srclist, dest): """ Pass in list of paths to file, and copy to root destination It will create patch's parent folder if not already exist in the destination folder For example: fileTransferHelper(["..../OP1_File_Organizer/NotUsed/..../patch.aif"], dest = "/..../synth") :param srclist: ["pwd/1.aif", "pwd/2.aif", "pwd/3.aif",....., "pwd/n.aif"] :param dest: Root of the synth and drum destination folder :return: NA """ for i in srclist: srcParentFolderName = abspath(join(i, pardir)).split("/")[-1:][0] srcBaseName = basename(i) distParentFolderName = dest + "/" + str(srcParentFolderName) print(distParentFolderName) forcedir(distParentFolderName) image = Image.new('1', (128, 64)) if workDir in srclist[0]: # Local to OP1 image.paste(Image.open(workDir + "/Assets/Img/UploadPatches.png").convert("1")) else: # OP1 to Local image.paste(Image.open(workDir + "/Assets/Img/DownloadPatches.png").convert("1")) draw = ImageDraw.Draw(image) draw.text((20, 63), srcBaseName, font=getFont(), fill="white") displayImage(image) print(i, distParentFolderName + "/" + srcBaseName) shutil.copy2(i, distParentFolderName + "/" + srcBaseName) displayPng(workDir + "/Assets/Img/Done.png") getAnyKeyEvent() # Press any key to proceed return
def start(): image = Image.open(workDir + "/Assets/Img/OP_1Connect_64.png").convert("1") displayImage(image) # start_OP_1_Connection() connected = Image.new('1', (128, 64)) draw = ImageDraw.Draw(connected) draw.text((30, 25), "Connected !", font=getFont(), fill='white') displayImage(connected) currentCursor = 1 # Initialize Menu System pg = Menu_Page_Router.PageRouter() # Start First Page pg.renderPage(0, currentCursor) while 1: # if not is_connected(): # print("Disconnected") # start() key = getKeyStroke() if key == "UP": if currentCursor - 1 >= 1: currentCursor -= 1 pg.renderPage(0, currentCursor) elif key == "DOWN": if currentCursor + 1 < pg.getListSize(): currentCursor += 1 pg.renderPage(0, currentCursor) elif key == "LEFT": currentCursor = 1 pg.renderPage(-1, 1) elif key == "RIGHT": pg.renderPage(1, currentCursor) currentCursor = 1 elif key == "CENTER": pg.renderPage(1, currentCursor) currentCursor = 1 elif key == "B": # pg.renderPage(1, currentCursor) # currentCursor = 1 pass elif key == "A": # currentCursor = 1 # pg.renderPage(-1, 1) pass else: raise ("Log: Key ", key, "Not recognized")
def check_OP_Z_Connection(): connected = Image.new('1', (128, 64)) draw = ImageDraw.Draw(connected) draw.text((0, 25), "Connecting.....", font=getFont(), fill='white') displayImage(connected) if do_mount("OPZ"): connected = Image.new('1', (128, 64)) draw = ImageDraw.Draw(connected) draw.text((0, 25), "Connected", font=getFont(), fill='white') displayImage(connected) time.sleep(1) return True else: connected = Image.new('1', (128, 64)) draw = ImageDraw.Draw(connected) draw.text((0, 25), "No Connection!", font=getFont(), fill='white') displayImage(connected) config["USB_Mount_Path"] = "" time.sleep(1) return False
def renderStandardMenu(self, draw, currentDist=None, cursor=1): font = getFont() draw.rectangle([(-1, 0), (128, 64)], 'black', 'white') draw.rectangle([(0, 0), (128, 10)], 'white') draw.text((2, 0), str(currentDist[0][0]), fill='black', font=font) for i in range(1, len(currentDist)): draw.text((10, i * 10), str(currentDist[i][0]), fill='white', font=font) draw.text((2, cursor * 10), ">", fill='white', font=font)
def check_OP_1_Connection(): if is_connected(): do_mount() return True else: connected = Image.new('1', (128, 64)) draw = ImageDraw.Draw(connected) draw.text((0, 25), "Please Check Connection!", font=getFont(), fill='white') displayImage(connected) config["USB_Mount_Path"] = "" config["OP_1_Mounted_Dir"] = "" time.sleep(1) return False
def op1FunDownlaodQue(op1ServiceObj, downloadLst, savePath): op = op1ServiceObj for i in downloadLst: print(i) name, link = i regex = re.compile(".*?\]") result = re.findall(regex, name) dsp = name.replace(result[0], "") mesg = Image.new('1', (128, 64)) mesg.paste(Image.open(workDir + "/Assets/Img/downloadIcon.png").convert("1")) draw = ImageDraw.Draw(mesg) draw.text((5, 35), "Getting patch list", font=getFont(), fill='white') draw.text((5, 44), "from op1.fun...", font=getFont(), fill='white') displayImage(mesg) strzip = op.getPackDownloadURL(link) mesg = Image.new('1', (128, 64)) mesg.paste(Image.open(workDir + "/Assets/Img/downloadIcon.png").convert("1")) draw = ImageDraw.Draw(mesg) draw.text((20, 35), "Downloading...", font=getFont(), fill='white') draw.text((5, 45), dsp, font=getFont(), fill='white') displayImage(mesg) downloadFile = op.downloadFile(strzip) mesg = Image.new('1', (128, 64)) mesg.paste(Image.open(workDir + "/Assets/Img/downloadIcon.png").convert("1")) draw = ImageDraw.Draw(mesg) draw.text((25, 35), "Unpacking...", font=getFont(), fill='white') draw.text((5, 45), dsp, font=getFont(), fill='white') displayImage(mesg) try: op.unPackageToLocal(downloadFile, savePath) except: print("unpack error") time.sleep(1) if len(downloadLst) == 1: displayPng(workDir + "/Assets/Img/Done.png") getAnyKeyEvent() print ("Done Download and unpack")
def actionRouter(self, event): # =============Projects Actions =========== if event == "act_Backup_Project_From_OP_1": image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/BackupProject.png").convert("1")) displayImage(image) time.sleep(0.1) try: tape = TapeBackup() tape.copyToLocal() except: print("File Transfer Error") image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/Done.png").convert("1")) displayImage(image) time.sleep(0.1) getAnyKeyEvent() self.renderPage(-1, 1) if event == "act_Load_Project_From_Local": renderFolders(savePaths["Local_Projects"], "Upload") self.renderPage(-1, 1) # ===========Patches Actions=========== if event == "OP1_Synth_Patches": option = "RETURN" # while option == "RETURN": renderFolders(savePaths["OP_1_Synth"], "Backup") self.renderPage(-1, 1) if event == "OP1_Drum_Patches": renderFolders(savePaths["OP_1_Drum"], "Backup") self.renderPage(-1, 1) if event == "UploadSynthPatches": # option = "RETURN" # while option == "RETURN": renderFolders(savePaths["Local_Synth"], "Upload") # if option == "Upload": # print("Upload") # if option == "Rename": # print("Rename") # if option == "Delete": # print("Delete") self.renderPage(-1, 1) if event == "UploadDrumPatches": renderFolders(savePaths["Local_Drum"], "Upload") self.renderPage(-1, 1) if event == "act_5_Backup_All_Patches": self.renderPage(-1, 1) # ===========Eject Actions=========== if event == "act_ESC_Eject_OP_1": # unmount_OP_1() cmd = "sudo umount " + config["OP_1_Mounted_Dir"] try: os.system(cmd) except: pass print("Ejected") time.sleep(5) start() # pass if event == "checkStorage": image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/Storage_64.png").convert("1")) draw = ImageDraw.Draw(image) sampler, synth, drum = update_Current_Storage_Status() Disk = subprocess.check_output( "df -h | awk '$NF==\"/\"{printf \"%d/%dGB %s\", $3,$2,$5}'", shell=True) draw.text((50, 13), Disk, font=getFont(), fill="white") # Disk Storage Render draw.text((28, 48), str(config["Max_Synth_Sampler_patches"] - sampler), font=getFont(), fill="white") draw.text((70, 48), str(config["Max_Synth_Synthesis_patches"] - synth), font=getFont(), fill="white") draw.text((112, 48), str(config["Max_Drum_Patches"] - drum), font=getFont(), fill="white") displayImage(image) getAnyKeyEvent() # Press any key to proceed self.renderPage(-1, 1)
class PageRouter: pageQue = [MainPage] currentDist = [] font = getFont() smallFont = getSmallFont() def __init__(self): self.processState = False self.cursor = 1 def getListSize(self): return len(self.pageQue[-1]) def renderPage(self, action, cur): frameSize = (128, 64) image = Image.new('1', frameSize) draw = ImageDraw.Draw(image) currentDist = self.pageQue[-1] # Stay on same page (Up Down) Render Standard Menu if action == 0: draw.rectangle([(-1, 0), (128, 64)], 'black', 'white') draw.rectangle([(0, 0), (128, 10)], 'white') draw.text((2, 0), str(currentDist[0][0]), fill='black', font=self.font) draw.text((105, 0), readCapacity(), fill='black', font=self.smallFont) for i in range(1, len(currentDist)): draw.text((10, i * 10), str(currentDist[i][0]), fill='white', font=self.font) draw.text((2, cur * 10), ">", fill='white', font=self.font) # Action Events (RIGHT) if action == 1: if type(currentDist[cur][1]) is str: self.pageQue.append(["Action Page Route", -1]) self.actionRouter(currentDist[cur][1]) else: self.pageQue.append(currentDist[cur][1]) self.renderPage(0, 1) return # Previous Page (Left) if action == -1: if len(self.pageQue) > 1: self.pageQue = self.pageQue[:-1] self.renderPage(0, 1) return displayImage(image) def actionRouter(self, event): # =============Projects Actions =========== if event == "act_Backup_Project_From_OP_1": if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": displayPng(workDir + "/Assets/Img/BackupProject.png") time.sleep(0.1) try: tape = TapeBackup() tape.copyToLocal() displayPng(workDir + "/Assets/Img/Done.png") time.sleep(0.1) getAnyKeyEvent() except: print("File Transfer Error") self.renderErrorMessagePage("File Transfer Error") self.renderPage(-1, 1) if event == "act_Load_Project_From_Local": # rtn = "RETURN" while True: temp = RenderOptionsMenu( getDirFileList(savePaths["Local_Projects"]), "Projects") if temp == "RETURN": break else: # while rtn == "RETURN": rtn = RenderOptionsMenu(["Upload", "Rename", "Delete"]) # temp = RenderOptionsMenu(getDirFileList(savePaths["Local_Projects"]), "Projects") if rtn == "Upload": pass elif rtn == "Rename": renderRename( os.path.join(savePaths["Local_Projects"], temp)) elif rtn == "Delete": deleteHelper( [os.path.join(savePaths["Local_Projects"], temp)]) elif rtn == "RETURN": pass self.renderPage(-1, 1) # ===========Patches Actions=========== if event == "OP1_Synth_Patches": if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": renderFolders(config["OP_1_Mounted_Dir"] + "/synth", "Backup", savePaths["Local_Synth"]) self.renderPage(-1, 1) if event == "OP1_Drum_Patches": if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": renderFolders(config["OP_1_Mounted_Dir"] + "/drum", "Backup", savePaths["Local_Drum"]) self.renderPage(-1, 1) if event == "UploadSynthPatches": renderFolders(savePaths["Local_Synth"], "Upload", config["OP_1_Mounted_Dir"] + "/synth") self.renderPage(-1, 1) if event == "UploadDrumPatches": renderFolders(savePaths["Local_Drum"], "Upload", config["OP_1_Mounted_Dir"] + "/drum") self.renderPage(-1, 1) if event == "act_5_Backup_All_Patches": image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/BackupProject.png").convert("1")) displayImage(image) time.sleep(0.1) self.renderPage(-1, 1) if event == "USB_MIDI_In_Test": startMidi() self.renderPage(-1, 1) if event == "USB_MIDI_Out_Test": usbMIDIOut() self.renderPage(-1, 1) # ===========Eject Actions=========== if event == "act_ESC_Eject_OP_1": try: if unmount_OP_1(): print("Ejected") except: print("Error") self.renderPage(-1, 1) # ============= MOUNT OPTION ============== if event == "act_ESC_Mount_OP_1": try: if do_mount(): print("Mounted") except: print("Error") self.renderPage(-1, 1) # ========= POWER OFF ==================== if event == "act_POWER_OFF": image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/PowerOff.png").convert("1")) displayImage(image) time.sleep(1.0) call("sudo shutdown -h now", shell=True) if event == "checkStorage": if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/Storage_64.png").convert("1")) draw = ImageDraw.Draw(image) sampler, synth, drum = update_Current_Storage_Status() Disk = subprocess.check_output( "df -h | awk '$NF==\"/\"{printf \"%d/%dGB %s\", $3,$2,$5}'", shell=True) draw.text((50, 13), Disk, font=getFont(), fill="white") # Disk Storage Render draw.text((28, 48), str(config["Max_Synth_Sampler_patches"] - sampler), font=getFont(), fill="white") draw.text((70, 48), str(config["Max_Synth_Synthesis_patches"] - synth), font=getFont(), fill="white") draw.text((112, 48), str(config["Max_Drum_Patches"] - drum), font=getFont(), fill="white") displayImage(image) getAnyKeyEvent() # Press any key to proceed else: print("Not Connected") self.renderPage(-1, 1) # Useful in "Are you sure to delete.", "Are you sure to rename" def renderConfirmation(self, message=""): """ Renders The Message and ask for yes or no :return: Boolean """ pass def renderErrorMessagePage(self, errorMessage=""): """
def mountMidiDevice(self, assignIn=None, assignOut=None): if assignIn is not None or assignOut is not None: if assignIn is not None: self._setInPort(assignIn) print("Mounting Device--", " | Device Lst: ", self.usbIn.get_ports(), "| Mounting: ", assignIn) USB_In_Stream_Thread = threading.Thread( target=self.getSerialMIDIByteStream) USB_In_Stream_Thread.start() self.threads.append( ["MidiIn", self.currentInDevice, USB_In_Stream_Thread]) elif assignOut is not None: self._setOutPort(assignOut) print("Mounting Device--", " | Device Lst: ", self.usbOut.get_ports(), "| Mounting: ", assignOut) USB_Out_Stream_Thread = threading.Thread( target=self.getUSBMidi) USB_Out_Stream_Thread.start() self.threads.append( ["MidiOut", self.currentOutDevice, USB_Out_Stream_Thread]) return # Start Wait Device Connection Process else: In, Out = self._availInPortCheck(), self._availOutPortCheck() print(self.usbIn.get_ports()) print(self.usbOut.get_ports()) if In != None and Out != None: image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/Midi.png").convert("1")) draw = ImageDraw.Draw(image) # Mount first USB Midi in device that's available if In: self._setInPort(In[0]) draw.text((20, 5), str( self._strip_Midi_Name(self.currentInDevice, maxLen=16)), fill='white', font=getFont()) # In Device Mounted---start Midi thread USB_In_Stream_Thread = threading.Thread( name=self.currentInDevice, target=self.getSerialMIDIByteStream) USB_In_Stream_Thread.start() self.threads.append( ["MidiIn", self.currentInDevice, USB_In_Stream_Thread]) else: draw.text((20, 5), str(self.currentInDevice), fill='white', font=getFont()) # Mount first Midi out device that's available if Out: self._setOutPort(Out[0]) draw.text((20, 50), str( self._strip_Midi_Name(self.currentOutDevice, maxLen=16)), fill='white', font=getFont()) # Out Device Mounted---start Midi thread USB_Out_Stream_Thread = threading.Thread( name=self.currentOutDevice, target=self.getUSBMidi) USB_Out_Stream_Thread.start() self.threads.append([ "MidiOut", self.currentOutDevice, USB_Out_Stream_Thread ]) else: draw.text((20, 50), str(self.currentInDevice), fill='white', font=getFont()) print(self.threads) displayImage(image)
def renderRename(file="", jsutName=False): """ Given a file path, renders for rename, with confirmation for rename or cancel, :param file: :return: """ dirPath, originalName = os.path.dirname(file), basename(file) newName = list("__________") ascii_uppercase, digits, space = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "0123456789", "_" curser, charPointer = 15, 0 while True: image = Image.new('1', (128, 64)) draw = ImageDraw.Draw(image) draw.rectangle([(-1, 0), (128, 64)], 'black', 'white') draw.rectangle([(0, 0), (128, 10)], 'white') if not os.path.exists(file): # The given path does not exist, means its creating a new folder draw.text((2, 0), str("New Folder"), fill='black', font=getFont()) elif os.path.isdir(file): draw.text((2, 0), str("Rename Folder"), fill='black', font=getFont()) draw.text((1, 15), str(originalName.split(".")[0]), font=getFont(), fill="white") else: draw.text((2, 0), str("Rename Patch"), fill='black', font=getFont()) draw.text((1, 15), str(originalName.split(".")[0]), font=getFont(), fill="white") # Render Rename Edit Space offset, spacing = 15, 10 for i in newName: draw.text((offset, 35), str(i), font=getFont(), fill="white") offset += spacing # Render cursor draw.text((curser, 45), str("^"), font=getFont(), fill="white") displayImage(image) key = getKeyStroke() if key == "LEFT": if curser - spacing >= 15: curser -= spacing charPointer -= 1 if key == "RIGHT": if curser + spacing < 115: curser += spacing charPointer += 1 if key == "UP": if newName[charPointer] == "_": newName[charPointer] = ascii_uppercase[0] elif newName[charPointer] in ascii_uppercase: current = ascii_uppercase.index(str(newName[charPointer])) if current - 1 >= 0: newName[charPointer] = ascii_uppercase[current - 1] elif newName[charPointer] in digits: current = digits.index(str(newName[charPointer])) if current - 1 >= 0: newName[charPointer] = digits[current - 1] if key == "DOWN": if newName[charPointer] == "_": newName[charPointer] = ascii_uppercase[0] elif newName[charPointer] in ascii_uppercase: current = ascii_uppercase.index(str(newName[charPointer])) if current + 1 < len(ascii_uppercase): newName[charPointer] = ascii_uppercase[current + 1] elif newName[charPointer] in digits: current = digits.index(str(newName[charPointer])) if current + 1 < len(digits): newName[charPointer] = digits[current + 1] if key == "CENTER": if newName[charPointer] == "_": newName[charPointer] = ascii_uppercase[0] elif newName[charPointer] in digits: newName[charPointer] = space elif newName[charPointer] in ascii_uppercase: newName[charPointer] = digits[0] if key == "A": return "" if key == "B": if jsutName: name = ''.join(newName).replace("_", " ").strip() if len(name) != 0: rtn = RenderOptionsMenu(["Yes", "Cancel"], "Confirm") if rtn == "Yes": return name else: return "" dirlst = os.listdir(dirPath) name = ''.join(newName).replace("_", " ").strip() if newName in dirlst: alreadyExist = Image.new('1', (128, 64)) draw = ImageDraw.Draw(alreadyExist) draw.text((30, 25), "Name Already Exist!", font=getFont(), fill='white') displayImage(alreadyExist) pass if newName not in dirlst and len(name) != 0: rtn = RenderOptionsMenu(["Yes", "Cancel"], "Confirm") if rtn == "Yes": # print(dirPath + "/" + originalName, dirPath + "/" + name + ".aif") if not os.path.isdir(file): os.rename(dirPath + "/" + originalName, dirPath + "/" + name + ".aif") else: os.rename(dirPath + "/" + originalName, dirPath + "/" + name) image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/Done.png").convert("1")) displayImage(image) getAnyKeyEvent() return elif rtn == "Cancel": pass
def actionRouter(self, event): # =============Projects Actions =========== if event == "act_Backup_Project_From_OP_1": if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": displayPng(workDir + "/Assets/Img/BackupProject.png") time.sleep(0.1) try: tape = TapeBackup() tape.copyToLocal() displayPng(workDir + "/Assets/Img/Done.png") time.sleep(0.1) getAnyKeyEvent() except: print("File Transfer Error") self.renderErrorMessagePage("File Transfer Error") self.renderPage(-1, 1) if event == "act_Load_Project_From_Local": # rtn = "RETURN" while True: temp = RenderOptionsMenu( getDirFileList(savePaths["Local_Projects"]), "Projects") if temp == "RETURN": break else: # while rtn == "RETURN": rtn = RenderOptionsMenu(["Upload", "Rename", "Delete"]) # temp = RenderOptionsMenu(getDirFileList(savePaths["Local_Projects"]), "Projects") if rtn == "Upload": pass elif rtn == "Rename": renderRename( os.path.join(savePaths["Local_Projects"], temp)) elif rtn == "Delete": deleteHelper( [os.path.join(savePaths["Local_Projects"], temp)]) elif rtn == "RETURN": pass self.renderPage(-1, 1) # ===========Patches Actions=========== if event == "OP1_Synth_Patches": if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": renderFolders(config["OP_1_Mounted_Dir"] + "/synth", "Backup", savePaths["Local_Synth"]) self.renderPage(-1, 1) if event == "OP1_Drum_Patches": if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": renderFolders(config["OP_1_Mounted_Dir"] + "/drum", "Backup", savePaths["Local_Drum"]) self.renderPage(-1, 1) if event == "UploadSynthPatches": renderFolders(savePaths["Local_Synth"], "Upload", config["OP_1_Mounted_Dir"] + "/synth") self.renderPage(-1, 1) if event == "UploadDrumPatches": renderFolders(savePaths["Local_Drum"], "Upload", config["OP_1_Mounted_Dir"] + "/drum") self.renderPage(-1, 1) if event == "act_5_Backup_All_Patches": image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/BackupProject.png").convert("1")) displayImage(image) time.sleep(0.1) self.renderPage(-1, 1) if event == "USB_MIDI_In_Test": startMidi() self.renderPage(-1, 1) if event == "USB_MIDI_Out_Test": usbMIDIOut() self.renderPage(-1, 1) # ===========Eject Actions=========== if event == "act_ESC_Eject_OP_1": try: if unmount_OP_1(): print("Ejected") except: print("Error") self.renderPage(-1, 1) # ============= MOUNT OPTION ============== if event == "act_ESC_Mount_OP_1": try: if do_mount(): print("Mounted") except: print("Error") self.renderPage(-1, 1) # ========= POWER OFF ==================== if event == "act_POWER_OFF": image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/PowerOff.png").convert("1")) displayImage(image) time.sleep(1.0) call("sudo shutdown -h now", shell=True) if event == "checkStorage": if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/Storage_64.png").convert("1")) draw = ImageDraw.Draw(image) sampler, synth, drum = update_Current_Storage_Status() Disk = subprocess.check_output( "df -h | awk '$NF==\"/\"{printf \"%d/%dGB %s\", $3,$2,$5}'", shell=True) draw.text((50, 13), Disk, font=getFont(), fill="white") # Disk Storage Render draw.text((28, 48), str(config["Max_Synth_Sampler_patches"] - sampler), font=getFont(), fill="white") draw.text((70, 48), str(config["Max_Synth_Synthesis_patches"] - synth), font=getFont(), fill="white") draw.text((112, 48), str(config["Max_Drum_Patches"] - drum), font=getFont(), fill="white") displayImage(image) getAnyKeyEvent() # Press any key to proceed else: print("Not Connected") self.renderPage(-1, 1)
def renderOPZFolder(path, upload_download): """ Slight modification to the renderOP1Folder since it is in different folder layout :param path: Path the OPZ mounted dir :param upload_download: String: Selection menu type :return: """ actualFilePointer = 1 currentCursor = 1 shortArray = [] interFolder = ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10"] fb = fileBrowserDT(path) # RenderFolders while True: image = Image.new('1', (128, 64)) draw = ImageDraw.Draw(image) # draw.rectangle([(-1, 0), (128, 64)], 'black', 'white') draw.rectangle([(0, 0), (128, 10)], 'white') draw.text((2, -1), os.path.basename(fb.structCurrentPath()[:-1]), fill='black', font=getFont()) shortArray = shiftArray(fb.getDirList(), shortArray, 0) # Render Sub-folder files if interFolder == fb.getDirList(): counter = 1 for i in shortArray: subFolderFileName = listdir(fb.currentDirPath + "/" + str(fb.histQueue[-1]) + "/" + str(i)) if len(subFolderFileName) == 0: subFolderFileName = "---Empty---" else: subFolderFileName = subFolderFileName[0] subFolderFileName = subFolderFileName.replace('.aif', '') subFolderFileName = subFolderFileName.replace( '.engine', ' [Engine]') subFolderFileName = subFolderFileName.replace('~', '') draw.text((10, counter * 10), str(i) + " - " + str(subFolderFileName), fill='white', font=getFont()) # Render next item from current Directory counter += 1 else: counter = 1 for i in shortArray: i = i.replace("-", " - ") draw.text((10, counter * 10), str(i), fill='white', font=getFont()) # Render next item from current Directory counter += 1 # Render cursor draw.text((0, currentCursor * 10), ">", fill='white', font=getFont()) # Render Scroll Bar scrollBarXLocation = 127 # List Shorter than screen size, fill the whole scroll bar if len(fb.getDirList()) <= 5: draw.line((scrollBarXLocation, 10, scrollBarXLocation, 64), fill="white", width=1) else: scrollBarLength = int(getScrollBarSize(fb.getDirList())) offset = getOffset(fb.getDirList(), actualFilePointer - 1, scrollBarLength) draw.line((scrollBarXLocation, 10 + offset, scrollBarXLocation, 10 + scrollBarLength + offset), fill="white", width=1) # Update Image to the display displayImage(image) key = getKeyStroke() if key == "UP": if currentCursor - 1 < 1: temp = shortArray shortArray = shiftArray(fb.getDirList(), shortArray, -1) if temp != shortArray: actualFilePointer -= 1 else: currentCursor -= 1 actualFilePointer -= 1 if key == "DOWN": if currentCursor + 1 > len(shortArray): temp = shortArray shortArray = shiftArray(fb.getDirList(), shortArray, 1) if temp != shortArray: actualFilePointer += 1 else: currentCursor += 1 actualFilePointer += 1 if key == "LEFT": if len(fb.histQueue) > 1: currentCursor = actualFilePointer = 1 fb.clearCopyQueue() fb.prevPage() else: return if key == "RIGHT": if interFolder != fb.getDirList(): fb.selectNewPath(fb.getDirList()[actualFilePointer - 1]) currentCursor = 1 actualFilePointer = 1 if key == "CENTER": pass if key == "A": pass # return if key == "B": currentFile = fb.getDirList()[actualFilePointer - 1] rtn = RenderOptionsMenu([upload_download, "Delete"], sort=False) if "Choose From OP-1 Lib" in rtn: if check_OP_Z_Connection( ) and config["OP_Z_Mounted_Dir"] != "": try: # Single file path selected from the OP-1 patch lib # Start a new file browser / selecter singleFile = renderFolders( savePaths["Local_Patches"], "Upload to OPZ", savePaths["OP_Z_System_Path"], singleFileSelection=True) # User selected a dir but not a file. if os.path.isdir(singleFile): errorMessage = Image.new('1', (128, 64)) draw = ImageDraw.Draw(errorMessage) draw.text((0, 25), "Folder is not allowed!", font=getFont(), fill='white') displayImage(errorMessage) time.sleep(1) # Ensure the selected file is supported on OP-Z system type, fx, lfo = analyzeAIF(singleFile) # Correct File. Execute file transfer if type == "Drum" or type == "Sampler": destPath = join(path, fb.histQueue[-1]) # Clear Dir on OPZ clearUnderFolder( join(destPath, fb.getDirList()[actualFilePointer - 1])) target = join( destPath, join(fb.getDirList()[actualFilePointer - 1], basename(singleFile))) print("Transfer Single Patch to OPZ", singleFile, target) try: shutil.copy2(singleFile, target) except: pass print("Done") # File not supported on OP-Z else: errorMessage = Image.new('1', (128, 64)) draw = ImageDraw.Draw(errorMessage) draw.text((0, 15), "File not supported", font=getFont(), fill='white') draw.text((0, 25), "on OP-Z", font=getFont(), fill='white') displayImage(errorMessage) time.sleep(1) except: pass elif "Delete" in rtn: if check_OP_Z_Connection( ) and config["OP_Z_Mounted_Dir"] != "": try: destPath = join(path, fb.histQueue[-1]) target = join( destPath, join(fb.getDirList()[actualFilePointer - 1])) print("Deleting file under...", target) # Clear Dir on OPZ clearUnderFolder(target) print("Deleted") except: pass fb.updatePage()
def renderFolders(path, upload_download, dest, singleFileSelection=False, localMode=False): actualFilePointer = 1 currentCursor = 1 shortArray = [] selectedDisplay = [] fb = fileBrowserDT(path) # RenderFolders while True: # sampler, synth, drum = update_Current_Storage_Status() if check_OP_1_Connection_Silent(): sampler, synth, drum = update_Current_Storage_Status() if "synth" in fb.structCurrentPath( ) or "Synth" in fb.structCurrentPath(): # Display synth and Sample Available availableSlots = config["Max_Synth_Synthesis_patches"] + config[ "Max_Synth_Sampler_patches"] - (synth + sampler) else: availableSlots = config["Max_Drum_Patches"] - drum else: availableSlots = 0 image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/FileBrowser.png").convert("1")) draw = ImageDraw.Draw(image) draw.text((2, -1), os.path.basename(fb.structCurrentPath()[:-1]), fill='black', font=getFont()) if config["OP_1_Mounted_Dir"] != "": if "synth" in fb.structCurrentPath().lower(): # Display synth and Sample Available draw.text((108, -2), str(availableSlots - len(fb.getCopyQueue())), fill='white', font=getFont()) else: # Display available drums draw.text((108, -2), str(availableSlots - len(fb.getCopyQueue())), fill='white', font=getFont()) else: draw.text((108, -2), "--", fill='white', font=getFont()) shortArray = shiftArray(fb.getDirList(), shortArray, 0) # Empty Folder if not shortArray: draw.text((5, 10), "[----Empty----]", fill='white', font=getFont()) displayImage(image) counter = 1 for i in shortArray: # Check if current item is selected selected = True if i in selectedDisplay else False # Render the AIF data from cursor landed item if "aif" in i and counter == currentCursor: try: synType, FX, LFO = analyzeAIF( os.path.join(fb.structCurrentPath(), i)) except: # AIF meta data not retrievable synType, FX, LFO = "N/A", "N/A", "N/A" pass # Render Patch Type draw.text((90, 17), str(get_abbreviation(synType)), fill='white', font=getSmallFont()) draw.text((90, 35), str(get_abbreviation(FX)), fill='white', font=getSmallFont()) draw.text((90, 54), str(get_abbreviation(LFO)), fill='white', font=getSmallFont()) # Remove extension for display and dash out long file names i = i.replace(".aif", "") if len(i) > 10: i = i[:10] + ".." # Iterate through selected queue and invert the color if selected: draw.rectangle(((9, counter * 10), (83, counter * 10 + 10)), 'white') draw.text((10, counter * 10), str(i), fill='black', font=getFont()) else: draw.text((10, counter * 10), str(i), fill='white', font=getFont()) # Render next item from current Directory counter += 1 # Render cursor if shortArray: draw.text((0, currentCursor * 10), ">", fill='white', font=getFont()) # Render Scroll Bar scrollBarXLocation = 86 # List Shorter than screen size, fill the whole scroll bar if len(fb.getDirList()) <= 5: draw.line((scrollBarXLocation, 10, scrollBarXLocation, 64), fill="white", width=1) else: scrollBarLength = int(getScrollBarSize(fb.getDirList())) offset = getOffset(fb.getDirList(), actualFilePointer - 1, scrollBarLength) draw.line((scrollBarXLocation, 10 + offset, scrollBarXLocation, 10 + scrollBarLength + offset), fill="white", width=1) # Update Image to the display displayImage(image) key = getKeyStroke() if key == "UP": if currentCursor - 1 < 1: temp = shortArray shortArray = shiftArray(fb.getDirList(), shortArray, -1) if temp != shortArray: actualFilePointer -= 1 else: currentCursor -= 1 actualFilePointer -= 1 if key == "DOWN": if currentCursor + 1 > len(shortArray): temp = shortArray shortArray = shiftArray(fb.getDirList(), shortArray, 1) if temp != shortArray: actualFilePointer += 1 else: currentCursor += 1 actualFilePointer += 1 if key == "LEFT": if len(fb.histQueue) > 1: currentCursor = actualFilePointer = 1 availableSlots += len(fb.getCopyQueue()) selectedDisplay = [] fb.clearCopyQueue() fb.prevPage() else: return if key == "RIGHT": if len(fb.getDirList()): if len(fb.getCopyQueue()) == 0 and "aif" not in fb.getDirList( )[actualFilePointer - 1]: fb.selectNewPath(fb.getDirList()[actualFilePointer - 1]) currentCursor = 1 actualFilePointer = 1 if key == "CENTER": # Start Multi-select. (Select and deselect, and add the selected ones to copy queue) if not singleFileSelection: currentFile = [] selectedFolderPath = "" if len(fb.getDirList()): currentFile = fb.getDirList()[actualFilePointer - 1] selectedFolderPath = fb.structCurrentPath() + currentFile # Add to copy if currentFile not in selectedDisplay: # Decrement Available Patches if os.path.isdir(selectedFolderPath): if availableSlots - len( listdir(selectedFolderPath)) >= 0 or config[ "OP_1_Mounted_Dir"] == "": selectedDisplay.append(currentFile) for i in listdir(selectedFolderPath): fb.addToCopyQueue(currentFile + "/" + i) if "media" not in fb.structCurrentPath(): availableSlots -= 1 else: print("Over Shoot") else: if availableSlots - 1 >= 0 or config[ "OP_1_Mounted_Dir"] == "": fb.addToCopyQueue(currentFile) selectedDisplay.append(currentFile) if "media" not in fb.structCurrentPath(): availableSlots -= 1 else: print("Over Shoot") else: # Remove form copy if os.path.isdir(selectedFolderPath): selectedDisplay.remove(currentFile) for i in listdir(selectedFolderPath): fb.removeFromCopyQueue(currentFile + "/" + i) if "media" not in fb.structCurrentPath(): availableSlots += 1 else: fb.removeFromCopyQueue(currentFile) selectedDisplay.remove(currentFile) if "media" not in fb.structCurrentPath(): availableSlots += 1 if key == "A": print("") # return if key == "B": if not singleFileSelection: if len(fb.getDirList()): currentFile = fb.getDirList()[actualFilePointer - 1] selectedFolderPath = fb.structCurrentPath() + currentFile fileCount = len(fb.getCopyQueue()) if len(selectedDisplay) == 0 and len(fb.getCopyQueue()) == 0: rtn = RenderOptionsMenu(["New Folder"], sort=False) if "New Folder" in rtn: name = renderRename("/New Folder", jsutName=True) if name != "": print(join(fb.currentDirPath, name), "Folder Created") try: createEmptyFolder(fb.currentDirPath, name) fb.updatePage() except OSError: print("Folder can not be created") print("Folder Created") else: print("Create Folder Canceled") # if len(fb.getCopyQueue()) == 0 or len(selectedDisplay) == 1: # # Takes case if non of the folder or file is selected # if os.path.isdir(selectedFolderPath): # for i in listdir(selectedFolderPath): # fb.addToCopyQueue(currentFile + "/" + i) # fileCount = len(fb.getCopyQueue()) # # availableSlots += len(fb.getCopyQueue()) # rtn = RenderOptionsMenu( # [upload_download + " " + str(fileCount) + " Patches", # "Delete " + str(fileCount) + "Patches", "New Folder"], sort=False) # else: # fb.addToCopyQueue(currentFile) # # availableSlots += 1 # rtn = RenderOptionsMenu([upload_download, "Rename", "Delete"], sort=False) else: if fileCount == 1: rtn = RenderOptionsMenu( [upload_download, "Rename", "Move", "Delete"], sort=False) else: rtn = RenderOptionsMenu([ upload_download + " " + str(fileCount) + " Patches", "Move " + str(fileCount) + " Patches", "Delete " + str(fileCount) + "Patches" ], sort=False) # if rtn == "RETURN": # availableSlots += fileCount else: currentFile = fb.getDirList()[actualFilePointer - 1] selectedFolderPath = fb.structCurrentPath() + currentFile if os.path.isdir(selectedFolderPath): return selectedFolderPath pass else: rtn = RenderOptionsMenu(["Copy / Overwrite", "Cancel"], title="Upload to OP-Z", sort=False) if "Copy / Overwrite" in rtn: currentFile = fb.getDirList()[actualFilePointer - 1] selectedFolderPath = fb.structCurrentPath() + currentFile return selectedFolderPath if "Cancel" in rtn: print("Canceled") return # Main File Actions if "Upload" in rtn or "Backup" in rtn: # List allowed if check_OP_1_Connection( ) and config["OP_1_Mounted_Dir"] != "": try: copyQueue = fb.getCopyQueue() if dest == "": dest = config["OP_1_Mounted_Dir"] fileTransferHelper(copyQueue, dest) except: pass elif "Move" in rtn: # Move files within folder if fb.getCopyQueue(): temp = fb.getCopyQueue()[0] parentDir = dirname(dirname(temp)) parentDirLst = os.listdir(parentDir) rtn = RenderOptionsMenu(parentDirLst, title="Move To ...", sort=False) if "RETURN" not in rtn: try: moveFilesToFolder(fb.getCopyQueue(), os.path.join(parentDir, rtn)) fb.clearCopyQueue() selectedDisplay = [] fb.updatePage() except OSError: print("File Moving Error") elif "Delete" in rtn: # List allowed # if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": try: if len(fb.getCopyQueue()) == 0: # Empty Folder Selected currentFolder = fb.getDirList()[actualFilePointer - 1] print(join(fb.structCurrentPath(), currentFolder)) shutil.rmtree( join(fb.structCurrentPath(), currentFolder)) else: # Deleting folder that have patches print("In!!") deleteHelper(fb.getCopyQueue()) # Current Folder is empty and no longer existed go to Prev Page if not os.path.exists(fb.structCurrentPath()): fb.prevPage() selectedDisplay = [] selected = [] fb.clearCopyQueue() # Finished deleting, refresh the file list for display fb.updatePage() except OSError: pass elif "Rename" in rtn: # Only one item is allowed # Rename Page print(fb.getCopyQueue()[0]) renderRename(str(fb.getCopyQueue()[0])) fb.updatePage() # currentCursor = 1 # actualFilePointer = 1 # fb.clearCopyQueue() # selectedDisplay = [] # Update Remain Available Patches Here sampler, synth, drum = update_Current_Storage_Status()
def renderFolders(path, upload_download): actualFilePointer = 1 currentCursor = 1 shortArray = [] selectedDisplay = [] fb = fileBrowser(path) sampler = currentStorageStatus["sampler"] synth = currentStorageStatus["synth"] drum = currentStorageStatus["drum"] drum, synth, sampler = 42, 100, 42 if "synth" in fb.structCurrentPath() or "Synth" in fb.structCurrentPath(): # Display synth and Sample Available availableSlots = synth + sampler else: availableSlots = drum # RenderFolders while True: image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/FileBrowser.png").convert("1")) draw = ImageDraw.Draw(image) draw.text((2, -1), os.path.basename(fb.structCurrentPath()[:-1]), fill='black', font=getFont()) if "synth" in fb.structCurrentPath( ) or "Synth" in fb.structCurrentPath(): # Display synth and Sample Available draw.text((108, -2), str(availableSlots), fill='white', font=getFont()) else: # Display available drums draw.text((108, -2), str(availableSlots), fill='white', font=getFont()) shortArray = shiftArray(fb.getDirList(), shortArray, 0) clearDisplay() # Empty Folder if not shortArray: draw.text((30, 40), "[Empty]", fill='white', font=getFont()) displayImage(image) time.sleep(2) return counter = 1 for i in shortArray: # Check if current item is selected selected = True if i in selectedDisplay else False # Render the AIF data from cursor landed item if "aif" in i and counter == currentCursor: try: synType, FX, LFO = analyzeAIF(fb.structCurrentPath() + "/" + i) except: # AIF meta data not retrievable synType, FX, LFO = "N/A", "N/A", "N/A" pass # Render Patch Type draw.text((90, 16), str(synType), fill='white', font=getFont()) draw.text((90, 35), str(FX), fill='white', font=getFont()) draw.text((90, 53), str(LFO), fill='white', font=getFont()) # Remove extension for display and dash out long file names i = i.replace(".aif", "") if len(i) > 10: i = i[:10] + ".." # Iterate through selected queue and invert the color if selected: draw.rectangle(((9, counter * 10), (84, counter * 10 + 10)), 'white') draw.text((10, counter * 10), str(i), fill='black', font=getFont()) else: draw.text((10, counter * 10), str(i), fill='white', font=getFont()) # Render next item from current Directory counter += 1 # Render cursor draw.text((0, currentCursor * 10), ">", fill='white', font=getFont()) # Render Scroll Bar scrollBarXLocation = 86 # List Shorter than screen size, fill the whole scroll bar if len(fb.getDirList()) <= 5: draw.line((scrollBarXLocation, 10, scrollBarXLocation, 64), fill="white", width=1) else: scrollBarLength = int(getScrollBarSize(fb.getDirList())) offset = getOffset(fb.getDirList(), actualFilePointer - 1, scrollBarLength) draw.line((scrollBarXLocation, 10 + offset, scrollBarXLocation, 10 + scrollBarLength + offset), fill="white", width=1) # Update Image to the display displayImage(image) key = getKeyStroke() if key == "UP": if currentCursor - 1 < 1: temp = shortArray shortArray = shiftArray(fb.getDirList(), shortArray, -1) if temp != shortArray: actualFilePointer -= 1 else: currentCursor -= 1 actualFilePointer -= 1 if key == "DOWN": if currentCursor + 1 > len(shortArray): temp = shortArray shortArray = shiftArray(fb.getDirList(), shortArray, 1) if temp != shortArray: actualFilePointer += 1 else: currentCursor += 1 actualFilePointer += 1 if key == "LEFT": if len(fb.histQueue) == 1: # No more Page to return to, exit the page return else: currentCursor = 1 actualFilePointer = 1 availableSlots += len(fb.getCopyQueue()) fb.clearCopyQueue() fb.prevPage() if key == "RIGHT": if len(fb.getCopyQueue()) == 0 and "aif" not in fb.getDirList()[ actualFilePointer - 1]: fb.selectNewPath(fb.getDirList()[actualFilePointer - 1]) currentCursor = 1 actualFilePointer = 1 if key == "CENTER": # Start Multi-select. (Select and deselect, and add the selected ones to copy queue) currentFile = fb.getDirList()[actualFilePointer - 1] selectedFolderPath = fb.structCurrentPath() + currentFile # Add to copy if currentFile not in selectedDisplay: # Decrement Available Patches if os.path.isdir(selectedFolderPath): selectedDisplay.append(currentFile) for i in getDirFileList(selectedFolderPath): fb.addToCopyQueue(i) availableSlots -= 1 else: fb.addToCopyQueue(currentFile) selectedDisplay.append(currentFile) availableSlots -= 1 else: # Remove form copy if os.path.isdir(selectedFolderPath): selectedDisplay.remove(currentFile) for i in getDirFileList(selectedFolderPath): fb.removeFromCopyQueue(i) availableSlots += 1 else: fb.removeFromCopyQueue(currentFile) selectedDisplay.remove(currentFile) availableSlots += 1 if key == "A": print("") # return if key == "B": ##This part need redo currentFile = fb.getDirList()[actualFilePointer - 1] selectedFolderPath = fb.structCurrentPath() + currentFile rtn = "" if len(fb.getCopyQueue()) == 0 or len(selectedDisplay) == 1: if os.path.isdir(selectedFolderPath): for i in getDirFileList(selectedFolderPath): fb.addToCopyQueue(i) fileCount = len(fb.getCopyQueue()) # availableSlots += len(fb.getCopyQueue()) rtn = RenderOptionsMenu([ upload_download + " " + str(fileCount) + " Patches", "Delete " + str(fileCount) + "Patches" ]) else: fb.addToCopyQueue(currentFile) # availableSlots += 1 rtn = RenderOptionsMenu( [upload_download, "Rename", "Delete"]) else: fileCount = len(fb.getCopyQueue()) rtn = RenderOptionsMenu([ upload_download + " " + str(fileCount) + " Patches", "Delete " + str(fileCount) + "Patches" ]) if rtn == "RETURN": availableSlots += fileCount if "Upload" in rtn: # List allowed print("Upload", fb.getCopyQueue()) pass elif "Delete" in rtn: # List allowed print("Delete", fb.getCopyQueue()) pass elif "Rename" in rtn: # Only one item is allowed print("Rename", fb.getCopyQueue()) pass # if rtn == "RETURN": currentCursor = 1 actualFilePointer = 1 fb.clearCopyQueue() selectedDisplay = []
def renderFolders(path, upload_download, dest): actualFilePointer = 1 currentCursor = 1 shortArray = [] selectedDisplay = [] fb = fileBrowser(path) # RenderFolders while True: sampler, synth, drum = update_Current_Storage_Status() if "synth" in fb.structCurrentPath( ) or "Synth" in fb.structCurrentPath(): # Display synth and Sample Available availableSlots = config["Max_Synth_Synthesis_patches"] + config[ "Max_Synth_Sampler_patches"] - (synth + sampler) else: availableSlots = config["Max_Drum_Patches"] - drum image = Image.new('1', (128, 64)) image.paste( Image.open(workDir + "/Assets/Img/FileBrowser.png").convert("1")) draw = ImageDraw.Draw(image) draw.text((2, -1), os.path.basename(fb.structCurrentPath()[:-1]), fill='black', font=getFont()) if "synth" in fb.structCurrentPath().lower(): # Display synth and Sample Available draw.text((108, -2), str(availableSlots), fill='white', font=getFont()) else: # Display available drums draw.text((108, -2), str(availableSlots), fill='white', font=getFont()) shortArray = shiftArray(fb.getDirList(), shortArray, 0) clearDisplay() # Empty Folder if not shortArray: draw.text((30, 40), "[Empty]", fill='white', font=getFont()) displayImage(image) time.sleep(2) return counter = 1 for i in shortArray: # Check if current item is selected selected = True if i in selectedDisplay else False # Render the AIF data from cursor landed item if "aif" in i and counter == currentCursor: try: synType, FX, LFO = analyzeAIF( os.path.join(fb.structCurrentPath(), i)) except: # AIF meta data not retrievable synType, FX, LFO = "N/A", "N/A", "N/A" pass # Render Patch Type draw.text((90, 17), str(get_abbreviation(synType)), fill='white', font=getSmallFont()) draw.text((90, 35), str(get_abbreviation(FX)), fill='white', font=getSmallFont()) draw.text((90, 54), str(get_abbreviation(LFO)), fill='white', font=getSmallFont()) # Remove extension for display and dash out long file names i = i.replace(".aif", "") if len(i) > 10: i = i[:10] + ".." # Iterate through selected queue and invert the color if selected: draw.rectangle(((9, counter * 10), (84, counter * 10 + 10)), 'white') draw.text((10, counter * 10), str(i), fill='black', font=getFont()) else: draw.text((10, counter * 10), str(i), fill='white', font=getFont()) # Render next item from current Directory counter += 1 # Render cursor draw.text((0, currentCursor * 10), ">", fill='white', font=getFont()) # Render Scroll Bar scrollBarXLocation = 86 # List Shorter than screen size, fill the whole scroll bar if len(fb.getDirList()) <= 5: draw.line((scrollBarXLocation, 10, scrollBarXLocation, 64), fill="white", width=1) else: scrollBarLength = int(getScrollBarSize(fb.getDirList())) offset = getOffset(fb.getDirList(), actualFilePointer - 1, scrollBarLength) draw.line((scrollBarXLocation, 10 + offset, scrollBarXLocation, 10 + scrollBarLength + offset), fill="white", width=1) # Update Image to the display displayImage(image) key = getKeyStroke() if key == "UP": if currentCursor - 1 < 1: temp = shortArray shortArray = shiftArray(fb.getDirList(), shortArray, -1) if temp != shortArray: actualFilePointer -= 1 else: currentCursor -= 1 actualFilePointer -= 1 if key == "DOWN": if currentCursor + 1 > len(shortArray): temp = shortArray shortArray = shiftArray(fb.getDirList(), shortArray, 1) if temp != shortArray: actualFilePointer += 1 else: currentCursor += 1 actualFilePointer += 1 if key == "LEFT": if len(fb.histQueue) > 1: currentCursor = actualFilePointer = 1 availableSlots += len(fb.getCopyQueue()) selectedDisplay = [] fb.clearCopyQueue() fb.prevPage() else: return if key == "RIGHT": if len(fb.getCopyQueue()) == 0 and "aif" not in fb.getDirList()[ actualFilePointer - 1]: fb.selectNewPath(fb.getDirList()[actualFilePointer - 1]) currentCursor = 1 actualFilePointer = 1 if key == "CENTER": # Start Multi-select. (Select and deselect, and add the selected ones to copy queue) currentFile = fb.getDirList()[actualFilePointer - 1] selectedFolderPath = fb.structCurrentPath() + currentFile # Add to copy if currentFile not in selectedDisplay: # Decrement Available Patches if os.path.isdir(selectedFolderPath): selectedDisplay.append(currentFile) for i in listdir(selectedFolderPath): fb.addToCopyQueue(currentFile + "/" + i) if "media" not in fb.structCurrentPath(): availableSlots -= 1 else: fb.addToCopyQueue(currentFile) selectedDisplay.append(currentFile) if "media" not in fb.structCurrentPath(): availableSlots -= 1 else: # Remove form copy if os.path.isdir(selectedFolderPath): selectedDisplay.remove(currentFile) for i in listdir(selectedFolderPath): fb.removeFromCopyQueue(currentFile + "/" + i) if "media" not in fb.structCurrentPath(): availableSlots += 1 else: fb.removeFromCopyQueue(currentFile) selectedDisplay.remove(currentFile) if "media" not in fb.structCurrentPath(): availableSlots += 1 if key == "A": print("") # return if key == "B": currentFile = fb.getDirList()[actualFilePointer - 1] selectedFolderPath = fb.structCurrentPath() + currentFile fileCount = len(fb.getCopyQueue()) if len(fb.getCopyQueue()) == 0 or len(selectedDisplay) == 1: # Takes case if non of the folder or file is selected if os.path.isdir(selectedFolderPath): for i in listdir(selectedFolderPath): fb.addToCopyQueue(currentFile + "/" + i) fileCount = len(fb.getCopyQueue()) # availableSlots += len(fb.getCopyQueue()) rtn = RenderOptionsMenu([ upload_download + " " + str(fileCount) + " Patches", "Delete " + str(fileCount) + "Patches" ]) else: fb.addToCopyQueue(currentFile) # availableSlots += 1 rtn = RenderOptionsMenu( [upload_download, "Rename", "Delete"]) else: if fileCount == 1: rtn = RenderOptionsMenu( [upload_download, "Rename", "Delete"]) else: rtn = RenderOptionsMenu([ upload_download + " " + str(fileCount) + " Patches", "Delete " + str(fileCount) + "Patches" ]) # if rtn == "RETURN": # availableSlots += fileCount if "Upload" in rtn or "Backup" in rtn: # List allowed if check_OP_1_Connection( ) and config["OP_1_Mounted_Dir"] != "": try: copyQueue = fb.getCopyQueue() if dest == "": dest = config["OP_1_Mounted_Dir"] fileTransferHelper(copyQueue, dest) except: pass elif "Delete" in rtn: # List allowed if check_OP_1_Connection( ) and config["OP_1_Mounted_Dir"] != "": try: deleteHelper(fb.getCopyQueue()) fb.updatePage() except: pass elif "Rename" in rtn: # Only one item is allowed # Rename Page print(fb.getCopyQueue()[0]) renderRename(str(fb.getCopyQueue()[0])) fb.updatePage() # currentCursor = 1 # actualFilePointer = 1 # fb.clearCopyQueue() # selectedDisplay = [] # Update Remain Available Patches Here sampler, synth, drum = update_Current_Storage_Status()
class PageRouter: pageQue = [MainPage] currentDist = [] cursorHistory = [] font = getFont() smallFont = getSmallFont() def __init__(self): self.processState = False self.cursor = 1 def getListSize(self): return len(self.pageQue[-1]) def renderPage(self, action, cur): frameSize = (128, 64) image = Image.new('1', frameSize) # Battery Icon draw = ImageDraw.Draw(image) currentDist = self.pageQue[-1] # Stay on same page (Up Down) Render Standard Menu if action == 0: draw.rectangle([(-1, 0), (128, 64)], 'black', 'white') draw.rectangle([(0, 0), (128, 10)], 'white') draw.text((2, 0), str(currentDist[0][0]), fill='black', font=self.font) if batteryConfig["enable"]: # Battery Level in percentage # draw.text((105, 0), readCapacity(), fill='black', font=self.smallFont) # Battery Level Icon icon = Image.open(os.path.join(workDir, getBatteryImagePath(readCapacity()))).convert("1") image.paste(icon, (117, 0)) for i in range(1, len(currentDist)): draw.text((10, i * 10), str(currentDist[i][0]), fill='white', font=self.font) draw.text((2, cur * 10), ">", fill='white', font=self.font) # Action Events (RIGHT) if action == 1: if type(currentDist[cur][1]) is str: self.pageQue.append(["Action Page Route", -1]) self.cursorHistory.append(cur) self.actionRouter(currentDist[cur][1]) else: self.pageQue.append(currentDist[cur][1]) self.cursorHistory.append(cur) self.renderPage(0, 1) return # Previous Page (Left) if action == -1: if len(self.pageQue) > 1: self.pageQue = self.pageQue[:-1] # Previous Cursor History Recall cur = self.cursorHistory[len(self.cursorHistory) - 1] self.cursorHistory = self.cursorHistory[:-1] return cur displayImage(image) def actionRouter(self, event): # =============Projects Actions =========== if event == "act_Backup_Project_From_OP_1": if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": displayPng(workDir + "/Assets/Img/BackupProject.png") time.sleep(0.1) try: tape = OP1Backup() tape.copyToLocal() displayPng(workDir + "/Assets/Img/Done.png") time.sleep(0.1) getAnyKeyEvent() except: print("File Transfer Error") # self.renderPage(-1, 1) if event == "act_Load_Project_From_Local_only_tracks": if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": displayPng(workDir + "/Assets/Img/BackupProject.png") time.sleep(0.1) try: tape = OP1Backup() tape.copyOnlyTapesToLocal() displayPng(workDir + "/Assets/Img/Done.png") time.sleep(0.1) getAnyKeyEvent() except: print("File Transfer Error") self.renderPage(-1, 1) if event == "act_Load_Project_From_Local": # rtn = "RETURN" while True: temp = RenderOptionsMenu(getDirFileList(savePaths["Local_Projects"]), "Projects") if temp == "RETURN": break else: rtn = RenderOptionsMenu(["Upload", "Rename", "Delete"]) if rtn == "Upload": if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": displayPng(workDir + "/Assets/Img/UploadingProject.png") time.sleep(0.1) try: tape = OP1Backup() tape.loadProjectToOP1(os.path.join(savePaths["Local_Projects"], temp)) except: print("File Transfer Error") elif rtn == "Rename": renderRename(os.path.join(savePaths["Local_Projects"], temp)) elif rtn == "Delete": deleteHelper([os.path.join(savePaths["Local_Projects"], temp)]) elif rtn == "RETURN": pass # ===========Patches Actions=========== if event == "OP1_Synth_Patches": if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": renderFolders(config["OP_1_Mounted_Dir"] + "/synth", "Backup", savePaths["Local_Synth"]) if event == "OP1_Drum_Patches": if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": renderFolders(config["OP_1_Mounted_Dir"] + "/drum", "Backup", savePaths["Local_Drum"]) if event == "UploadSynthPatches": renderFolders(savePaths["Local_Synth"], "Upload", config["OP_1_Mounted_Dir"] + "/synth") if event == "UploadDrumPatches": renderFolders(savePaths["Local_Drum"], "Upload", config["OP_1_Mounted_Dir"] + "/drum") if event == "act_5_Backup_All_Patches": if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": image = Image.new('1', (128, 64)) image.paste(Image.open(workDir + "/Assets/Img/DownloadPatches.png").convert("1")) displayImage(image) time.sleep(0.1) try: bk = OP1Backup() bk.backupOP1Patches() displayPng(workDir + "/Assets/Img/Done.png") time.sleep(0.1) getAnyKeyEvent() except: print("File Transfer Error") # =================== OP-Z Action Routes ==================== if event == "act_Freeze_State_OPZ": if check_OP_Z_Connection() and config["OP_Z_Mounted_Dir"] != "": displayPng(workDir + "/Assets/Img/BackupProject.png") time.sleep(0.1) try: state = OP1Backup() if state.backupOPZState(): displayPng(workDir + "/Assets/Img/Done.png") time.sleep(0.1) getAnyKeyEvent() except: print("File Transfer Error") # self.renderPage(-1, 1) if event == "act_Recall_State_To_OPZ": # rtn = "RETURN" while True: temp = RenderOptionsMenu(getDirFileList(savePaths["OP_Z_Local_Backup_States_Path"]), "Recall State") if temp == "RETURN": break else: rtn = RenderOptionsMenu(["Upload", "Rename", "Delete"]) if rtn == "Upload": if check_OP_Z_Connection(): displayPng(workDir + "/Assets/Img/UploadingProject.png") time.sleep(0.1) try: state = OP1Backup() print("Recall File: ", os.path.join(savePaths["OP_Z_Local_Backup_States_Path"], temp)) state.loadStateToOPZ(os.path.join(savePaths["OP_Z_Local_Backup_States_Path"], temp)) displayPng(workDir + "/Assets/Img/Done.png") time.sleep(0.1) getAnyKeyEvent() except: print("File Transfer Error") elif rtn == "Rename": renderRename(os.path.join(savePaths["OP_Z_Local_Backup_States_Path"], temp)) elif rtn == "Delete": deleteHelper([os.path.join(savePaths["OP_Z_Local_Backup_States_Path"], temp)]) elif rtn == "RETURN": pass # self.renderPage(-1, 1) if event == "OPZ_Patches": if check_OP_Z_Connection() and config["OP_Z_Mounted_Dir"] != "": renderOPZFolder(config["OP_Z_Mounted_Dir"] + "/samplepacks", "Choose From OP-1 Lib") if event == "MIDI_Host": midi = MidiTool() midi.usbMIDIOut() if event == "OP1FUN_BrowsePacks" or event == "OP1FUN_DownloadAllPacks": Connecting = Image.new('1', (128, 64)) draw = ImageDraw.Draw(Connecting) draw.text((0, 30), "Connecting to Wifi..", font=getFont(), fill='white') # draw.text((5, 35), "WIFI..", font=getFont(), fill='white') displayImage(Connecting) if not internetIsOn(): displayPng(workDir + "/Assets/Img/NoWifi.png") getAnyKeyEvent() noWifiMesg = Image.new('1', (128, 64)) draw = ImageDraw.Draw(noWifiMesg) draw.rectangle([(0, 0), (128, 10)], 'white') draw.text((30, 0), "No Internet", font=getFont(), fill='black') draw.text((5, 15), "Connect to Wifi AP", font=getFont(), fill='white') draw.text((5, 40), "Then assign", font=getFont(), fill='white') draw.text((5, 50), "Available Wifi", font=getFont(), fill='white') displayImage(noWifiMesg) getAnyKeyEvent() else: Connecting = Image.new('1', (128, 64)) draw = ImageDraw.Draw(Connecting) draw.text((0, 30), "Logging into op1.fun", font=getFont(), fill='white') displayImage(Connecting) op = op1funRequests() userAccount = op.getUserAccount() if "" in userAccount: Connecting = Image.new('1', (128, 64)) draw = ImageDraw.Draw(Connecting) draw.text((5, 30), "No Login Info!", font=getFont(), fill='white') displayImage(Connecting) else: packlst = op.getPackList() if event == "OP1FUN_DownloadAllPacks" and packlst: op1FunDownlaodQue(op, packlst, savePaths["Local_Patches"]) elif event == "OP1FUN_BrowsePacks" and packlst: rtn = "" while "RETURN" not in rtn: rtn = RenderOptionsMenu([i[0] for i in packlst], "User:"******"RETURN" not in rtn: actRtn = RenderOptionsMenu(["Download To Local", "Download To OP1"], "Pack: " + rtn) download = [] for i in packlst: name, link = i if name == rtn: download.append((name, link)) if "Download To Local" == actRtn: op1FunDownlaodQue(op, download, savePaths["Local_Patches"]) if "Download To OP1" == actRtn: if check_OP_1_Connection(): op1FunDownlaodQue(op, download, config["OP_1_Mounted_Dir"]) else: break # ===================== Server ================== if event == "Check_IP": import logging logging.basicConfig(level=logging.DEBUG, filename="/home/pi/OP1_File_Organizer/logfile.txt", filemode="a+", format="%(asctime)-15s %(levelname)-8s %(message)s") logging.info("In Check IP") username = "******" IP = "" try: # SSH = SSH_Service() # logging.info("After SSH initialized : ", SSH) # IP = SSH.get_ip_address() IP = get_ip_address() logging.info("Getting the IP Address: ", IP) username = os.getlogin() logging.info("Getting the User Name: ", username) # print(SSH.get_ip_address()) # print(SSH.get_current_connected()) # SSH.start_SSH_Service() IP = IP.replace(".", " . ") IPDisplay = Image.new('1', (128, 64)) draw = ImageDraw.Draw(IPDisplay) draw.rectangle([(0, 0), (128, 10)], 'white') draw.text((50, 0), "SSH IP", font=getFont(), fill='black') draw.text((5, 15), "User : "******"IP : " + IP, font=getFont(), fill='white') draw.text((5, 50), "Password : sys paswd", font=getFont(), fill='white') displayImage(IPDisplay) getAnyKeyEvent() except: IPDisplay = Image.new('1', (128, 64)) draw = ImageDraw.Draw(IPDisplay) draw.rectangle([(0, 0), (128, 10)], 'white') draw.text((50, 0), "SSH IP", font=getFont(), fill='black') draw.text((5, 15), "User : "******"IP : " + IP, font=getFont(), fill='white') draw.text((5, 50), "Password : sys paswd", font=getFont(), fill='white') displayImage(IPDisplay) getAnyKeyEvent() # Display = Image.new('1', (128, 64)) # draw = ImageDraw.Draw(Display) # draw.rectangle([(0, 0), (128, 10)], 'white') # draw.text((5, 25), "Wifi is not ready." + IP, font=getFont(), fill='white') # draw.text((5, 35), "Please try later....." + IP, font=getFont(), fill='white') # displayImage(Display) # getAnyKeyEvent() if event == "Server IP": try: SSH = SSH_Service() IP = SSH.get_ip_address() IPDisplay = Image.new('1', (128, 64)) draw = ImageDraw.Draw(IPDisplay) draw.rectangle([(0, 0), (128, 10)], 'white') draw.text((30, 0), "Browser App", font=getFont(), fill='black') draw.text((0, 15), "Connect To Wifi", font=getFont(), fill='white') draw.text((0, 25), "Open Browser, Then", font=getFont(), fill='white') draw.text((0, 35), "-------------------------------------------------------", font=getSmallFont(), fill='white') draw.text((0, 40), "http://" + IP + ":", font=getFont(), fill='white') draw.text((10, 53), "/5000/files", font=getFont(), fill='white') displayImage(IPDisplay) getAnyKeyEvent() except: pass # ===========Eject Actions=========== if event == "act_ESC_Eject": try: unmounting = Image.new('1', (128, 64)) draw = ImageDraw.Draw(unmounting) draw.text((0, 25), "Ejecting....", font=getFont(), fill='white') displayImage(unmounting) if unmount_OP_1(): time.sleep(1) # unmounted = Image.new('1', (128, 64)) # draw = ImageDraw.Draw(unmounted) # draw.text((0, 25), "Ejected", font=getFont(), fill='white') # displayImage(unmounted) # time.sleep(1) except: pass # ========= POWER OFF ==================== if event == "act_POWER_OFF": image = Image.new('1', (128, 64)) image.paste(Image.open(workDir + "/Assets/Img/PowerOff.png").convert("1")) displayImage(image) time.sleep(1.0) # call("sudo shutdown -h now", shell=True) call("sudo poweroff", shell=True) if event == "checkStorage": image = Image.new('1', (128, 64)) image.paste(Image.open(workDir + "/Assets/Img/Storage_64.png").convert("1")) draw = ImageDraw.Draw(image) if check_OP_1_Connection() and config["OP_1_Mounted_Dir"] != "": sampler, synth, drum = update_Current_Storage_Status() else: sampler, synth, drum = 42, 100, 42 Disk = str(subprocess.check_output("df -h | awk '$NF==\"/\"{printf \"%d/%dGB %s\", $3,$2,$5}'", shell=True)) Disk = Disk.replace("b\'", "") Disk = Disk.replace("\'", "") draw.text((50, 13), str(Disk), font=getFont(), fill="white") # Disk Storage Render draw.text((28, 48), str(config["Max_Synth_Sampler_patches"] - sampler), font=getFont(), fill="white") draw.text((70, 48), str(config["Max_Synth_Synthesis_patches"] - synth), font=getFont(), fill="white") draw.text((112, 48), str(config["Max_Drum_Patches"] - drum), font=getFont(), fill="white") displayImage(image) getAnyKeyEvent() # Press any key to proceed self.renderPage(-1, 1)