From 9a8ece087e7761880a314c489e6d710a4b8b73d8 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Thu, 23 Aug 2018 12:30:35 -0400 Subject: [PATCH 1/9] Support for Listbox.Update --- PySimpleGUI.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 9fa1ca91..51ac0bfc 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -290,7 +290,7 @@ class Listbox(Element): :param auto_size_text: True if should shrink field to fit the default text :param background_color: Color for Element. Text or RGB Hex ''' self.Values = values - self.TKListBox = None + self.TKListbox = None if select_mode == LISTBOX_SELECT_MODE_BROWSE: self.SelectMode = SELECT_MODE_BROWSE elif select_mode == LISTBOX_SELECT_MODE_EXTENDED: @@ -305,6 +305,12 @@ class Listbox(Element): fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR super().__init__(ELEM_TYPE_INPUT_LISTBOX, scale=scale, size=size, auto_size_text=auto_size_text, font=font, background_color=bg, text_color=fg, key=key) + def Update(self, values): + self.TKListbox.delete(0, 'end') + for item in values: + self.TKListbox.insert(tk.END, item) + self.TKListbox.selection_set(0, 0) + def __del__(self): try: self.TKListBox.__del__() From dcbbf319ebddd24e6bfd77b66b08697abb85467a Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Thu, 23 Aug 2018 12:45:51 -0400 Subject: [PATCH 2/9] Update method for Text Element now includes colors --- PySimpleGUI.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 51ac0bfc..78430d43 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -482,10 +482,15 @@ class Text(Element): super().__init__(ELEM_TYPE_TEXT, scale, size, auto_size_text, background_color=bg, font=font if font else DEFAULT_FONT, text_color=self.TextColor) return - def Update(self, NewValue): - self.DisplayText=NewValue - stringvar = self.TKStringVar - stringvar.set(NewValue) + def Update(self, new_value = None, background_color=None, text_color=None): + if new_value is not None: + self.DisplayText=new_value + stringvar = self.TKStringVar + stringvar.set(new_value) + if background_color is not None: + self.TKText.configure(background=background_color) + if text_color is not None: + self.TKText.configure(fg=text_color) def __del__(self): super().__del__() @@ -1478,6 +1483,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): if element.TextColor != COLOR_SYSTEM_DEFAULT and element.TextColor is not None: tktext_label.configure(fg=element.TextColor) tktext_label.pack(side=tk.LEFT) + element.TKText = tktext_label # print(f'Text element placed w = {width}, h = {height}, wrap = {wraplen}') # ------------------------- BUTTON element ------------------------- # elif element_type == ELEM_TYPE_BUTTON: From dad31df5479bace26a9e7198946f4eb52c0663d2 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Thu, 23 Aug 2018 13:17:58 -0400 Subject: [PATCH 3/9] New simple persistent form. --- docs/cookbook.md | 53 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/docs/cookbook.md b/docs/cookbook.md index 61e581c0..256b2cbf 100644 --- a/docs/cookbook.md +++ b/docs/cookbook.md @@ -57,7 +57,7 @@ Browse for a filename that is populated into the input field. import PySimpleGUI as sg - with sg.FlexForm('SHA-1 & 256 Hash', auto_size_text=True) as form: + with sg.FlexForm('SHA-1 & 256 Hash') as form: form_rows = [[sg.Text('SHA-1 and SHA-256 Hashes for the file')], [sg.InputText(), sg.FileBrowse()], [sg.Submit(), sg.Cancel()]] @@ -101,7 +101,7 @@ Example of nearly all of the widgets in a single form. Uses a customized color progress_meter_border_depth=0, scrollbar_color='#F7F3EC') - with sg.FlexForm('Everything bagel', auto_size_text=True, default_element_size=(40, 1)) as form: + with sg.FlexForm('Everything bagel', default_element_size=(40, 1)) as form: layout = [ [sg.Text('All graphic widgets in one form!', size=(30, 1), font=("Helvetica", 25))], [sg.Text('Here is some text.... and a place to enter text')], @@ -141,7 +141,7 @@ Example of nearly all of the widgets in a single form. Uses a customized color progress_meter_border_depth=0, scrollbar_color='#F7F3EC') - form = sg.FlexForm('Everything bagel', auto_size_text=True, default_element_size=(40, 1)) + form = sg.FlexForm('Everything bagel', default_element_size=(40, 1)) layout = [ [sg.Text('All graphic widgets in one form!', size=(30, 1), font=("Helvetica", 25))], [sg.Text('Here is some text.... and a place to enter text')], @@ -175,7 +175,7 @@ An async form that has a button read loop. A Text Element is updated periodical import PySimpleGUI as sg import time - form = sg.FlexForm('Running Timer', auto_size_text=True) + form = sg.FlexForm('Running Timer') # create a text element that will be updated periodically text_element = sg.Text('', size=(10, 2), font=('Helvetica', 20), justification='center') @@ -210,7 +210,7 @@ Like the previous recipe, this form is an async form. The difference is that th import PySimpleGUI as sg import time - with sg.FlexForm('Running Timer', auto_size_text=True) as form: + with sg.FlexForm('Running Timer') as form: text_element = sg.Text('', size=(10, 2), font=('Helvetica', 20), text_color='red', justification='center') layout = [[sg.Text('Non blocking GUI with updates', justification='center')], [text_element], @@ -249,7 +249,7 @@ The architecture of some programs works better with button callbacks instead of # Create a standard form form = sg.FlexForm('Button callback example') # Layout the design of the GUI - layout = [[sg.Text('Please click a button', auto_size_text=True)], + layout = [[sg.Text('Please click a button')], [sg.ReadFormButton('1'), sg.ReadFormButton('2'), sg.Quit()]] # Show the form to the user form.Layout(layout) @@ -593,3 +593,44 @@ To make it easier to see the Column in the window, the Column background has bee button, values = sg.FlexForm('Compact 1-line form with column').LayoutAndRead(layout) sg.MsgBox(button, values, line_width=200) + + +## Persistent Form With Text Element Updates + +This simple program keep a form open, taking input values until the user terminates the program using the "X" button. + +![math game](https://user-images.githubusercontent.com/13696193/44537842-c9444080-a6cd-11e8-94bc-6cdf1b765dd8.jpg) + + + + import PySimpleGUI as sg + + form = sg.FlexForm('Math') + + output = sg.Txt('', size=(8,1)) + + layout = [ [sg.Txt('Enter values to calculate')], + [sg.In(size=(8,1), key='numerator')], + [sg.Txt('_' * 10)], + [sg.In(size=(8,1), key='denominator')], + [output], + [sg.ReadFormButton('Calculate', bind_return_key=True)]] + + form.Layout(layout) + + while True: + button, values = form.Read() + + if button is not None: + try: + numerator = float(values['numerator']) + denominator = float(values['denominator']) + calc = numerator / denominator + except: + calc = 'Invalid' + + output.Update(calc) + else: + break + + From a57fc797063b74327b34d3656da017150db451c4 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Thu, 23 Aug 2018 13:50:20 -0400 Subject: [PATCH 4/9] Update method for Buttons --- PySimpleGUI.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 78430d43..1b34a341 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -715,6 +715,9 @@ class Button(Element): self.ParentForm.TKroot.quit() # kick the users out of the mainloop return + def Update(self, new_text): + self.TKButton.configure(text=new_text) + def __del__(self): try: self.TKButton.__del__() From fcdd58ae8366b5626f09db568350ca79613d113f Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Thu, 23 Aug 2018 14:10:58 -0400 Subject: [PATCH 5/9] Protection around update in case form was manually closed --- PySimpleGUI.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 1b34a341..0813e8ce 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -716,7 +716,10 @@ class Button(Element): return def Update(self, new_text): - self.TKButton.configure(text=new_text) + try: + self.TKButton.configure(text=new_text) + except: + return def __del__(self): try: @@ -1060,6 +1063,7 @@ class FlexForm: except: self.TKrootDestroyed = True _my_windows.Decrement() + # return None, None return BuildResults(self, False, self) def GetScreenDimensions(self): From cc96d52ae4d364df9749843f791a00e32fe337dc Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Thu, 23 Aug 2018 14:17:46 -0400 Subject: [PATCH 6/9] Added ability to change button colors using Update method --- PySimpleGUI.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 0813e8ce..0df8a727 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -715,9 +715,11 @@ class Button(Element): self.ParentForm.TKroot.quit() # kick the users out of the mainloop return - def Update(self, new_text): + def Update(self, new_text, button_color=(None, None)): try: self.TKButton.configure(text=new_text) + if button_color != (None, None): + self.TKButton.config(foreground=button_color[0], background=button_color[1]) except: return @@ -1043,8 +1045,6 @@ class FlexForm: if self.RootNeedsDestroying: self.TKroot.destroy() _my_windows.Decrement() - # if self.ReturnValues[0] is not None: # keyboard events build their own return values - # return self.ReturnValues if self.LastKeyboardEvent is not None or self.LastButtonClicked is not None: return BuildResults(self, False, self) else: From a2e8b0fad3ec42af7452ad4b770027ed71508460 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Fri, 24 Aug 2018 07:45:31 -0400 Subject: [PATCH 7/9] Added Slider Update method, reworking of how Text Elements wrap (risky change), rework how MsgBox wraps Some risky changes to how text wraps, but hopefully these will fix problems of forms being way too wide. Also added Update to Slider Element. This allows it to be used for things like tracking progress in a song being played. --- PySimpleGUI.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 0df8a727..985bf244 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -840,6 +840,9 @@ class Slider(Element): super().__init__(ELEM_TYPE_INPUT_SLIDER, scale=scale, size=size, font=font, background_color=background_color, text_color=text_color, key=key) return + def Update(self, value): + self.TKIntVar.set(value) + def __del__(self): super().__del__() @@ -1481,17 +1484,18 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): justify = tk.LEFT if justification == 'left' else tk.CENTER if justification == 'center' else tk.RIGHT anchor = tk.NW if justification == 'left' else tk.N if justification == 'center' else tk.NE tktext_label = tk.Label(tk_row_frame, textvariable=stringvar, width=width, height=height, justify=justify, bd=border_depth) - # tktext_label = tk.Label(tk_row_frame,anchor=tk.NW, text=display_text, width=width, height=height, justify=tk.LEFT, bd=border_depth) # Set wrap-length for text (in PIXELS) == PAIN IN THE ASS - wraplen = tktext_label.winfo_reqwidth() # width of widget in Pixels - tktext_label.configure(anchor=anchor, font=font, wraplen=wraplen+40) # set wrap to width of widget + wraplen = tktext_label.winfo_reqwidth()+40 # width of widget in Pixels + if not auto_size_text: + wraplen = 0 + # print("wraplen, width, height", wraplen, width, height) + tktext_label.configure(anchor=anchor, font=font, wraplen=wraplen) # set wrap to width of widget if element.BackgroundColor is not None: tktext_label.configure(background=element.BackgroundColor) if element.TextColor != COLOR_SYSTEM_DEFAULT and element.TextColor is not None: tktext_label.configure(fg=element.TextColor) tktext_label.pack(side=tk.LEFT) element.TKText = tktext_label - # print(f'Text element placed w = {width}, h = {height}, wrap = {wraplen}') # ------------------------- BUTTON element ------------------------- # elif element_type == ELEM_TYPE_BUTTON: element.Location = (row_num, col_num) @@ -1952,7 +1956,8 @@ def MsgBox(*args, button_color=None, button_type=MSG_BOX_OK, auto_close=False, a max_line_total = max(max_line_total, width_used) # height = _GetNumLinesNeeded(message, width_used) height = message_wrapped_lines - form.AddRow(Text(message_wrapped, auto_size_text=True, size=(width_used, height))) + # print('Msgbox width, height', width_used, height) + form.AddRow(Text(message_wrapped, auto_size_text=True)) total_lines += height pad = max_line_total-15 if max_line_total > 15 else 1 From 53e0c25a0227c7e4a5ffdb99ab1a89e5b404b0bb Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Fri, 24 Aug 2018 07:57:22 -0400 Subject: [PATCH 8/9] Chaned how wrapping in Text Elements work, changed MsgBox to use new wrapping More risky Text Element changes --- PySimpleGUI.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 985bf244..0fc5f76a 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1473,7 +1473,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): stringvar = tk.StringVar() element.TKStringVar = stringvar stringvar.set(display_text) - if auto_size_text: + if element.AutoSizeText: width = 0 if element.Justification is not None: justification = element.Justification @@ -1957,7 +1957,7 @@ def MsgBox(*args, button_color=None, button_type=MSG_BOX_OK, auto_close=False, a # height = _GetNumLinesNeeded(message, width_used) height = message_wrapped_lines # print('Msgbox width, height', width_used, height) - form.AddRow(Text(message_wrapped, auto_size_text=True)) + form.AddRow(Text(message_wrapped, auto_size_text=True, size=(width_used, height))) total_lines += height pad = max_line_total-15 if max_line_total > 15 else 1 From 2e3c401e872576a40bf1edc8fa31b5af0ea87482 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Fri, 24 Aug 2018 08:03:56 -0400 Subject: [PATCH 9/9] NEW Demo - MIDI player using Mido --- Demo_MIDI_Player.py | 228 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 Demo_MIDI_Player.py diff --git a/Demo_MIDI_Player.py b/Demo_MIDI_Player.py new file mode 100644 index 00000000..3da9b17d --- /dev/null +++ b/Demo_MIDI_Player.py @@ -0,0 +1,228 @@ +import os +import PySimpleGUI as g +import mido +import time + +PLAYER_COMMAND_NONE = 0 +PLAYER_COMMAND_EXIT = 1 +PLAYER_COMMAND_PAUSE = 2 +PLAYER_COMMAND_NEXT = 3 +PLAYER_COMMAND_RESTART_SONG = 4 + +# ---------------------------------------------------------------------- # +# PlayerGUI CLASS # +# ---------------------------------------------------------------------- # +class PlayerGUI(): + ''' + Class implementing GUI for both initial screen but the player itself + ''' + + def __init__(self): + self.Form = None + self.TextElem = None + self.PortList = mido.get_output_names() # use to get the list of midi ports + self.PortList = self.PortList[::-1] # reverse the list so the last one is first + + # ---------------------------------------------------------------------- # + # PlayerChooseSongGUI # + # Show a GUI get to the file to playback # + # ---------------------------------------------------------------------- # + def PlayerChooseSongGUI(self): + + # ---------------------- DEFINION OF CHOOSE WHAT TO PLAY GUI ---------------------------- + with g.FlexForm('MIDI File Player', auto_size_text=False, + default_element_size=(30, 1), + font=("Helvetica", 12)) as form: + layout = [[g.Text('MIDI File Player', font=("Helvetica", 15), size=(20, 1), text_color='green')], + [g.Text('File Selection', font=("Helvetica", 15), size=(20, 1))], + [g.Text('Single File Playback', justification='right'), g.InputText(size=(65, 1), key='midifile'), g.FileBrowse(size=(10, 1), file_types=(("MIDI files", "*.mid"),))], + [g.Text('Or Batch Play From This Folder', auto_size_text=False, justification='right'), g.InputText(size=(65, 1), key='folder'), g.FolderBrowse(size=(10, 1))], + [g.Text('_' * 250, auto_size_text=False, size=(100, 1))], + [g.Text('Choose MIDI Output Device', size=(22, 1)), + g.Listbox(values=self.PortList, size=(30, len(self.PortList) + 1), key='device')], + [g.Text('_' * 250, auto_size_text=False, size=(100, 1))], + [g.SimpleButton('PLAY!', size=(10, 2), button_color=('red', 'white'), font=("Helvetica", 15), bind_return_key=True), g.Text(' ' * 2, size=(4, 1)), g.Cancel(size=(8, 2), font=("Helvetica", 15))]] + + + self.Form = form + return form.LayoutAndRead(layout) + + + def PlayerPlaybackGUIStart(self, NumFiles=1): + # ------- Make a new FlexForm ------- # + + image_pause = './ButtonGraphics/Pause.png' + image_restart = './ButtonGraphics/Restart.png' + image_next = './ButtonGraphics/Next.png' + image_exit = './ButtonGraphics/Exit.png' + + self.TextElem = g.T('Song loading....', size=(85, 5 + NumFiles), font=("Helvetica", 14), auto_size_text=False) + form = g.FlexForm('MIDI File Player', default_element_size=(30, 1),font=("Helvetica", 25)) + layout = [ + [g.T('MIDI File Player', size=(30, 1), font=("Helvetica", 25))], + [self.TextElem], + [g.ReadFormButton('PAUSE', button_color=g.TRANSPARENT_BUTTON, + image_filename=image_pause, image_size=(50,50),image_subsample=2, border_width=0, + font=("Helvetica", 15), size=(10, 2)), g.T(' ' * 3), + g.ReadFormButton('NEXT', button_color=g.TRANSPARENT_BUTTON, + image_filename=image_next, image_size=(50,50),image_subsample=2, border_width=0, + size=(10, 2), font=("Helvetica", 15)), g.T(' ' * 3), + g.ReadFormButton('Restart Song', button_color=g.TRANSPARENT_BUTTON, + image_filename=image_restart, image_size=(50,50), image_subsample=2,border_width=0, + size=(10, 2), font=("Helvetica", 15)), g.T(' ' * 3), + g.T(' '*2), g.SimpleButton('EXIT', button_color=g.TRANSPARENT_BUTTON, + image_filename=image_exit, image_size=(50,50), image_subsample=2,border_width=0, + size=(10, 2), font=("Helvetica", 15))] + ] + + form.LayoutAndRead(layout, non_blocking=True) + self.Form = form + + + + # ------------------------------------------------------------------------- # + # PlayerPlaybackGUIUpdate # + # Refresh the GUI for the main playback interface (must call periodically # + # ------------------------------------------------------------------------- # + def PlayerPlaybackGUIUpdate(self, DisplayString): + form = self.Form + if 'form' not in locals() or form is None: # if the form has been destoyed don't mess with it + return PLAYER_COMMAND_EXIT + self.TextElem.Update(DisplayString) + button, (values) = form.ReadNonBlocking() + if values is None: + return PLAYER_COMMAND_EXIT + if button == 'PAUSE': + return PLAYER_COMMAND_PAUSE + elif button == 'EXIT': + return PLAYER_COMMAND_EXIT + elif button == 'NEXT': + return PLAYER_COMMAND_NEXT + elif button == 'Restart Song': + return PLAYER_COMMAND_RESTART_SONG + return PLAYER_COMMAND_NONE + + +# ---------------------------------------------------------------------- # +# MAIN - our main program... this is it # +# Runs the GUI to get the file / path to play # +# Decodes the MIDI-Video into a MID file # +# Plays the decoded MIDI file # +# ---------------------------------------------------------------------- # +def main(): + def GetCurrentTime(): + ''' + Get the current system time in milliseconds + :return: milliseconds + ''' + return int(round(time.time() * 1000)) + + g.SetOptions(border_width=1, element_padding=(4, 6), font=("Helvetica", 10), button_color=('white', g.BLUES[0]), + progress_meter_border_depth=1, slider_border_width=1) + pback = PlayerGUI() + + button, values = pback.PlayerChooseSongGUI() + if button != 'PLAY!': + g.MsgBoxCancel('Cancelled...\nAutoclose in 2 sec...', auto_close=True, auto_close_duration=2) + exit(69) + if values['device'] is not None: + midi_port = values['device'][0] + else: + g.MsgBoxCancel('No devices found\nAutoclose in 2 sec...', auto_close=True, auto_close_duration=2) + + batch_folder = values['folder'] + midi_filename = values['midifile'] + # ------ Build list of files to play --------------------------------------------------------- # + if batch_folder: + filelist = os.listdir(batch_folder) + filelist = [batch_folder+'/'+f for f in filelist if f.endswith(('.mid', '.MID'))] + filetitles = [os.path.basename(f) for f in filelist] + elif midi_filename: # an individual filename + filelist = [midi_filename,] + filetitles = [os.path.basename(midi_filename),] + else: + g.MsgBoxError('*** Error - No MIDI files specified ***') + exit(666) + + # ------ LOOP THROUGH MULTIPLE FILES --------------------------------------------------------- # + pback.PlayerPlaybackGUIStart(NumFiles=len(filelist) if len(filelist) <=10 else 10) + port = None + # Loop through the files in the filelist + for now_playing_number, current_midi_filename in enumerate(filelist): + display_string = 'Playing Local File...\n{} of {}\n{}'.format(now_playing_number+1, len(filelist), current_midi_filename) + midi_title = filetitles[now_playing_number] + # --------------------------------- REFRESH THE GUI ----------------------------------------- # + pback.PlayerPlaybackGUIUpdate(display_string) + + # ---===--- Output Filename is .MID --- # + midi_filename = current_midi_filename + + # --------------------------------- MIDI - STARTS HERE ----------------------------------------- # + if not port: # if the midi output port not opened yet, then open it + port = mido.open_output(midi_port if midi_port else None) + + try: + mid = mido.MidiFile(filename=midi_filename) + except: + print('****** Exception trying to play MidiFile filename = {}***************'.format(midi_filename)) + g.MsgBoxError('Exception trying to play MIDI file:', midi_filename, 'Skipping file') + continue + + # Build list of data contained in MIDI File using only track 0 + midi_length_in_seconds = mid.length + display_file_list = '>> ' + '\n'.join([f for i, f in enumerate(filelist[now_playing_number:]) if i < 10]) + paused = cancelled = next_file = False + ######################### Loop through MIDI Messages ########################### + while(True): + start_playback_time = GetCurrentTime() + port.reset() + + for midi_msg_number, msg in enumerate(mid.play()): + #################### GUI - read values ################## + if not midi_msg_number % 4: # update the GUI every 4 MIDI messages + t = (GetCurrentTime() - start_playback_time)//1000 + display_midi_len = '{:02d}:{:02d}'.format(*divmod(int(midi_length_in_seconds),60)) + display_string = 'Now Playing {} of {}\n{}\n {:02d}:{:02d} of {}\nPlaylist:'.\ + format(now_playing_number+1, len(filelist), midi_title, *divmod(t, 60), display_midi_len) + # display list of next 10 files to be played. + rc = pback.PlayerPlaybackGUIUpdate(display_string + '\n' + display_file_list) + else: # fake rest of code as if GUI did nothing + rc = PLAYER_COMMAND_NONE + if paused: + rc = PLAYER_COMMAND_NONE + while rc == PLAYER_COMMAND_NONE: # TIGHT-ASS loop waiting on a GUI command + rc = pback.PlayerPlaybackGUIUpdate(display_string) + time.sleep(.25) + + ####################################### MIDI send data ################################## + port.send(msg) + + # ------- Execute GUI Commands after sending MIDI data ------- # + if rc == PLAYER_COMMAND_EXIT: + cancelled = True + break + elif rc == PLAYER_COMMAND_PAUSE: + paused = not paused + port.reset() + elif rc == PLAYER_COMMAND_NEXT: + next_file = True + break + elif rc == PLAYER_COMMAND_RESTART_SONG: + break + + if cancelled or next_file: + break + #------- DONE playing the song ------- # + port.reset() # reset the midi port when done with the song + + if cancelled: + break + exit(69) + +# ---------------------------------------------------------------------- # +# LAUNCH POINT -- program starts and ends here # +# ---------------------------------------------------------------------- # +if __name__ == '__main__': + main() + + exit(69)