class Control(Frame): def __init__(self): # initialize RED and BLUE fighters self.RED = 0 self.BLUE = 1 # initialize score and kyonggo variables self.redPoints = 0 self.bluePoints = 0 self.redKyonggo = 0 self.blueKyonggo = 0 self.currentRound = 0 self.display = None self.miniDisplay = None self.numRounds = 0 self.timer = None self.isSuddenDeath = False self.callNextRound = True try: # for Python3 super().__init__() except: # for Python2 Frame.__init__(self) # set title and default style self.master.title("TKD Scoring System") # create style self.s = Style() self.s.configure("TButton", padding=10, font=(None, 20)) self.s.configure("TCheckbutton", padding=10, font=(None, 20)) self.s.configure("TOptionMenu", padding=10, font=(None, 20)) self.pack(fill=BOTH, expand=True) # create setup frames, labels, and entries # time entry frame self.setTimeFrame = Frame(self) self.timerLabel = Label(self.setTimeFrame, text="Time:", font=(None, 20)) self.secondsEntry = Entry(self.setTimeFrame, width=3, font=(None, 20)) self.colonLabel = Label(self.setTimeFrame, text=":", font=(None, 20)) self.minuteEntry = Entry(self.setTimeFrame, width=3, font=(None, 20)) # round entry frame self.roundsFrame = Frame(self) self.roundsLabel = Label(self.roundsFrame, text="Number of Rounds:", font=(None, 20)) self.roundsEntry = Entry(self.roundsFrame, width=3, font=(None, 20)) # serial entry frame self.serialFrame = Frame(self) try: self.arduino_ports = ["None"] + [ p.device for p in serial.tools.list_ports.comports() ] except: # if serial is not installed self.arduino_ports = ["None"] self.serialEntry = StringVar() self.serialEntry.set("None") self.serialLabel = Label(self.serialFrame, text="Serial Input:", font=(None, 20)) self.serialCheck = OptionMenu(self.serialFrame, self.serialEntry, "None", *self.arduino_ports) self.createMatchButton = Button(self, text="Create Match", style="TButton", command=self.hideSetup) # initialize frames for UI # red frame and buttons self.redFrame = Frame(self) self.redScoreButton = Button( self.redFrame, text="Red +", style="TButton", command=lambda: self.incrementPoints(self.RED)) self.redDeletePoint = Button( self.redFrame, text="Red -", style="TButton", command=lambda: self.deductPoints(self.RED)) self.redKyonggoButton = Button( self.redFrame, text="Kyonggo +", style="TButton", command=lambda: self.callKyonggo(self.RED)) self.redKyonggoDelete = Button( self.redFrame, text="Kyonggo -", style="TButton", command=lambda: self.deductKyonggo(self.RED)) # blue frame and buttons self.blueFrame = Frame(self) self.blueScoreButton = Button( self.blueFrame, text="Blue +", style="TButton", command=lambda: self.incrementPoints(self.BLUE)) self.blueDeletePoint = Button( self.blueFrame, text="Blue -", style="TButton", command=lambda: self.deductPoints(self.BLUE)) self.blueKyonggoButton = Button( self.blueFrame, text="Kyonggo +", style="TButton", command=lambda: self.callKyonggo(self.BLUE)) self.blueKyonggoDelete = Button( self.blueFrame, text="Kyonggo -", style="TButton", command=lambda: self.deductKyonggo(self.BLUE)) # reset and new match frame and buttons self.resetFrame = Frame(self) self.startStop = StringVar() self.timerStartStop = Button(self.resetFrame, textvariable=self.startStop, style="TButton", command=self.timerPush) self.startStop.set("Start Round 1") self.newMatch = Button(self.resetFrame, text="New Match", style="TButton", command=self.newMatch) self.resetMatch = Button(self.resetFrame, text="Reset Match", style="TButton", command=self.resetMatch) self.setup() # displays setup frames def setup(self): # timer frame self.setTimeFrame.pack(fill=X) # timer label and entry self.timerLabel.pack(side=LEFT, padx=5, pady=5) self.secondsEntry.pack(side=RIGHT) self.colonLabel.pack(side=RIGHT) self.minuteEntry.pack(side=RIGHT) # frame for number of rounds self.roundsFrame.pack(fill=X) # number of rounds label and entry self.roundsLabel.pack(side=LEFT, padx=5, pady=5) self.roundsEntry.pack(side=RIGHT) # frame for serial entry self.serialFrame.pack(fill=X, expand=True) # serial entry label and checkbox self.serialLabel.pack(side=LEFT, padx=5, pady=5) self.serialCheck.pack(side=RIGHT) # create match button self.createMatchButton.pack(side=BOTTOM) # hides setup widgets and initalizes timer and number of rounds def hideSetup(self): # check if minutes, seconds, and round entries are valid if len(self.minuteEntry.get()) < 1: minutes = 0 else: try: minutes = int(self.minuteEntry.get()) except: minutes = 0 if len(self.secondsEntry.get()) < 1: seconds = 0 else: try: seconds = int(self.secondsEntry.get()) % 60 minutes += int(self.secondsEntry.get()) // 60 except: seconds = 0 if len(self.roundsEntry.get()) < 1: numRounds = 0 else: try: numRounds = int(self.roundsEntry.get()) except: numRounds = 0 # set up serial input if checked if self.serialEntry.get() != "None": self.serialSetup() else: self.arduino = False # only moves on if entries are valid if ((minutes != 0) or (seconds != 0)) and (numRounds != 0): self.roundLength = [minutes, seconds] self.timer = Timer(self.roundLength) self.numRounds = numRounds self.currentRound = 1 self.isSuddenDeath = False self.roundsFrame.pack_forget() self.setTimeFrame.pack_forget() self.createMatchButton.pack_forget() self.serialFrame.pack_forget() self.initUI() # set up serial input def serialSetup(self): try: self.arduino = True self.serialPort = self.serialEntry.get() self.baudRate = 9600 self.ser = serial.Serial(self.serialPort, self.baudRate, timeout=0, writeTimeout=0) self.ser.flushInput() except: self.arduino = False print("Could Not Complete Serial Port Set Up") # creates user interface def initUI(self): # create display if self.display == None: self.display = Display(self.timer) self.display.attributes('-fullscreen', True) else: self.display.newTimer(self.timer) self.display.updateCurrentRound("R1") if self.miniDisplay == None: self.miniDisplay = miniDisplay(self.timer) else: self.miniDisplay.newTimer(self.timer) self.miniDisplay.updateCurrentRound("R1") # red point and kyonggo buttons self.redFrame.pack(fill=BOTH, side=LEFT) self.redScoreButton.pack(padx=5, pady=5, fill=X) self.redDeletePoint.pack(padx=5, pady=5, fill=X) self.redKyonggoButton.pack(padx=5, pady=5, fill=X) self.redKyonggoDelete.pack(padx=5, pady=5, fill=X) # blue point and kyonggo buttons self.blueFrame.pack(fill=BOTH, side=RIGHT) self.blueScoreButton.pack(padx=5, pady=5, fill=X) self.blueDeletePoint.pack(padx=5, pady=5, fill=X) self.blueKyonggoButton.pack(padx=5, pady=5, fill=X) self.blueKyonggoDelete.pack(padx=5, pady=5, fill=X) # timer start/stop button, reset button, and quit button self.resetFrame.pack(side=BOTTOM) self.startStop.set("Start Round " + str(self.currentRound)) self.timerStartStop.pack(side=TOP, pady=5) self.newMatch.pack(side=LEFT, padx=5) self.resetMatch.pack(side=RIGHT, padx=5) def timerPush(self): # if round is over, reset time give option to start next round if self.timer.timeLeft[0] == self.timer.timeLeft[1] == 0: self.timer.reset() self.startStop.set("Start Round " + str(self.currentRound)) self.display.updateCurrentRound("R" + str(self.currentRound)) self.miniDisplay.updateCurrentRound("R" + str(self.currentRound)) self.updateDisplayTimer() # pause timer, give option to unpause elif self.timer.isRunning(): self.timer.stop() self.startStop.set("Start") # unpause timer, give option to pause else: if self.arduino: self.ser.flushInput() self.timer.start() if self.arduino: self.readSerialInput() self.startStop.set("Pause") if not self.callNextRound: self.callNextRound = True self.updateDisplayTimer() def resetMatch(self): if not self.timer.isRunning(): self.timer.reset() self.redPoints = 0 self.bluePoints = 0 self.redKyonggo = 0 self.blueKyonggo = 0 self.currentRound = 1 if self.isSuddenDeath: self.isSuddenDeath = False self.newMatch.pack_forget() self.resetMatch.pack_forget() self.timerStartStop.pack(side=TOP, pady=5) self.newMatch.pack(side=LEFT, padx=5) self.resetMatch.pack(side=RIGHT, padx=5) self.startStop.set("Start Round 1") self.display.reset(self.timer.getTimeString()) self.miniDisplay.reset(self.timer.getTimeString()) def updateDisplayTimer(self): if self.timer.isElapsed(): self.timer.stop() if self.callNextRound: self.nextRound() if self.currentRound < self.numRounds or self.redPoints == self.bluePoints: self.display.updateTimer(self.timer.getTimeString()) self.miniDisplay.updateTimer(self.timer.getTimeString()) elif self.currentRound > self.numRounds: self.suddenDeath() else: self.display.updateTimer(self.timer.getTimeString()) self.miniDisplay.updateTimer(self.timer.getTimeString()) self.after(1000, self.updateDisplayTimer) def nextRound(self): self.callNextRound = False self.currentRound += 1 if self.currentRound <= self.numRounds: self.startStop.set("Reset Timer") elif self.redPoints == self.bluePoints: self.startStop.set("Sudden Death") else: self.declareWinner() self.timerStartStop.pack_forget() def declareWinner(self): if self.redPoints > self.bluePoints: winner = "RED" else: winner = "BLUE" self.display.updateTimer(winner + " WINS") self.display.updateCurrentRound("") def suddenDeath(self): self.redPoints = 0 self.display.updateRedPoints(0) self.miniDisplay.updateRedPoints(0) self.bluePoints = 0 self.display.updateBluePoints(0) self.miniDisplay.updateBluePoints(0) self.display.updateTimer("SUDDEN DEATH") self.miniDisplay.updateTimer("SUDDEN DEATH") self.display.updateCurrentRound("") self.miniDisplay.updateCurrentRound("") self.isSuddenDeath = True if self.arduino: self.readSerialInput() self.timerStartStop.pack_forget() def readSerialInput(self): if self.timer.isRunning() or self.isSuddenDeath: output = self.ser.readline() if len(output) != 0: try: fighter = int(output) self.incrementPoints(fighter) except: print("Invalid Serial Input") self.after(250, self.readSerialInput) else: self.after(50, self.readSerialInput) def incrementPoints(self, fighter): if fighter == self.RED: self.redPoints += 1 self.display.updateRedPoints(self.redPoints) self.miniDisplay.updateRedPoints(self.redPoints) elif fighter == self.BLUE: self.bluePoints += 1 self.display.updateBluePoints(self.bluePoints) self.miniDisplay.updateBluePoints(self.bluePoints) if self.isSuddenDeath: self.declareWinner() def deductPoints(self, fighter): if fighter == self.RED and self.redPoints > 0: self.redPoints -= 1 self.display.updateRedPoints(self.redPoints) self.miniDisplay.updateRedPoints(self.redPoints) elif fighter == self.BLUE and self.bluePoints > 0: self.bluePoints -= 1 self.display.updateBluePoints(self.bluePoints) self.miniDisplay.updateBluePoints(self.bluePoints) def callKyonggo(self, fighter): if fighter == self.RED: self.redKyonggo += 1 self.display.updateRedKyonggo("Kyonggo: " + str(self.redKyonggo)) self.miniDisplay.updateRedKyonggo("Kyonggo: " + str(self.redKyonggo)) if self.redKyonggo % 2 == 0: self.bluePoints += 1 self.display.updateBluePoints(self.bluePoints) self.miniDisplay.updateBluePoints(self.bluePoints) elif fighter == self.BLUE: self.blueKyonggo += 1 self.display.updateBlueKyonggo("Kyonggo: " + str(self.blueKyonggo)) self.miniDisplay.updateBlueKyonggo("Kyonggo: " + str(self.blueKyonggo)) if self.blueKyonggo % 2 == 0: self.redPoints -= 1 self.display.updateRedPoints(self.redPoints) self.miniDisplay.updateRedPoints(self.redPoints) def deductKyonggo(self, fighter): if fighter == self.RED and self.redKyonggo > 0: self.redKyonggo -= 1 self.display.updateRedKyonggo("Kyonggo: " + str(self.redKyonggo)) self.miniDisplay.updateRedKyonggo("Kyonggo: " + str(self.redKyonggo)) if self.redKyonggo % 2 == 1: self.redPoints += 1 self.display.updateRedPoints(self.redPoints) self.miniDisplay.updateRedPoints(self.redPoints) elif fighter == self.BLUE and self.blueKyonggo > 0: self.blueKyonggo -= 1 self.display.updateBlueKyonggo("Kyonggo: " + str(self.blueKyonggo)) self.miniDisplay.updateBlueKyonggo("Kyonggo: " + str(self.blueKyonggo)) if self.blueKyonggo % 2 == 1: self.bluePoints += 1 self.display.updateBluePoints(self.bluePoints) self.miniDisplay.updateBluePoints(self.bluePoints) def newMatch(self): if not self.timer.isRunning(): self.redPoints = 0 self.redKyonggo = 0 self.bluePoints = 0 self.blueKyonggo = 0 self.display.reset("0:00") self.miniDisplay.reset("0:00") self.hideUI() self.setup() def hideUI(self): self.redFrame.pack_forget() self.blueFrame.pack_forget() self.resetFrame.pack_forget()
class App(Tk): def __init__(self, **kwargs): super(App, self).__init__(**kwargs) tags = list(self.bindtags()) tags.insert(2, 'App') self.bindtags(tags) themes = ThemeEngine() self.option_readfile(themes.options_file) themes.set_ttk_style() self.new_reader_icon = get_icon('ic_new_reader') self.new_writer_icon = get_icon('ic_new_writer') self.close_panel_icon = get_icon('ic_close') self.save_icon = get_icon('ic_save') self.edit_icon = get_icon('ic_mode_edit') self.link_icon = get_icon('ic_insert_link') self.clear_content_icon = get_icon('ic_delete_sweep') self.delete_icon = get_icon('ic_delete_forever') img = Image.open('.resources/wm_icon.png') app_icon = ImageTk.PhotoImage(image=img) if backup_enabled(): check = check_backup() if check != 1: # print(check) pass self.title('Meta-Jurnl') self.iconphoto(True, app_icon) self.withdraw() menu_bar = Menu(master=self) self.config(menu=menu_bar) # menu_bar.pack(fill='x') file_menu = Menu(master=menu_bar, tearoff=0, relief='flat', borderwidth=1) file_menu.add_command(label='New Entry', command=self.add_writer) file_menu.add_command(label='New Linked Entry') page_menu = Menu(master=file_menu, tearoff=0) page_menu.add_command(label='New Reader', command=self.add_reader) page_menu.add_command(label='New Writer', command=self.add_writer) file_menu.add_cascade(label='New', menu=page_menu, underline=0) file_menu.add_command(label='Save') file_menu.add_command(label='Quit', command=self.destroy) edit_menu = Menu(master=menu_bar, tearoff=0) edit_menu.add_command(label='Preferences') help_menu = Menu(master=menu_bar, tearoff=0) help_menu.add_command(label='Keyboard Shortcuts') help_menu.add_command(label='About') menu_bar.add_cascade(label='File', menu=file_menu, underline=0) menu_bar.add_cascade(label='Edit', menu=edit_menu, underline=0) menu_bar.add_cascade(label='Help', menu=help_menu, underline=0) toolbar = Frame(master=self, relief='flat', borderwidth=0, padding=5) toolbar.pack(fill='x') self.journal = Journal(master=self) self.journal.pack(fill='both', expand=True) self.autoimport() self.new_reader = Button(master=toolbar, image=self.new_reader_icon, command=self.add_reader) new_writer = Button(master=toolbar, image=self.new_writer_icon, command=self.add_writer) self.close_panel = Button(master=toolbar, text='Close Tab', image=self.close_panel_icon, command=self.journal.remove_page) self.clear_button = Button(master=toolbar, image=self.clear_content_icon, command=self.clear_fields) self.save_button = Button(master=toolbar, image=self.save_icon, command=self.save_entry) self.edit_button = Button(master=toolbar, image=self.edit_icon, command=self.edit_entry) self.link_button = Button(master=toolbar, image=self.link_icon, command=self.link_entry) self.delete_button = Button(master=toolbar, image=self.delete_icon) self.new_reader.pack(side='left', padx=(0, 5)) new_writer.pack(side='left', padx=(0, 5)) self.close_panel.pack(side='left', padx=(0, 5)) self.clear_button.pack(side='left', padx=(0, 5)) self.close_panel.state(['disabled']) self.clear_button.state(['disabled']) self.journal.update_idletasks() s_width = self.winfo_screenwidth() / 2 s_height = self.winfo_screenheight() / 2 dims = dimensions() try: w_width = self.winfo_reqwidth() if not dims[0] else dims[0] w_height = self.winfo_reqheight() if not dims[1] else dims[1] except IndexError: w_width = self.winfo_reqwidth() w_height = self.winfo_reqheight() pos = w_width, w_height, s_width - floor( w_width / 2), s_height - floor(w_height / 2) self.geometry('{}x{}+{}+{}'.format(int(pos[0]), int(pos[1]), int(pos[2]), int(pos[3]))) self.bind('<Configure>', self.update_dimensions) self.bind_all('<<Check Save Button>>', self.check_writer_buttons) self.bind_all('<<Id Selected>>', self.check_reader_buttons) self.bind('<<NotebookTabChanged>>', self.change_buttons) self.change_buttons() self.after(1000, self.deiconify) self.mainloop() def update_dimensions(self, event): # s_width = self.winfo_screenwidth() / 2 # s_height = self.winfo_screenheight() / 2 w_width = max(self.winfo_width(), 1500) w_height = max(self.winfo_height(), 600) # pos = w_width, w_height, self.winfo_rootx(), self.winfo_rooty() # self.geometry('{}x{}+{}+{}'.format( # int(pos[0]), int(pos[1]), int(pos[2]), int(pos[3]) # )) dimensions((w_width, w_height)) def add_reader(self): if not database_is_empty(): self.journal.add_page('Reader') def add_writer(self): self.journal.add_page('Writer') # def add_tagged_writer(self): # self.journal.add_page('Writer', tags=True) def change_buttons(self, event=None): self.new_reader.state( ['disabled' if database_is_empty() else '!disabled']) if self.journal.mode_ == 'Writer': self.close_panel.state(['!disabled']) self.clear_button.state(['!disabled']) self.save_button.pack_forget() self.edit_button.pack_forget() self.link_button.pack_forget() self.delete_button.pack_forget() self.save_button.pack(side='left', padx=(0, 5)) self.link_button.pack(side='left', padx=(0, 5)) self.check_writer_buttons() elif self.journal.mode_ == 'Reader': self.close_panel.state(['!disabled']) self.clear_button.state(['!disabled']) self.save_button.pack_forget() self.edit_button.pack_forget() self.link_button.pack_forget() self.delete_button.pack_forget() self.edit_button.pack(side='left', padx=(0, 5)) self.link_button.pack(side='left', padx=(0, 5)) self.delete_button.pack(side='left', padx=(0, 5)) self.check_reader_buttons() else: self.close_panel.state(['disabled']) self.clear_button.state(['disabled']) self.save_button.pack_forget() self.edit_button.pack_forget() self.link_button.pack_forget() self.delete_button.pack_forget() def check_writer_buttons(self, event=None): saved = self.journal.check_saved(event) self.save_button.state(['disabled' if saved else '!disabled']) self.link_button.state( ['disabled' if not self.journal.id_ else '!disabled']) def check_reader_buttons(self, event=None): entry = True if self.journal.id_ else False self.edit_button.state(['disabled' if not entry else '!disabled']) self.link_button.state(['disabled' if not entry else '!disabled']) self.delete_button.state(['disabled' if not entry else '!disabled']) def save_entry(self): self.journal.save() self.change_buttons() def edit_entry(self): self.journal.add_page(mode='Writer', entry_id=self.journal.id_) def link_entry(self): self.journal.add_page(mode='Writer', parent=self.journal.id_) def delete_entry(self): # TODO Implement pass def clear_fields(self): if self.journal.mode_ == 'Writer': saved = self.journal.check_saved() if not saved: if askquestion( 'Clear Window Contents?', 'There are unsaved edits in this tab.\nSave before continuing?' ): self.save_entry() self.journal.clear() def autoimport(self): import_entries() self.journal.refresh_readers() if autodelete_imports(): delete_imports()
class SubfoldersListFrame(Frame): """ Frame con Entry degli autori """ def __init__(self, master, data_path_var, add_empty_author_entry=True, **kwargs): """ :param master: :param add_empty_author_entry: se `True`, aggiungi una Entry vuota in cima, altrimenti parti senza nessuna Entry :param kwargs: """ super(SubfoldersListFrame, self).__init__(master, **kwargs) self.master = master self._subfolder_entries = [] self.add_button = None self.data_path_var = data_path_var # Aggiungi entry vuota se richiesto if add_empty_author_entry: self.add_subfolder() # Pulsante 'Aggiungi autore' self.add_button = Button(self, image=icons.get_icon("add.png"), text="Add subfolder", compound="left", command=self.add_subfolder) self.add_button.pack(fill="x", pady=2) def add_subfolder(self, value=""): """ Aggiungi un autore :param value: nome dell'autore :return: """ # Rimuovi pulsante 'Aggiungi autore', se è stato posizionato if self.add_button is not None: self.add_button.pack_forget() # Crea frame con Entry e pulsante rimozione e posizionali f = Frame(self) status_label = Label(f, image=icons.get_icon("warning.png")) ae = SubfolderEntry(StringVar(value=value), f, status_label) self._subfolder_entries.append(ae) f.grid_columnconfigure(1, weight=1) ae.status_label.grid(row=0, column=0, sticky="we") ae.var.trace("w", lambda *_: self.update_entry_status_label(ae)) Entry(f, textvariable=self._subfolder_entries[-1].var).grid(row=0, column=1, sticky="we") Button( f, image=icons.get_icon("search.png"), command=lambda: ae.var.set( f"{self.data_path_var.get().strip()}\\{ae.var.get().strip()}") ).grid(row=0, column=2, sticky="e") Button(f, image=icons.get_icon("folder.png"), command=lambda: ae.var.set(filedialog.askdirectory().replace( "/", "\\").strip())).grid(row=0, column=3, sticky="e") Button(f, image=icons.get_icon("delete.png"), command=lambda: self.remove_subfolder(ae)).grid(row=0, column=4, sticky="e") f.pack(fill="x", pady=1, expand=True) # Riaggiungi pulsante 'Aggiungi autore', se necessario if self.add_button is not None: self.add_button.pack(fill="x", pady=2) def is_subfolder(self, path: str) -> bool: data_path = self.data_path_var.get().lower().rstrip("\\").strip() return bool(data_path) and path.lower().strip().startswith( data_path) and os.path.isdir(path) def update_entry_status_label(self, entry: SubfolderEntry) -> None: entry.status_label.configure( image=icons.get_icon("success.png" if self.is_subfolder( entry.var.get()) else "warning.png")) def remove_subfolder(self, author_entry): """ Rimuove un autore dalla lista degli autori :param author_entry: `AutorEntry` dell'autore da rimuovere :return: """ author_entry.frame.pack_forget() self._subfolder_entries.remove(author_entry) @property def subfolders(self): """ Ritorna gli autori :return: """ return self._subfolder_entries @subfolders.setter def subfolders(self, authors): """ Imposta gli autori e ricostruisce la lista dei widget :param authors: :return: """ self._subfolder_entries.clear() for widget in self.pack_slaves(): widget.pack_forget() for author in authors: self.add_subfolder(author) def reevaluate_statuses(self): for x in self._subfolder_entries: self.update_entry_status_label(x)