def play(self,show_id,end_callback,show_ready_callback, top=False,command='nil'):

        """ displays the mediashow
              end_callback - function to be called when the menu exits
              ready_callback - callback when menu is ready to display (not used)
              top is True when the show is top level (run from [start])
        """

        #instantiate the arguments
        self.show_id=show_id
        self.end_callback=end_callback
        self.show_ready_callback=show_ready_callback
        self.top=top
        self.command=command
        self.mon.log(self,self.show_params['show-ref']+ ' '+ str(self.show_id)+ ": Starting show")

        # check  data files are available.
        self.media_file = self.pp_profile + "/" + self.show_params['medialist']
        if not os.path.exists(self.media_file):
            self.mon.err(self,"Medialist file not found: "+ self.media_file)
            self.end('error',"Medialist file not found")


        #create a medialist for the mediashow and read it.
        self.medialist=MediaList(self.show_params['sequence'])
        if self.medialist.open_list(self.media_file,self.showlist.sissue())==False:
            self.mon.err(self,"Version of medialist different to Pi Presents")
            self.end('error',"Version of medialist different to Pi Presents")

        #get controls for this show if top level
        controlsmanager=ControlsManager()
        if self.top==True:
            self.controls_list=controlsmanager.default_controls()
            # and merge in controls from profile
            self.controls_list=controlsmanager.merge_show_controls(self.controls_list,self.show_params['controls'])


        #set up the time of day triggers for the show
        if self.show_params['trigger']in('time','time-quiet'):
            error_text=self.tod.add_times(self.show_params['trigger-input'],id(self),self.tod_start_callback,self.show_params['trigger'])
            if error_text<>'':
                self.mon.err(self,error_text)
                self.end('error',error_text)

        if self.show_params['trigger-end']=='time':
            # print self.show_params['trigger-end-time']
            error_text=self.tod.add_times(self.show_params['trigger-end-time'],id(self),self.tod_end_callback,'n/a')
            if error_text<>'':
                self.mon.err(self,error_text)
                self.end('error',error_text)
                
        if self.show_params['trigger-end']=='duration':
            error_text=self.calculate_duration(self.show_params['trigger-end-time'])
            if error_text<>'':
                self.mon.err(self,error_text)
                self.end('error',error_text)
                
        self.state='closed'
        self.egg_timer=None
        self.wait_for_trigger()
Example #2
0
    def play(self,show_id,end_callback,show_ready_callback, top=False,command='nil'):

        """ displays the mediashow
              end_callback - function to be called when the menu exits
              ready_callback - callback when menu is ready to display (not used)
              top is True when the show is top level (run from [start])
        """

        #instantiate the arguments
        self.show_id=show_id
        self.end_callback=end_callback
        self.show_ready_callback=show_ready_callback
        self.top=top
        self.command=command
        self.mon.log(self,self.show_params['show-ref']+ ' '+ str(self.show_id)+ ": Starting show")

        # check  data files are available.
        self.media_file = self.pp_profile + "/" + self.show_params['medialist']
        if not os.path.exists(self.media_file):
            self.mon.err(self,"Medialist file not found: "+ self.media_file)
            self.end('error',"Medialist file not found")


        #create a medialist for the mediashow and read it.
        self.medialist=MediaList()
        if self.medialist.open_list(self.media_file,self.showlist.sissue())==False:
            self.mon.err(self,"Version of medialist different to Pi Presents")
            self.end('error',"Version of medialist different to Pi Presents")

        #get controls for this show if top level
        controlsmanager=ControlsManager()
        if self.top==True:
            self.controls_list=controlsmanager.default_controls()
            # and merge in controls from profile
            self.controls_list=controlsmanager.merge_show_controls(self.controls_list,self.show_params['controls'])


        #set up the time of day triggers for the show
        if self.show_params['trigger']in('time','time-quiet'):
            error_text=self.tod.add_times(self.show_params['trigger-input'],id(self),self.tod_start_callback,self.show_params['trigger'])
            if error_text<>'':
                self.mon.err(self,error_text)
                self.end('error',error_text)

        if self.show_params['trigger-end']=='time':
            # print self.show_params['trigger-end-time']
            error_text=self.tod.add_times(self.show_params['trigger-end-time'],id(self),self.tod_end_callback,'n/a')
            if error_text<>'':
                self.mon.err(self,error_text)
                self.end('error',error_text)
                
        if self.show_params['trigger-end']=='duration':
            error_text=self.calculate_duration(self.show_params['trigger-end-time'])
            if error_text<>'':
                self.mon.err(self,error_text)
                self.end('error',error_text)
                
        self.state='closed'
        self.egg_timer=None
        self.wait_for_trigger()
Example #3
0
    def __init__(self, show_id, show_params, root, canvas, showlist, pp_dir,
                 pp_home, pp_profile, command_callback):
        """
            show_id - index of the top level show caling this (for debug only)
            show_params - dictionary section for the menu
            canvas - the canvas that the menu is to be written on
            showlist  - the showlist
            pp_dir - Pi Presents directory
            pp_home - Pi presents data_home directory
            pp_profile - Pi presents profile directory
        """

        # init the common bits
        Show.base__init__(self, show_id, show_params, root, canvas, showlist,
                          pp_dir, pp_home, pp_profile, command_callback)

        # instatiatate the screen driver - used only to access enable and hide click areas
        self.sr = ScreenDriver()

        self.controlsmanager = ControlsManager()

        # init variables
        self.show_timeout_timer = None
        self.track_timeout_timer = None
        self.next_track_signal = False
        self.next_track = None
        self.menu_index = 0
        self.menu_showing = True
        self.req_next = ''
        self.last_menu_index = 0
        self.return_to_zero = False
    def __init__(self, show_id, show_params, root, canvas, showlist, pp_dir,
                 pp_home, pp_profile, command_callback):

        # init the common bits
        Show.base__init__(self, show_id, show_params, root, canvas, showlist,
                          pp_dir, pp_home, pp_profile, command_callback)

        # instatiatate the screen driver - used only to access enable and hide click areas
        self.sr = ScreenDriver()

        self.controlsmanager = ControlsManager()

        # Init variables special to this show
        self.poll_for_interval_timer = None
        self.interval_timer_signal = False
        self.waiting_for_interval = False
        self.interval_timer = None
        self.duration_timer = None

        self.end_trigger_signal = False
        self.next_track_signal = False
        self.previous_track_signal = False
        self.play_child_signal = False
        self.error_signal = False
        self.show_timeout_signal = False

        self.req_next = 'nil'
        self.state = 'closed'

        self.count = 0
        self.interval = 0
        self.duration = 0
        self.controls_list = []
        self.enable_hint = True
    def play(self,show_id,end_callback,ready_callback,top=False,command='nil'):
        """ starts the hyperlink show at start-track 
              end_callback - function to be called when the show exits
              ready_callback - callback when event-show is ready to display its forst track (not used?)
              top is True when the show is top level (run from [start] or from show control)
              command is not used
        """
        
        #instantiate arguments
        self.show_id=show_id
        self.end_callback=end_callback
        self.ready_callback=ready_callback
        self.top=top
        self.command=command

        # check data files are available.
        self.medialist_file = self.pp_profile + "/" + self.show_params['medialist']
        if not os.path.exists(self.medialist_file):
            self.mon.err(self,"Medialist file not found: "+ self.medialist_file)
            self.end('error',"Medialist file not found")
        
        #create a medialist object for the hyperlinkshow and read the file into it.
        self.medialist=MediaList()
        if self.medialist.open_list(self.medialist_file,self.showlist.sissue()) == False:
            self.mon.err(self,"Version of medialist different to Pi Presents")
            self.end('error',"Version of medialist different to Pi Presents")

        #get controls for this show if top level
        controlsmanager=ControlsManager()
        if self.top==True:
            self.controls_list=controlsmanager.default_controls()
            # and merge in controls from profile
            self.controls_list=controlsmanager.merge_show_controls(self.controls_list,self.show_params['controls'])

        
        # read show  links and destinations
        self.first_track_ref=self.show_params['first-track-ref']
        self.home_track_ref=self.show_params['home-track-ref']
        self.timeout_track_ref=self.show_params['timeout-track-ref']
        

    # state variables and signals   
        self.end_hyperlinkshow_signal= False
        self.egg_timer=None
        self.next_track_signal=False
        self.next_track_ref=''
        self.current_track_ref=''
        self.current_track_type=''

        # ready callback for show
        if self.ready_callback<>None:
            self.ready_callback()
                    
        self.canvas.delete('pp-content')
        self.canvas.config(bg='black')
        
        self.do_first_track()
    def track_ready_callback(self, enable_show_background):
        self.mon.trace(self, '')

        # get control bindings for this show
        self.controlsmanager = ControlsManager()
        if self.show_params['disable-controls'] == 'yes':
            self.controls_list = []
        else:
            reason, message, self.controls_list = self.controlsmanager.get_controls(
                self.show_params['controls'])
            if reason == 'error':
                self.mon.err(self, message)
                self.end('error', "error in controls: " + message)
                return
            # print '\nshow controls',self.show_params['controls']

            #merge controls from the track
            controls_text = self.current_player.get_links()
            # print 'current player controls',controls_text
            reason, message, track_controls = self.controlsmanager.parse_controls(
                controls_text)
            if reason == 'error':
                self.mon.err(
                    self, message + " in track: " +
                    self.current_player.track_params['track-ref'])
                self.error_signal = True
                self.what_next_after_showing()
            self.controlsmanager.merge_controls(self.controls_list,
                                                track_controls)

        # show the show background done for every track but quick operation
        if enable_show_background is True:
            self.base_show_show_background()
        else:
            self.base_withdraw_show_background()
        # !!!!!!!!! withdraw the background from the parent show
        if self.previous_shower != None:
            self.previous_shower.base_withdraw_show_background()

        # close the player from the previous track
        if self.previous_player is not None:
            self.mon.trace(
                self, 'hiding previous: ' +
                self.mon.pretty_inst(self.previous_player))
            self.previous_player.hide()
            if self.previous_player.get_play_state() == 'showing':
                self.mon.trace(
                    self, 'closing previous: ' +
                    self.mon.pretty_inst(self.previous_player))
                self.previous_player.close(self.closed_callback)
            else:
                self.mon.trace(self, 'previous is none')
                self.previous_player = None
Example #7
0
    def play(self,show_id,end_callback,ready_callback,top=False,command='nil'):
        """ displays the menu 
              end_callback - function to be called when the menu exits
              ready_callback - callback when menu is ready to display (not used)
              top is True when the show is top level (run from [start])
        """
        
        #instantiate arguments
        self.show_id=show_id
        self.end_callback=end_callback
        self.ready_callback=ready_callback
        self.top=top
        self.command=command

        # check  data files are available.
        self.menu_file = self.pp_profile + "/" + self.show_params['medialist']
        if not os.path.exists(self.menu_file):
            self.mon.err(self,"Medialist file not found: "+ self.menu_file)
            self.end('error',"Medialist file not found")
        
        #create a medialist for the menu and read it.
        self.medialist=MediaList()
        if self.medialist.open_list(self.menu_file,self.showlist.sissue()) == False:
            self.mon.err(self,"Version of medialist different to Pi Presents")
            self.end('error',"Version of medialist different to Pi Presents")

        #get control bindings for this show if top level
        controlsmanager=ControlsManager()
        if self.top==True:
            self.controls_list=controlsmanager.default_controls()
            # and merge in controls from profile
            self.controls_list=controlsmanager.merge_show_controls(self.controls_list,self.show_params['controls'])

           
        if self.show_params['has-background']=="yes":
            background_index=self.medialist.index_of_track ('pp-menu-background')
            if background_index>=0:
                self.menu_img_file = self.complete_path(self.medialist.track(background_index)['location'])
                if not os.path.exists(self.menu_img_file):
                    self.mon.err(self,"Menu background file not found: "+ self.menu_img_file)
                    self.end('error',"Menu background file not found")
            else:
                self.mon.err(self,"Menu background not found in medialist")
                self.end('error',"Menu background not found")
                               
        self.end_menushow_signal= False
        if self.ready_callback<>None:
            self.ready_callback()

        self.menu_timeout_value=int(self.show_params['timeout'])*1000
        self.do_menu()
Example #8
0
    def __init__(self, show_id, show_params, root, canvas, showlist, pp_dir, pp_home, pp_profile, command_callback):

        """
            show_id - index of the top level show caling this (for debug only)
            show_params - dictionary section for the menu
            canvas - the canvas that the menu is to be written on
            showlist  - the showlist
            pp_dir - Pi Presents directory
            pp_home - Pi presents data_home directory
            pp_profile - Pi presents profile directory
        """

        # init the common bits
        Show.base__init__(
            self, show_id, show_params, root, canvas, showlist, pp_dir, pp_home, pp_profile, command_callback
        )

        # instatiatate the screen driver - used only to access enable and hide click areas
        self.sr = ScreenDriver()

        self.controlsmanager = ControlsManager()

        # init variables
        self.show_timeout_timer = None
        self.track_timeout_timer = None
        self.next_track_signal = False
        self.next_track = None
        self.menu_index = 0
        self.menu_showing = True
        self.req_next = ""
Example #9
0
    def __init__(self,
                 show_id,
                 show_params,
                 root,
                 canvas,
                 showlist,
                 pp_dir,
                 pp_home,
                 pp_profile,
                 command_callback):


        # init the common bits
        Show.base__init__(self,
                          show_id,
                          show_params,
                          root,
                          canvas,
                          showlist,
                          pp_dir,
                          pp_home,
                          pp_profile,
                          command_callback)

        # instatiatate the screen driver - used only to access enable and hide click areas
        self.sr=ScreenDriver()

        self.controlsmanager=ControlsManager()

        # Init variables special to this show
        self.poll_for_interval_timer=None
        self.interval_timer_signal=False
        self.waiting_for_interval=False
        self.interval_timer=None
        self.duration_timer=None

        self.end_trigger_signal=False
        self.next_track_signal=False
        self.previous_track_signal=False
        self.play_child_signal = False
        self.error_signal=False
        self.show_timeout_signal=False
        
        self.req_next='nil'
        self.state='closed'

        self.count=0
        self.interval=0
        self.duration=0
        self.controls_list=[]
        self.enable_hint= True
        self.escapetrack_required=False
Example #10
0
    def __init__(self, show_id, show_params, root, canvas, showlist, pp_dir,
                 pp_home, pp_profile, command_callback):

        # init the common bits
        Show.base__init__(self, show_id, show_params, root, canvas, showlist,
                          pp_dir, pp_home, pp_profile, command_callback)

        # instatiatate the screen driver - used only to access enable and hide click areas
        self.sr = ScreenDriver()

        # create an instance of PathManager -  only used to parse the links.
        self.path = PathManager()

        self.allowed_links = ('play', 'pause', 'exit', 'return', 'null',
                              'no-command', 'stop')
        # init variables
        self.links = []
        self.track_timeout_timer = None
        self.show_timeout_timer = None
        self.next_track_signal = False
        self.current_track_ref = ''
        self.req_next = ''

        self.controlsmanager = ControlsManager()

        # Init variables special to this show
        self.poll_for_interval_timer = None
        self.interval_timer_signal = False
        self.waiting_for_interval = False
        self.interval_timer = None
        self.duration_timer = None

        self.end_trigger_signal = False
        self.next_track_signal = False
        self.previous_track_signal = False
        self.play_child_signal = False
        self.error_signal = False
        self.show_timeout_signal = False

        self.req_next = 'nil'
        self.state = 'closed'

        self.count = 0
        self.interval = 0
        self.duration = 0
        self.controls_list = []
        self.enable_hint = True
Example #11
0
    def track_ready_callback(self,enable_show_background):
        self.mon.trace(self, '')

        # get control bindings for this show
        self.controlsmanager=ControlsManager()
        if self.show_params['disable-controls'] == 'yes':
            self.controls_list=[]
        else:
            reason,message,self.controls_list= self.controlsmanager.get_controls(self.show_params['controls'])
            if reason=='error':
                self.mon.err(self,message)
                self.end('error',"error in controls")
                return
            # print '\nshow controls',self.show_params['controls']
   
            #merge controls from the track
            controls_text=self.current_player.get_links()
            # print 'current player controls',controls_text
            reason,message,track_controls=self.controlsmanager.parse_controls(controls_text)
            if reason == 'error':
                self.mon.err(self,message + " in track: "+ self.current_player.track_params['track-ref'])
                self.error_signal=True
                self.what_next_after_showing()
            self.controlsmanager.merge_controls(self.controls_list,track_controls)

        # show the show background done for every track but quick operation
        if enable_show_background is True:
            self.base_show_show_background()
        else:
            self.base_withdraw_show_background()
        # !!!!!!!!! withdraw the background from the parent show
        if self.previous_shower != None:
            self.previous_shower.base_withdraw_show_background()
            
        # close the player from the previous track
        if self.previous_player is not None:
            self.mon.trace(self, 'hiding previous: ' + self.mon.pretty_inst(self.previous_player))
            self.previous_player.hide()
            if self.previous_player.get_play_state() == 'showing':
                self.mon.trace(self,'closing previous: ' + self.mon.pretty_inst(self.previous_player))
                self.previous_player.close(self.closed_callback)
            else:
                self.mon.trace(self, 'previous is none')
                self.previous_player=None
class ArtShow(Show):
    """
        Automatically plays a set of tracks from a medialist. Does gapless and time of day trigger but little else.
    """

    # *******************
    # External interface
    # ********************

    def __init__(self, show_id, show_params, root, canvas, showlist, pp_dir,
                 pp_home, pp_profile, command_callback):

        # init the common bits
        Show.base__init__(self, show_id, show_params, root, canvas, showlist,
                          pp_dir, pp_home, pp_profile, command_callback)

        # delay in mS before next track is loaded after showing a track.
        # can be inceeased if animation is required
        self.load_delay = 5

        # Init variables for this show
        self.end_medialist_signal = False
        self.end_medialist_warning = False
        self.next_track_signal = False
        self.state = 'closed'
        self.req_next = ''
        self.next_player = None

    def play(self, end_callback, show_ready_callback, parent_kickback_signal,
             level, controls_list):
        self.mon.trace(self, self.show_params['show-ref'])
        Show.base_play(self, end_callback, show_ready_callback,
                       parent_kickback_signal, level, controls_list)

        # get the previous shower and player from calling show
        # Show.base_get_previous_player_from_parent(self)

        # and delete eggtimer started by the parent
        if self.previous_shower is not None:
            self.previous_shower.delete_eggtimer()

        self.wait_for_trigger()

# ********************************
# Respond to external events
# ********************************

    def exit(self):
        # set signal to stop the show when all  sub-shows and players have ended
        self.exit_signal = True
        # then stop track.
        if self.current_player is not None:
            self.current_player.input_pressed('stop')
        else:
            self.end('normal', 'ended by exit')

    # kill or error
    def terminate(self):
        self.terminate_signal = True
        if self.current_player is not None:
            self.ending_reason = 'killed'
            self.close_current_and_next()
        else:
            self.end('killed',
                     ' terminated with no shower or player to terminate')

# respond to key presses.

    def handle_input_event(self, symbol):
        Show.base_handle_input_event(self, symbol)

    def handle_input_event_this_show(self, symbol):
        operation = self.base_lookup_control(symbol, self.controls_list)
        self.do_operation(operation)

    def do_trigger_or_link(self, symbol, edge, source):
        pass

    # service the standard operations for this show
    def do_operation(self, operation):
        self.mon.trace(self, operation)
        # service the standard inputs for this show
        if operation == 'exit':
            self.exit()

        elif operation == 'stop':
            if self.level != 0:
                # not at top so stop the show
                self.user_stop_signal = True
                # and stop the track first
                if self.current_player is not None:
                    self.current_player.input_pressed('stop')
            else:
                # at top, just stop track if running
                if self.current_player is not None:
                    self.current_player.input_pressed('stop')

        elif operation == 'down':
            self.next()

        elif operation in ('pause', 'pause-on', 'pause-off', 'mute', 'unmute',
                           'go'):
            # pass down if show or track running.
            if self.current_player is not None:
                self.current_player.input_pressed(operation)

        elif operation in ('no-command', 'null'):
            return

        elif operation[0:4] == 'omx-' or operation[0:6] == 'mplay-':
            if self.current_player is not None:
                self.current_player.input_pressed(operation)

    def next(self):
        # stop track if running and set signal
        self.next_track_signal = True
        if self.current_player is not None:
            self.current_player.input_pressed('stop')

# ***************************
# Sequencing
# ***************************

    def wait_for_trigger(self):
        self.start_show()

    def start_show(self):
        self.load_first_track()

    # load the first track of the show
    def load_first_track(self):
        self.mon.trace(self, '')
        self.medialist.create_new_livelist()
        self.medialist.use_new_livelist()
        if self.medialist.start() is False:
            # print 'FIRST EMPTY'
            # list is empty - display a message for 5 secs and then retry
            Show.display_admin_message(self, self.show_params['empty-text'])
            self.canvas.after(5000, self.remove_list_empty_message)
        else:
            # otherwise load the first track
            # print "!!!!! artshow init first"
            # print 'after wait EMPTY'
            self.next_player = Show.base_init_selected_player(
                self, self.medialist.selected_track())
            if self.next_player is None:
                self.mon.err(
                    self, "Track Type cannot be played by this show: " +
                    self.medialist.selected_track()['type'])
                self.req_next = 'error'
                self.what_next()
            else:
                # messageplayer passes the text not a file name
                if self.medialist.selected_track()['type'] == 'message':
                    track_file = self.medialist.selected_track()['text']
                else:
                    track_file = Show.base_complete_path(
                        self,
                        self.medialist.selected_track()['location'])
                # print "!!!!! artshow load first ",track_file
                self.next_player.load(track_file,
                                      self.loaded_callback,
                                      enable_menu=False)
                self.wait_for_load()

    def remove_list_empty_message(self):
        Show.delete_admin_message(self)
        self.load_first_track()

    # start of the showing loop. Got here from the end of showing.
    def wait_for_load(self):
        # wait for load of next track and close of previous to complete
        # state after this is previous=None, current=closed or pause_at_end, next=loaded or load_failed
        # and is a good place to test for ending.
        # self.mon.trace(self,'')
        if self.next_player is not None:
            if self.next_player.get_play_state() == 'load-failed':
                self.req_next = 'error'
                self.what_next()
            else:
                if self.previous_player is None and self.next_player.get_play_state(
                ) == 'loaded':
                    self.mon.trace(self,
                                   ' - next is loaded and previous closed')
                    self.canvas.after(10, self.what_next)
                else:
                    self.canvas.after(50, self.wait_for_load)
        else:
            self.canvas.after(200, self.wait_for_load)

    def what_next(self):
        # do we need to end or restart, if so close the current, and unload the next, and wait
        # until next is unloaded and current has closed
        self.mon.trace(self, '')

        # terminate
        if self.terminate_signal is True:
            self.terminate_signal = False
            self.ending_reason = 'killed'
            self.close_current_and_next()

        elif self.req_next == 'error':
            self.req_next = ''
            # set what to do after closed or unloaded
            self.ending_reason = 'error'
            self.close_current_and_next()

        # used  for stopping show from other shows  etc.
        elif self.exit_signal is True:
            self.exit_signal = False
            self.stop_timers()
            self.ending_reason = 'exit'
            self.close_current_and_next()

        # user wants to stop the show
        elif self.user_stop_signal is True:
            self.user_stop_signal = False
            self.stop_timers()
            self.ending_reason = 'user-stop'
            self.close_current_and_next()

        elif self.medialist.length() == 0:
            self.load_first_track()

        # end of medialist
        elif self.end_medialist_signal is True:
            self.end_medialist_signal = False
            self.end_medialist_warning = False
            # test for ordered since medialist at end gives false positives for shuffle

            # repeat so go back to start
            if self.show_params['sequence'] == "ordered" and self.show_params[
                    'repeat'] == 'repeat':
                self.show_next_track()

            # single run so end
            elif self.show_params['sequence'] == "ordered" and self.show_params[
                    'repeat'] == 'single-run':
                self.ending_reason = 'end-of-medialist'
                self.close_current_and_next()

            else:
                # otherwise show the next track
                self.show_next_track()
        else:
            # otherwise show the next track
            self.show_next_track()

    def show_next_track(self):
        self.mon.trace(self, ' - SHUFFLE')
        self.previous_player = self.current_player
        self.current_player = self.next_player
        self.next_player = None
        self.mon.trace(
            self,
            'AFTER SHUFFLE n-c-p' + self.mon.pretty_inst(self.next_player) +
            ' ' + self.mon.pretty_inst(self.current_player) + ' ' +
            self.mon.pretty_inst(self.previous_player))
        self.mon.trace(self, 'showing track')
        if self.end_medialist_warning is True:
            self.end_medialist_signal = True
        self.current_player.show(self.track_ready_callback,
                                 self.finished_showing,
                                 self.closed_after_showing)
        # load the next after a wait to allow animation etc to be timely.
        self.canvas.after(self.load_delay, self.what_to_load_next)

    def finished_showing(self, reason, message):
        # showing has finished with 'pause at end', showing the next track will close it after next has started showing
        self.mon.trace(self, ' - pause at end')
        self.mon.log(
            self, "finished_showing - pause at end of showing with reason: " +
            reason + ' and message: ' + message)

        if self.current_player.play_state == 'show-failed':
            self.req_next = 'error'
            self.what_next()
        else:
            self.req_next = 'finished-player'
            self.wait_for_load()

    def closed_after_showing(self, reason, message):
        # showing has finished with closing of player but track instance is alive for hiding the x_content
        self.mon.trace(self, ' - closed after showing')
        self.mon.log(
            self, "closed_after_showing - Closed after showing with reason: " +
            reason + ' and message: ' + message)
        if self.current_player.play_state == 'show-failed':
            self.req_next = 'error'
            self.what_next()
        else:
            self.req_next = 'finished-player'
            self.wait_for_load()

    # pre-load the next track. Runs concurrently to show. Control goes nowhere after completion, success is detected from the states.
    def what_to_load_next(self):
        self.mon.trace(self, self.pretty_state())

        # closing down so don't load anything
        if self.ending_reason in ('killed', 'error'):
            return

        # wanting to exit so don't load just skip to what-next
        if self.terminate_signal is True or self.exit_signal is True or self.req_next == 'error':
            self.what_next()

        # has content of list been changed (replaced if it has, used for content of livelist)
        # print 'WHAT to load NEXT'
        self.medialist.create_new_livelist()

        # print result, self.medialist.new_length(),self.medialist.anon_length()
        if self.medialist.livelist_changed() is True:
            # print 'ITS CHANGED'
            self.ending_reason = 'change-medialist'
            self.close_current_and_next()
        else:
            # get the next track and init player
            self.medialist.next(self.show_params['sequence'])
            Show.delete_admin_message(self)
            if self.medialist.at_end() is True:
                self.end_medialist_warning = True
            # print "!!!!! artshow init next "
            self.next_player = Show.base_init_selected_player(
                self, self.medialist.selected_track())
            if self.next_player is None:
                self.mon.err(
                    self, "Track Type cannot be played by this show: " +
                    self.medialist.selected_track()['type'])
                self.req_next = 'error'
                self.what_next()
            else:
                # load the next track while current is showing
                # messageplayer passes the text not a file name
                if self.medialist.selected_track()['type'] == 'message':
                    track_file = self.medialist.selected_track()['text']
                else:
                    track_file = Show.base_complete_path(
                        self,
                        self.medialist.selected_track()['location'])
                # print "!!!!! artshow load next ",track_file
                self.mon.trace(self, track_file)
                self.next_player.load(track_file,
                                      self.loaded_callback,
                                      enable_menu=False)

    def loaded_callback(self, reason, message):
        self.mon.trace(
            self, ' - load complete with reason: ' + reason + '  message: ' +
            message)

##    def end_close_previous(self,reason,message):
##        self.mon.log(self,"end_close_previous - Previous closed with reason: "+reason+ ' and message: '+ message)
##        self.mon.trace(self,' - previous closed')
##        self.previous_player=None    # safer to delete the player here rather than in player as play-state is read elsewhere.

    def close_current_and_next(self):
        # end of show so close current, next and previous before ending
        if self.current_player is not None and self.current_player.get_play_state(
        ) == 'showing':
            self.mon.trace(self,
                           ' - closing_current from ' + self.ending_reason)
            self.current_player.close(self.end_close_current)
        if self.next_player is not None:
            if self.next_player.get_play_state() not in ('unloaded', 'closed',
                                                         'initialised',
                                                         'load-failed'):
                self.mon.trace(self,
                               '- unloading next from ' + self.ending_reason)
                self.next_player.unload()
        self.wait_for_end()

    def end_close_current(self, reason, message):
        self.mon.log(
            self, "Current track closed with reason: " + reason +
            ' and message: ' + message)
        self.mon.trace(self, ' - current closed')
        self.current_player = None  # safer to delete the player here rather than in player as play-state is read elsewhere.

    # previous=None at this point,just wait for loading and closing to complete then end
    def wait_for_end(self):
        self.mon.trace(self, self.pretty_state())
        ok_to_end = 0
        if self.current_player is None or self.current_player.get_play_state(
        ) == 'closed':
            self.current_player = None
            ok_to_end += 1
        if self.next_player is None or self.next_player.get_play_state() in (
                'initialised', 'unloaded', 'load-failed'):
            self.next_player = None
            ok_to_end += 1
        if ok_to_end != 2:
            self.canvas.after(50, self.wait_for_end)
        else:
            self.mon.trace(self,
                           ' - next and current closed ' + self.ending_reason)

            if self.ending_reason == 'killed':
                self.base_close_previous()

            elif self.ending_reason == 'error':
                self.base_close_previous()

            elif self.ending_reason == 'exit':
                self.base_close_previous()

            elif self.ending_reason == 'end-trigger':
                self.state = 'waiting'
                self.wait_for_trigger()

            elif self.ending_reason in ('user-stop', 'end-of-medialist'):
                self.end('normal', "show quit by user or natural end")

            elif self.ending_reason == 'change-medialist':
                self.load_first_track()
            else:
                self.mon.err(self,
                             "Unhandled ending_reason: " + self.ending_reason)
                self.end('error',
                         "Unhandled ending_reason: " + self.ending_reason)

    def track_ready_callback(self, enable_show_background):
        self.mon.trace(self, '')

        # get control bindings for this show
        self.controlsmanager = ControlsManager()
        if self.show_params['disable-controls'] == 'yes':
            self.controls_list = []
        else:
            reason, message, self.controls_list = self.controlsmanager.get_controls(
                self.show_params['controls'])
            if reason == 'error':
                self.mon.err(self, message)
                self.end('error', "error in controls: " + message)
                return
            # print '\nshow controls',self.show_params['controls']

            #merge controls from the track
            controls_text = self.current_player.get_links()
            # print 'current player controls',controls_text
            reason, message, track_controls = self.controlsmanager.parse_controls(
                controls_text)
            if reason == 'error':
                self.mon.err(
                    self, message + " in track: " +
                    self.current_player.track_params['track-ref'])
                self.error_signal = True
                self.what_next_after_showing()
            self.controlsmanager.merge_controls(self.controls_list,
                                                track_controls)

        # show the show background done for every track but quick operation
        if enable_show_background is True:
            self.base_show_show_background()
        else:
            self.base_withdraw_show_background()
        # !!!!!!!!! withdraw the background from the parent show
        if self.previous_shower != None:
            self.previous_shower.base_withdraw_show_background()

        # close the player from the previous track
        if self.previous_player is not None:
            self.mon.trace(
                self, 'hiding previous: ' +
                self.mon.pretty_inst(self.previous_player))
            self.previous_player.hide()
            if self.previous_player.get_play_state() == 'showing':
                self.mon.trace(
                    self, 'closing previous: ' +
                    self.mon.pretty_inst(self.previous_player))
                self.previous_player.close(self.closed_callback)
            else:
                self.mon.trace(self, 'previous is none')
                self.previous_player = None

    def closed_callback(self, reason, message):
        self.mon.trace(self, reason + ' ' + message)
        self.previous_player = None

    def base_close_previous(self):
        self.mon.log(
            self, self.show_params['show-ref'] + ' ' + str(self.show_id) +
            ": base close previous")
        self.mon.trace(self, '')
        # close the player from the previous track
        if self.previous_player is not None:
            self.mon.trace(
                self, 'previous is not None ' +
                self.mon.pretty_inst(self.previous_player))
            if self.previous_player.get_play_state() == 'showing':
                # showing or frozen
                self.mon.trace(
                    self, 'closing previous ' +
                    self.mon.pretty_inst(self.previous_player))
                self.previous_player.close(self._base_close_previous_callback)
            else:
                self.mon.trace(self, 'previous is not showing')
                self.previous_player.hide()
                self.previous_player = None
                self.end(self.ending_reason, '')
        else:
            self.mon.trace(self, 'previous is None')
            self.end(self.ending_reason, '')

    def _base_close_previous_callback(self, status, message):
        self.mon.trace(
            self, ' previous is None  - was ' +
            self.mon.pretty_inst(self.previous_player))
        self.previous_player.hide()
        self.previous_player = None
        self.end(self.ending_reason, '')

# ***************************
# end of show
# ***************************

    def end(self, reason, message):
        Show.delete_admin_message(self)
        self.base_withdraw_show_background()
        self.base_delete_show_background()
        self.mon.log(self, "Ending Artshow: " + self.show_params['show-ref'])
        self.end_callback(self.show_id, reason, message)
        self = None

    def stop_timers(self):
        pass
        #if self.duration_timer is not None:
        #self.canvas.after_cancel(self.duration_timer)
        #self.duration_timer=None
        # clear outstanding time of day events for this show
        # self.tod.clear_times_list(id(self))

# ***************************
# debug
# ***************************

    def pretty_state(self):
        state = '  n-c-p   -  '
        if self.next_player is not None:
            state += self.next_player.get_play_state()
        else:
            state += 'None'
        if self.current_player is not None:
            state += self.current_player.get_play_state()
        else:
            state += 'None'
        if self.previous_player is not None:
            state += self.previous_player.get_play_state()
        else:
            state += 'None'
        return state
    def __init__(self):
        
        self.pipresents_issue="1.2"
        self.nonfull_window_width = 0.6 # proportion of width
        self.nonfull_window_height= 0.6 # proportion of height
        self.nonfull_window_x = 0 # position of top left corner
        self.nonfull_window_y=0   # position of top left corner
        
        StopWatch.global_enable=False

#****************************************
# Initialisation
# ***************************************
        # get command line options
        self.options=command_options()

        # get pi presents code directory
        pp_dir=sys.path[0]
        self.pp_dir=pp_dir
        
        if not os.path.exists(pp_dir+"/pipresents.py"):
            tkMessageBox.showwarning("Pi Presents","Bad Application Directory")
            exit()

        
        #Initialise logging
        Monitor.log_path=pp_dir
        self.mon=Monitor()
        self.mon.on()
        if self.options['debug']==True:
            Monitor.global_enable=True
        else:
            Monitor.global_enable=False
 
        self.mon.log (self, "Pi Presents is starting")
        self.mon.log (self," OS and separator:" + os.name +'  ' + os.sep)
        self.mon.log(self,"sys.path[0] -  location of code: "+sys.path[0])
        # self.mon.log(self,"os.getenv('HOME') -  user home directory (not used): " + os.getenv('HOME'))
        # self.mon.log(self,"os.path.expanduser('~') -  user home directory: " + os.path.expanduser('~'))

        # optional other classes used
        self.ppio=None
        self.tod=None
         
        #get profile path from -p option
        if self.options['profile']<>"":
            self.pp_profile_path="/pp_profiles/"+self.options['profile']
        else:
            self.pp_profile_path = "/pp_profiles/pp_profile"
        
       #get directory containing pp_home from the command,
        if self.options['home'] =="":
            home = os.path.expanduser('~')+ os.sep+"pp_home"
        else:
            home = self.options['home'] + os.sep+ "pp_home"         
        self.mon.log(self,"pp_home directory is: " + home)
        
        #check if pp_home exists.
        # try for 10 seconds to allow usb stick to automount
        # fall back to pipresents/pp_home
        self.pp_home=pp_dir+"/pp_home"
        found=False
        for i in range (1, 10):
            self.mon.log(self,"Trying pp_home at: " + home +  " (" + str(i)+')')
            if os.path.exists(home):
                found=True
                self.pp_home=home
                break
            time.sleep (1)
        if found==True:
            self.mon.log(self,"Found Requested Home Directory, using pp_home at: " + home)
        else:    
            self.mon.log(self,"FAILED to find requested home directory, using default to display error message: " + self.pp_home)


        #check profile exists, if not default to error profile inside pipresents
        self.pp_profile=self.pp_home+self.pp_profile_path
        if os.path.exists(self.pp_profile):
            self.mon.log(self,"Found Requested profile - pp_profile directory is: " + self.pp_profile)
        else:
            self.pp_profile=pp_dir+"/pp_home/pp_profiles/pp_profile"   
            self.mon.log(self,"FAILED to find requested profile, using default to display error message: pp_profile")
        
        if self.options['verify']==True:
            val =Validator()
            if  val.validate_profile(None,pp_dir,self.pp_home,self.pp_profile,self.pipresents_issue,False) == False:
                tkMessageBox.showwarning("Pi Presents","Validation Failed")
                exit()
                
        # open the resources
        self.rr=ResourceReader()
        # read the file, done once for all the other classes to use.
        if self.rr.read(pp_dir,self.pp_home,self.pp_profile)==False:
            self.end('error','cannot find resources.cfg')            

        #initialise and read the showlist in the profile
        self.showlist=ShowList()
        self.showlist_file= self.pp_profile+ "/pp_showlist.json"
        if os.path.exists(self.showlist_file):
            self.showlist.open_json(self.showlist_file)
        else:
            self.mon.err(self,"showlist not found at "+self.showlist_file)
            self.end('error','showlist not found')

        # check profile and Pi Presents issues are compatible
        if float(self.showlist.sissue())<>float(self.pipresents_issue):
            self.mon.err(self,"Version of profile " + self.showlist.sissue() + " is not  same as Pi Presents, must exit")
            self.end('error','wrong version of profile')
 
        # get the 'start' show from the showlist
        index = self.showlist.index_of_show('start')
        if index >=0:
            self.showlist.select(index)
            self.starter_show=self.showlist.selected_show()
        else:
            self.mon.err(self,"Show [start] not found in showlist")
            self.end('error','start show not found')

        
# ********************
# SET UP THE GUI
# ********************
        #turn off the screenblanking and saver
        if self.options['noblank']==True:
            call(["xset","s", "off"])
            call(["xset","s", "-dpms"])

        self.root=Tk()   
       
        self.title='Pi Presents - '+ self.pp_profile
        self.icon_text= 'Pi Presents'
        self.root.title(self.title)
        self.root.iconname(self.icon_text)
        self.root.config(bg='black')
        
        # get size of the screen
        self.screen_width = self.root.winfo_screenwidth()
        self.screen_height = self.root.winfo_screenheight()

        # set window dimensions and decorations
        if self.options['fullscreen']==True:

            self.root.attributes('-fullscreen', True)
            os.system('unclutter &')
            self.window_width=self.screen_width
            self.window_height=self.screen_height
            self.window_x=0
            self.window_y=0  
            self.root.geometry("%dx%d%+d%+d"  % (self.window_width,self.window_height,self.window_x,self.window_y))
            self.root.attributes('-zoomed','1')
        else:
            self.window_width=int(self.screen_width*self.nonfull_window_width)
            self.window_height=int(self.screen_height*self.nonfull_window_height)
            self.window_x=self.nonfull_window_x
            self.window_y=self.nonfull_window_y
            self.root.geometry("%dx%d%+d%+d" % (self.window_width,self.window_height,self.window_x,self.window_y))

            
        #canvas covers the whole window
        self.canvas_height=self.screen_height
        self.canvas_width=self.screen_width
        
        # make sure focus is set.
        self.root.focus_set()

        #define response to main window closing.
        self.root.protocol ("WM_DELETE_WINDOW", self.exit_pressed)

        #setup a canvas onto which will be drawn the images or text
        self.canvas = Canvas(self.root, bg='black')

        self.canvas.config(height=self.canvas_height,
                                       width=self.canvas_width,
                                       highlightthickness=0)
        # self.canvas.pack()
        self.canvas.place(x=0,y=0)

        self.canvas.focus_set()

                
# ****************************************
# INITIALISE THE INPUT DRIVERS
# ****************************************

        # looks after bindings between symbolic names and internal operations
        controlsmanager=ControlsManager()
        if controlsmanager.read(pp_dir,self.pp_home,self.pp_profile)==False:
                self.end('error','cannot find or error in controls.cfg.cfg')
        else:
            controlsmanager.parse_defaults()

        # each driver takes a set of inputs, binds them to symboic names
        # and sets up a callback which returns the symbolic name when an input event occurs/

        # use keyboard driver to bind keys to symbolic names and to set up callback
        kbd=KbdDriver()
        if kbd.read(pp_dir,self.pp_home,self.pp_profile)==False:
                self.end('error','cannot find or error in keys.cfg')
        kbd.bind_keys(self.root,self.input_pressed)

        self.sr=ScreenDriver()
        # read the screen click area config file
        if self.sr.read(pp_dir,self.pp_home,self.pp_profile)==False:
            self.end('error','cannot find screen.cfg')

        # create click areas on the canvas, must be polygon as outline rectangles are not filled as far as find_closest goes
        reason,message = self.sr.make_click_areas(self.canvas,self.input_pressed)
        if reason=='error':
            self.mon.err(self,message)
            self.end('error',message)


# ****************************************
# INITIALISE THE APPLICATION AND START
# ****************************************
        self.shutdown_required=False
        
        #kick off GPIO if enabled by command line option
        if self.options['gpio']==True:
            from pp_gpio import PPIO
            # initialise the GPIO
            self.ppio=PPIO()
            # PPIO.gpio_enabled=False
            if self.ppio.init(pp_dir,self.pp_home,self.pp_profile,self.canvas,50,self.gpio_pressed)==False:
                self.end('error','gpio error')
                
            # and start polling gpio
            self.ppio.poll()

        #kick off the time of day scheduler
        self.tod=TimeOfDay()
        self.tod.init(pp_dir,self.pp_home,self.canvas,500)
        self.tod.poll()


        # Create list of start shows initialise them and then run them
        self.run_start_shows()

        #start tkinter
        self.root.mainloop( )
Example #14
0
class MenuShow(Show):
    def __init__(self, show_id, show_params, root, canvas, showlist, pp_dir, pp_home, pp_profile, command_callback):

        """
            show_id - index of the top level show caling this (for debug only)
            show_params - dictionary section for the menu
            canvas - the canvas that the menu is to be written on
            showlist  - the showlist
            pp_dir - Pi Presents directory
            pp_home - Pi presents data_home directory
            pp_profile - Pi presents profile directory
        """

        # init the common bits
        Show.base__init__(
            self, show_id, show_params, root, canvas, showlist, pp_dir, pp_home, pp_profile, command_callback
        )

        # instatiatate the screen driver - used only to access enable and hide click areas
        self.sr = ScreenDriver()

        self.controlsmanager = ControlsManager()

        # init variables
        self.show_timeout_timer = None
        self.track_timeout_timer = None
        self.next_track_signal = False
        self.next_track = None
        self.menu_index = 0
        self.menu_showing = True
        self.req_next = ""

    def play(self, end_callback, show_ready_callback, parent_kickback_signal, level, controls_list):
        """ displays the menu 
              end_callback - function to be called when the menu exits
              show_ready_callback - callback when menu is ready to display (not used)
              level is 0 when the show is top level (run from [start] or from show control)
              parent_kickback_signal  - not used other than it being passed to a show
        """
        # need to instantiate the medialist here as not using gapshow
        self.medialist = MediaList("ordered")

        Show.base_play(self, end_callback, show_ready_callback, parent_kickback_signal, level, controls_list)

        self.mon.trace(self, self.show_params["show-ref"])

        # parse the show and track timeouts
        reason, message, self.show_timeout = Show.calculate_duration(self, self.show_params["show-timeout"])
        if reason == "error":
            self.mon.err(self, "Show Timeout has bad time: " + self.show_params["show-timeout"])
            self.end("error", "show timeout, bad time")

        reason, message, self.track_timeout = Show.calculate_duration(self, self.show_params["track-timeout"])
        if reason == "error":
            self.mon.err(self, "Track Timeout has bad time: " + self.show_params["track-timeout"])
            self.end("error", "track timeout, bad time")

        # and delete eggtimer
        if self.previous_shower is not None:
            self.previous_shower.delete_eggtimer()

        # and display the menu
        self.do_menu_track()

    # ********************
    # respond to inputs.
    # ********************

    # exit received from another concurrent show
    def exit(self):
        self.stop_timers()
        Show.base_exit(self)

    #  show timeout happened
    def show_timeout_stop(self):
        self.stop_timers()
        Show.base_show_timeout_stop(self)

    # terminate Pi Presents
    def terminate(self):
        self.stop_timers()
        Show.base_terminate(self)

    def handle_input_event(self, symbol):
        Show.base_handle_input_event(self, symbol)

    def handle_input_event_this_show(self, symbol):
        # menushow has only internal operation
        operation = self.base_lookup_control(symbol, self.controls_list)
        self.do_operation(operation)

    def do_operation(self, operation):
        # service the standard inputs for this show

        self.mon.trace(self, operation)
        if operation == "exit":
            self.exit()

        elif operation == "stop":
            self.stop_timers()
            if self.current_player is not None:
                if self.menu_showing is True and self.level != 0:
                    # if quiescent then set signal to stop the show when track has stopped
                    self.user_stop_signal = True
                self.current_player.input_pressed("stop")

        elif operation in ("up", "down"):
            # stop show timeout
            if self.show_timeout_timer is not None:
                self.canvas.after_cancel(self.show_timeout_timer)
                # and start it again
                if self.show_timeout != 0:
                    self.show_timeout_timer = self.canvas.after(self.show_timeout * 1000, self.show_timeout_stop)
            if operation == "up":
                self.previous()
            else:
                self.next()

        elif operation == "play":
            self.next_track_signal = True
            self.next_track = self.medialist.selected_track()
            self.current_player.stop()

            # cancel show timeout
            if self.show_timeout_timer is not None:
                self.canvas.after_cancel(self.show_timeout_timer)
                self.show_timeout_timer = None

            # stop current track (the menuplayer) if running or just start the next track
            if self.current_player is not None:
                self.current_player.input_pressed("stop")
            else:
                self.what_next_after_showing()

        elif operation in ("no-command", "null"):
            return

        elif operation == "pause":
            if self.current_player is not None:
                self.current_player.input_pressed(operation)

        elif operation[0:4] == "omx-" or operation[0:6] == "mplay-" or operation[0:5] == "uzbl-":
            if self.current_player is not None:
                self.current_player.input_pressed(operation)

    def next(self):
        # remove highlight
        if self.current_player.__class__.__name__ == "MenuPlayer":
            self.current_player.highlight_menu_entry(self.menu_index, False)
            self.medialist.next("ordered")
            if self.menu_index == self.menu_length - 1:
                self.menu_index = 0
            else:
                self.menu_index += 1
            # and highlight the new entry
            self.current_player.highlight_menu_entry(self.menu_index, True)

    def previous(self):
        # remove highlight
        if self.current_player.__class__.__name__ == "MenuPlayer":
            self.current_player.highlight_menu_entry(self.menu_index, False)
            if self.menu_index == 0:
                self.menu_index = self.menu_length - 1
            else:
                self.menu_index -= 1
            self.medialist.previous("ordered")
            # and highlight the new entry
            self.current_player.highlight_menu_entry(self.menu_index, True)

    # *********************
    # Sequencing
    # *********************

    def track_timeout_callback(self):
        self.do_operation("stop")

    def do_menu_track(self):
        self.menu_showing = True
        self.mon.trace(self, "")
        # start show timeout alarm if required
        if self.show_timeout != 0:
            self.show_timeout_timer = self.canvas.after(self.show_timeout * 1000, self.show_timeout_stop)

        # init the index used to hiighlight the selected menu entry by menuplayer
        self.menu_index = 0

        index = self.medialist.index_of_track(self.show_params["menu-track-ref"])
        if index == -1:
            self.mon.err(self, "'menu-track' not in medialist: " + self.show_params["menu-track-ref"])
            self.end("error", "menu-track not in medialist: ")
            return

        # make the medialist available to the menuplayer for cursor scrolling
        self.show_params["medialist_obj"] = self.medialist

        # load the menu track
        self.start_load_show_loop(self.medialist.track(index))

    # *********************
    # Playing show or track loop
    # *********************

    def start_load_show_loop(self, selected_track):
        # shuffle players
        Show.base_shuffle(self)
        self.mon.trace(self, "")
        self.display_eggtimer()

        # get control bindings for this show
        # needs to be done for each track as track can override the show controls
        if self.show_params["disable-controls"] == "yes":
            self.controls_list = []
        else:
            reason, message, self.controls_list = self.controlsmanager.get_controls(self.show_params["controls"])
            if reason == "error":
                self.mon.err(self, message)
                self.end("error", "error in controls")
                return

        # load the track or show
        Show.base_load_track_or_show(self, selected_track, self.what_next_after_load, self.end_shower, False)

    # track has loaded (menu or otherwise) so show it.
    def what_next_after_load(self, status, message):
        # get the calculated length of the menu for the loaded menu track
        if self.current_player.__class__.__name__ == "MenuPlayer":
            if self.medialist.display_length() == 0:
                self.req_next = "error"
                self.what_next_after_showing()
                return
            self.medialist.start()
            self.menu_index = 0
            self.menu_length = self.current_player.menu_length
            self.current_player.highlight_menu_entry(self.menu_index, True)
        self.mon.trace(self, " - load complete with status: " + status + "  message: " + message)
        if self.current_player.play_state == "load-failed":
            self.req_next = "error"
            self.what_next_after_showing()

        else:
            if (
                self.show_timeout_signal is True
                or self.terminate_signal is True
                or self.exit_signal is True
                or self.user_stop_signal is True
            ):
                self.what_next_after_showing()
            else:
                self.mon.trace(self, "")
                self.current_player.show(self.track_ready_callback, self.finished_showing, self.closed_after_showing)

    def finished_showing(self, reason, message):
        # showing has finished with 'pause at end', showing the next track will close it after next has started showing
        self.mon.trace(self, "")
        self.mon.log(self, "pause at end of showing track with reason: " + reason + " and message: " + message)
        self.sr.hide_click_areas(self.controls_list)
        if self.current_player.play_state == "show-failed":
            self.req_next = "error"
        else:
            self.req_next = "finished-player"
        self.what_next_after_showing()

    def closed_after_showing(self, reason, message):
        # showing has finished with closing of player but track instance is alive for hiding the x_content
        self.mon.trace(self, "")
        self.mon.log(self, "Closed after showing track with reason: " + reason + " and message: " + message)
        self.sr.hide_click_areas(self.controls_list)
        if self.current_player.play_state == "show-failed":
            self.req_next = "error"
        else:
            self.req_next = "closed-player"
        self.what_next_after_showing()

    # subshow or child show has ended
    def end_shower(self, show_id, reason, message):
        self.mon.log(
            self,
            self.show_params["show-ref"]
            + " "
            + str(self.show_id)
            + ": Returned from shower with "
            + reason
            + " "
            + message,
        )
        self.sr.hide_click_areas(self.controls_list)
        self.req_next = reason
        Show.base_end_shower(self)
        self.what_next_after_showing()

    # at the end of a track check for terminations else re-display the menu
    def what_next_after_showing(self):
        self.mon.trace(self, "")
        # cancel track timeout timer
        if self.track_timeout_timer is not None:
            self.canvas.after_cancel(self.track_timeout_timer)
            self.track_timeout_timer = None

        # need to terminate?
        if self.terminate_signal is True:
            self.terminate_signal = False
            # set what to do when closed or unloaded
            self.ending_reason = "killed"
            Show.base_close_or_unload(self)

        elif self.req_next == "error":
            self.req_next = ""
            # set what to do after closed or unloaded
            self.ending_reason = "error"
            Show.base_close_or_unload(self)

        # show timeout
        elif self.show_timeout_signal is True:
            self.show_timeout_signal = False
            # set what to do when closed or unloaded
            self.ending_reason = "show-timeout"
            Show.base_close_or_unload(self)

        # used by exit for stopping show from other shows.
        elif self.exit_signal is True:
            self.exit_signal = False
            self.ending_reason = "exit"
            Show.base_close_or_unload(self)

        # user wants to stop
        elif self.user_stop_signal is True:
            self.user_stop_signal = False
            self.ending_reason = "user-stop"
            Show.base_close_or_unload(self)

        elif self.next_track_signal is True:
            self.next_track_signal = False
            self.menu_showing = False
            # start timeout for the track if required
            if self.track_timeout != 0:
                self.track_timeout_timer = self.canvas.after(self.track_timeout * 1000, self.track_timeout_callback)
            self.start_load_show_loop(self.next_track)

        else:
            # no stopping the show required so re-display the menu
            self.do_menu_track()

    # *********************
    # Interface with other shows/players to reduce black gaps
    # *********************

    # called just before a track is shown to remove the  previous track from the screen
    # and if necessary close it
    def track_ready_callback(self, enable_show_background):
        self.delete_eggtimer()

        if self.show_params["disable-controls"] != "yes":
            # merge controls from the track
            controls_text = self.current_player.get_links()
            reason, message, track_controls = self.controlsmanager.parse_controls(controls_text)
            if reason == "error":
                self.mon.err(self, message + " in track: " + self.current_player.track_params["track-ref"])
                self.req_next = "error"
                self.what_next_after_showing()
            self.controlsmanager.merge_controls(self.controls_list, track_controls)

        self.sr.enable_click_areas(self.controls_list)

        Show.base_track_ready_callback(self, enable_show_background)

    # callback from begining of a subshow, provide previous shower player to called show
    def subshow_ready_callback(self):
        return Show.base_subshow_ready_callback(self)

    # *********************
    # Ending the show
    # *********************

    def end(self, reason, message):
        self.stop_timers()
        Show.base_end(self, reason, message)

    def stop_timers(self):
        if self.track_timeout_timer is not None:
            self.canvas.after_cancel(self.track_timeout_timer)
            self.track_timeout_timer = None
        if self.show_timeout_timer is not None:
            self.canvas.after_cancel(self.show_timeout_timer)
            self.show_timeout_timer = None
Example #15
0
    def play(self,
             show_id,
             end_callback,
             ready_callback,
             top=False,
             command='nil'):
        """ starts the hyperlink show at start-track 
              end_callback - function to be called when the show exits
              ready_callback - callback when event-show is ready to display its forst track (not used?)
              top is True when the show is top level (run from [start] or from show control)
              command is not used
        """

        #instantiate arguments
        self.show_id = show_id
        self.end_callback = end_callback
        self.ready_callback = ready_callback
        self.top = top
        self.command = command

        # check data files are available.
        self.medialist_file = self.pp_profile + "/" + self.show_params[
            'medialist']
        if not os.path.exists(self.medialist_file):
            self.mon.err(self,
                         "Medialist file not found: " + self.medialist_file)
            self.end('error', "Medialist file not found")

        #create a medialist object for the hyperlinkshow and read the file into it.
        self.medialist = MediaList()
        if self.medialist.open_list(self.medialist_file,
                                    self.showlist.sissue()) == False:
            self.mon.err(self, "Version of medialist different to Pi Presents")
            self.end('error', "Version of medialist different to Pi Presents")

        #get controls for this show if top level
        controlsmanager = ControlsManager()
        if self.top == True:
            self.controls_list = controlsmanager.default_controls()
            # and merge in controls from profile
            self.controls_list = controlsmanager.merge_show_controls(
                self.controls_list, self.show_params['controls'])

        # read show  links and destinations
        self.first_track_ref = self.show_params['first-track-ref']
        self.home_track_ref = self.show_params['home-track-ref']
        self.timeout_track_ref = self.show_params['timeout-track-ref']

        # state variables and signals
        self.end_hyperlinkshow_signal = False
        self.egg_timer = None
        self.next_track_signal = False
        self.next_track_ref = ''
        self.current_track_ref = ''
        self.current_track_type = ''

        # ready callback for show
        if self.ready_callback <> None:
            self.ready_callback()

        self.canvas.delete('pp-content')
        self.canvas.config(bg='black')

        self.do_first_track()
Example #16
0
class GapShow(Show):
    """
    this is the parent class of mediashow and liveshow
    The two derived clases just select the appropriate medialist from pp_medialist and pp_livelist
    the parents control the monitoring
    """

    # *******************
    # External interface
    # ********************

    def __init__(self, show_id, show_params, root, canvas, showlist, pp_dir,
                 pp_home, pp_profile, command_callback):

        # init the common bits
        Show.base__init__(self, show_id, show_params, root, canvas, showlist,
                          pp_dir, pp_home, pp_profile, command_callback)

        # instatiatate the screen driver - used only to access enable and hide click areas
        self.sr = ScreenDriver()

        self.controlsmanager = ControlsManager()

        # Init variables special to this show
        self.poll_for_interval_timer = None
        self.interval_timer_signal = False
        self.waiting_for_interval = False
        self.interval_timer = None
        self.duration_timer = None

        self.end_trigger_signal = False
        self.next_track_signal = False
        self.previous_track_signal = False
        self.play_child_signal = False
        self.error_signal = False
        self.show_timeout_signal = False

        self.req_next = 'nil'
        self.state = 'closed'

        self.count = 0
        self.interval = 0
        self.duration = 0
        self.controls_list = []
        self.enable_hint = True

    def play(self, end_callback, show_ready_callback, parent_kickback_signal,
             level, controls_list):
        self.mon.newline(3)
        self.mon.trace(self, self.show_params['show-ref'])

        Show.base_play(self, end_callback, show_ready_callback,
                       parent_kickback_signal, level, controls_list)

        # unpack show parameters

        reason, message, self.show_timeout = Show.calculate_duration(
            self, self.show_params['show-timeout'])
        if reason == 'error':
            self.mon.err(
                self, 'ShowTimeout has bad time: ' +
                self.show_params['show-timeout'])
            self.end(
                'error', 'ShowTimeout has bad time: ' +
                self.show_params['show-timeout'])

        self.track_count_limit = int(self.show_params['track-count-limit'])

        reason, message, self.interval = Show.calculate_duration(
            self, self.show_params['interval'])
        if reason == 'error':
            self.mon.err(
                self, 'Interval has bad time: ' + self.show_params['interval'])
            self.end('error',
                     'Interval has bad time: ' + self.show_params['interval'])

        # delete eggtimer started by the parent
        if self.previous_shower is not None:
            self.previous_shower.delete_eggtimer()

        self.start_show()

# ********************************
# Respond to external events
# ********************************

# exit received from another concurrent show

    def exit(self):
        Show.base_exit(self)

    # terminate Pi Presents
    def terminate(self):
        Show.base_terminate(self)

# respond to input events

    def handle_input_event(self, symbol):
        Show.base_handle_input_event(self, symbol)

    def handle_input_event_this_show(self, symbol):
        #  check symbol against mediashow triggers
        if self.state == 'waiting' and self.show_params[
                'trigger-start-type'] in (
                    'input', 'input-persist'
                ) and symbol == self.show_params['trigger-start-param']:
            self.mon.stats(self.show_params['type'],
                           self.show_params['show-ref'],
                           self.show_params['title'], 'start trigger', '', '',
                           '')
            Show.delete_admin_message(self)
            self.start_list()

        elif self.state == 'playing' and self.show_params[
                'trigger-end-type'] == 'input' and symbol == self.show_params[
                    'trigger-end-param']:
            self.end_trigger_signal = True
            if self.shower is not None:
                self.shower.do_operation('stop')
            elif self.current_player is not None:
                self.current_player.input_pressed('stop')

        elif self.state == 'playing' and self.show_params[
                'trigger-next-type'] == 'input' and symbol == self.show_params[
                    'trigger-next-param']:
            self.mon.stats(self.show_params['type'],
                           self.show_params['show-ref'],
                           self.show_params['title'], 'next trigger', '', '',
                           '')
            self.next()
        else:
            # event is not a trigger so must be internal operation
            operation = self.base_lookup_control(symbol, self.controls_list)
            if operation != '':
                self.do_operation(operation)

    # overrides base
    # service the standard operations for this show
    def do_operation(self, operation):
        # print 'do_operation ',operation
        self.mon.trace(self, operation)
        if operation == 'exit':
            self.exit()

        elif operation == 'stop':
            if self.level != 0:
                # not at top so stop the show
                self.user_stop_signal = True
                # and stop the track first
                if self.current_player is not None:
                    self.current_player.input_pressed('stop')
            else:
                # at top, just stop track if running
                if self.current_player is not None:
                    self.current_player.input_pressed('stop')

        elif operation == 'up' and self.state == 'playing':
            # print '\nUP'
            self.previous()

        elif operation == 'down' and self.state == 'playing':
            self.next()

        elif operation == 'play':
            # use 'play' to start child if state=playing or to trigger the show if waiting for trigger
            if self.state == 'playing':
                if self.show_params['child-track-ref'] != '':
                    # set a signal because must stop current track before running child show
                    self.play_child_signal = True
                    self.child_track_ref = self.show_params['child-track-ref']
                    # and stop the current track if its running
                    if self.current_player is not None:
                        self.current_player.input_pressed('stop')
            else:
                if self.state == 'waiting':
                    self.mon.stats(self.show_params['type'],
                                   self.show_params['show-ref'],
                                   self.show_params['title'], 'start trigger',
                                   '', '', '')
                    Show.delete_admin_message(self)
                    self.start_list()

        elif operation == 'pause':
            if self.current_player is not None:
                self.current_player.input_pressed('pause')

        elif operation in ('no-command', 'null'):
            return

        # if the operation is omxplayer mplayer or uzbl runtime control then pass it to player if running
        elif operation[0:4] == 'omx-' or operation[
                0:6] == 'mplay-' or operation[0:5] == 'uzbl-':
            if self.current_player is not None:
                self.current_player.input_pressed(operation)

    def next(self):
        # stop track if running and set signal
        self.next_track_signal = True
        if self.shower is not None:
            self.shower.do_operation('stop')
        else:
            if self.current_player is not None:
                self.current_player.input_pressed('stop')

    def previous(self):
        self.previous_track_signal = True
        if self.shower is not None:
            self.shower.do_operation('stop')
        else:
            if self.current_player is not None:
                self.current_player.input_pressed('stop')

# ***************************
# Show sequencing
# ***************************

    def start_show(self):
        # initial direction from parent show

        self.kickback_for_next_track = self.parent_kickback_signal
        # print '\n\ninital KICKBACK from parent', self.kickback_for_next_track

        # start duration timer
        if self.show_timeout != 0:
            # print 'set alarm ', self.show_timeout
            self.duration_timer = self.canvas.after(self.show_timeout * 1000,
                                                    self.show_timeout_stop)

        self.first_list = True

        # and start the first list of the show
        self.wait_for_trigger()

    def wait_for_trigger(self):

        # wait for trigger sets the state to waiting so that trigger events can do a start_list.
        self.state = 'waiting'

        self.mon.log(
            self, self.show_params['show-ref'] + ' ' + str(self.show_id) +
            ": Waiting for trigger: " + self.show_params['trigger-start-type'])

        if self.show_params['trigger-start-type'] == "input":

            #close the previous track to display admin message
            Show.base_shuffle(self)
            Show.base_track_ready_callback(self, False)
            Show.display_admin_message(self,
                                       self.show_params['trigger-wait-text'])

        elif self.show_params['trigger-start-type'] == "input-persist":
            if self.first_list == True:
                #first time through track list so play the track without waiting to get to end.
                self.first_list = False
                self.start_list()
            else:
                #wait for trigger while displaying previous track
                pass

        elif self.show_params['trigger-start-type'] == "start":
            # don't close the previous track to give seamless repeat of the show
            self.start_list()

        else:
            self.mon.err(
                self,
                "Unknown trigger: " + self.show_params['trigger-start-type'])
            self.end(
                'error',
                "Unknown trigger: " + self.show_params['trigger-start-type'])

    # timer for repeat=interval
    def end_interval_timer(self):
        self.interval_timer_signal = True
        # print 'INTERVAL TIMER ended'
        if self.shower is not None:
            self.shower.do_operation('stop')
        elif self.current_player is not None:
            self.current_player.input_pressed('stop')

    #  show timeout happened
    def show_timeout_stop(self):
        self.stop_timers()
        Show.base_show_timeout_stop(self)

    def start_list(self):
        # starts the list or any repeat having waited for trigger first.
        self.state = 'playing'

        # initialise track counter for the list
        self.track_count = 0

        # start interval timer
        self.interval_timer_signal = False
        if self.interval != 0:
            self.interval_timer = self.canvas.after(self.interval * 1000,
                                                    self.end_interval_timer)

        #get rid of previous track in order to display the empty message
        if self.medialist.display_length() == 0:
            Show.base_shuffle(self)
            Show.base_track_ready_callback(self, False)
            Show.display_admin_message(self, self.show_params['empty-text'])
            self.wait_for_not_empty()
        else:
            self.not_empty()

    def wait_for_not_empty(self):
        if self.medialist.display_length() == 0:
            # list is empty retry after 5 secs
            self.canvas.after(5000, self.wait_for_not_empty)
        else:
            Show.delete_admin_message(self)
            self.not_empty()

    def not_empty(self):
        #get first or last track depending on direction
        # print 'use direction for start or end of list', self.kickback_for_next_track
        if self.kickback_for_next_track is True:
            self.medialist.finish()
        else:
            self.medialist.start()
        self.start_load_show_loop(self.medialist.selected_track())

# ***************************
# Track load/show loop
# ***************************

# track playing loop starts here

    def start_load_show_loop(self, selected_track):

        # uncomment the next line to write stats for every track
        # Show.write_stats(self,'play a track',self.show_params,selected_track)

        # shuffle players
        Show.base_shuffle(self)

        self.delete_eggtimer()

        # is child track required
        if self.show_params['child-track-ref'] != '':
            self.enable_child = True
        else:
            self.enable_child = False

        # load the track or show
        # params - track,enable_menu
        enable = self.enable_child & self.enable_hint
        Show.base_load_track_or_show(self, selected_track,
                                     self.what_next_after_load,
                                     self.end_shower, enable)

    # track has loaded so show it.
    def what_next_after_load(self, status, message):
        self.mon.log(
            self, 'Show Id ' + str(self.show_id) +
            ' load complete with status: ' + status + '  message: ' + message)
        if self.current_player.play_state == 'load-failed':
            self.error_signal = True
            self.what_next_after_showing()

        else:
            if self.terminate_signal is True or self.exit_signal is True or self.user_stop_signal is True:
                self.what_next_after_showing()
            else:
                self.mon.trace(self, ' - showing track')
                self.current_player.show(self.track_ready_callback,
                                         self.finished_showing,
                                         self.closed_after_showing)

    def finished_showing(self, reason, message):
        self.sr.hide_click_areas(self.controls_list)
        if self.current_player.play_state == 'show-failed':
            self.error_signal = True
        else:
            self.req_next = 'finished-player'
        # showing has finished with 'pause at end', showing the next track will close it after next has started showing
        self.mon.trace(self, ' - pause at end ')
        self.mon.log(
            self, "pause at end of showing track with reason: " + reason +
            ' and message: ' + message)
        self.what_next_after_showing()

    def closed_after_showing(self, reason, message):
        self.sr.hide_click_areas(self.controls_list)
        if self.current_player.play_state == 'show-failed':
            self.error_signal = True
        else:
            self.req_next = 'closed-player'
        # showing has finished with closing of player but track instance is alive for hiding the x_content
        self.mon.trace(self, ' - closed')
        self.mon.log(
            self, "Closed after showing track with reason: " + reason +
            ' and message: ' + message)
        self.what_next_after_showing()

    # subshow or child show has ended
    def end_shower(self, show_id, reason, message):
        self.mon.log(
            self, self.show_params['show-ref'] + ' ' + str(self.show_id) +
            ': Returned from shower with ' + reason + ' ' + message)
        self.sr.hide_click_areas(self.controls_list)
        self.req_next = reason
        Show.base_end_shower(self)
        self.what_next_after_showing()

    def pretty_what_next_after_showing_state(self):
        state = '\n* terminate signal ' + str(self.terminate_signal)
        state += '\n* error signal ' + str(self.error_signal)
        state += '\n* req_next used to indicate subshow reports an error ' + self.req_next
        state += '\n* exit signal ' + str(self.exit_signal)
        state += '\n* show timeout  signal ' + str(self.show_timeout_signal)
        state += '\n* user stop  signal ' + str(self.user_stop_signal)
        state += '\n* previous track  signal ' + str(
            self.previous_track_signal)
        state += '\n* next track  signal ' + str(self.next_track_signal)
        state += '\n* kickback from subshow ' + str(
            self.subshow_kickback_signal)
        return state + '\n'

    def what_next_after_showing(self):
        self.mon.trace(self, self.pretty_what_next_after_showing_state())

        self.track_count += 1
        # set false when child rack is to be played
        self.enable_hint = True

        # first of all deal with conditions that do not require the next track to be shown
        # some of the conditions can happen at any time, others only when a track is closed or at pause_at_end

        # need to terminate
        if self.terminate_signal is True:
            self.terminate_signal = False
            self.stop_timers()
            # set what to do after closed or unloaded
            self.ending_reason = 'killed'
            Show.base_close_or_unload(self)

        elif self.error_signal == True or self.req_next == 'error':
            self.error_signal = False
            self.req_next = ''
            self.stop_timers()
            # set what to do after closed or unloaded
            self.ending_reason = 'error'
            Show.base_close_or_unload(self)

        # used for exiting show from other shows, time of day, external etc.
        elif self.exit_signal is True:
            self.exit_signal = False
            self.stop_timers()
            self.ending_reason = 'exit'
            Show.base_close_or_unload(self)

        #  show timeout
        elif self.show_timeout_signal is True:
            self.show_timeout_signal = False
            self.stop_timers()
            self.ending_reason = 'user-stop'
            Show.base_close_or_unload(self)

        # user wants to stop the show
        elif self.user_stop_signal is True:
            self.user_stop_signal = False
            self.stop_timers()
            self.ending_reason = 'user-stop'
            Show.base_close_or_unload(self)

    # interval > 0. If last track has finished we are waiting for interval timer before ending the list
    # note: if medialist finishes after interval is up then this route is used to start trigger.
        elif self.waiting_for_interval is True:
            # interval_timer_signal set by alarm clock started in start_list
            if self.interval_timer_signal is True:
                self.interval_timer_signal = False
                self.waiting_for_interval = False
                # print 'RECEIVED INTERVAL TIMER SIGNAL'
                if self.show_params['repeat'] == 'repeat':
                    self.wait_for_trigger()
                else:
                    self.stop_timers()
                    self.ending_reason = 'user-stop'
                    Show.base_close_or_unload(self)
            else:
                self.poll_for_interval_timer = self.canvas.after(
                    1000, self.what_next_after_showing)

        # has content of list been changed (replaced if it has, used for content of livelist)
        # causes it to go to wait_for_trigger and start_list
        #not sure why need clos_and_unload here ???????
        elif self.medialist.replace_if_changed() is True:
            self.ending_reason = 'change-medialist'
            # print 'CHANGE REQ'
            Show.base_close_or_unload(self)

        # otherwise consider operation that might show the next track
        else:
            # setup default direction for next track as normally goes forward unless kicked back
            self.kickback_for_next_track = False
            # print 'init direction to False at begin of what_next_after showing', self.kickback_for_next_track
            # end trigger from input, or track count
            if self.end_trigger_signal is True or (self.track_count_limit > 0
                                                   and self.track_count
                                                   == self.track_count_limit):
                self.end_trigger_signal = False
                # repeat so test start trigger
                if self.show_params['repeat'] == 'repeat':
                    self.stop_timers()
                    # print 'END TRIGGER restart'
                    self.wait_for_trigger()
                else:
                    # single run so exit show
                    if self.level != 0:
                        self.kickback_for_next_track = False
                        self.subshow_kickback_signal = False
                        self.end('normal',
                                 "End of single run - Return from Sub Show")
                    else:
                        # end of single run and at top - exit the show
                        self.stop_timers()
                        self.ending_reason = 'user-stop'
                        Show.base_close_or_unload(self)

            # user wants to play child
            elif self.play_child_signal is True:
                self.play_child_signal = False
                index = self.medialist.index_of_track(self.child_track_ref)
                if index >= 0:
                    # don't use select the track as need to preserve mediashow sequence for returning from child
                    child_track = self.medialist.track(index)
                    Show.write_stats(self, 'play child', self.show_params,
                                     child_track)
                    self.display_eggtimer()
                    self.enable_hint = False
                    self.start_load_show_loop(child_track)
                else:
                    self.mon.err(
                        self, "Child not found in medialist: " +
                        self.child_track_ref)
                    self.ending_reason = 'error'
                    Show.base_close_or_unload(self)

            # skip to next track on user input or after subshow
            elif self.next_track_signal is True:
                # print 'skip forward test' ,self.subshow_kickback_signal
                if self.next_track_signal is True or self.subshow_kickback_signal is False:
                    self.next_track_signal = False
                    self.kickback_for_next_track = False
                    if self.medialist.at_end() is True:
                        # medialist_at_end can give false positive for shuffle
                        if self.show_params[
                                'sequence'] == "ordered" and self.show_params[
                                    'repeat'] == 'repeat':
                            self.wait_for_trigger()
                        elif self.show_params[
                                'sequence'] == "ordered" and self.show_params[
                                    'repeat'] == 'single-run':
                            if self.level != 0:
                                self.kickback_for_next_track = False
                                self.subshow_kickback_signal = False
                                # print 'end subshow skip forward test, self. direction is ' ,self.kickback_for_next_track
                                self.end('normal', "Return from Sub Show")
                            else:
                                # end of single run and at top - exit the show
                                self.stop_timers()
                                self.ending_reason = 'user-stop'
                                Show.base_close_or_unload(self)
                        else:
                            # shuffling  - just do next track
                            self.kickback_for_next_track = False
                            self.medialist.next(self.show_params['sequence'])
                            self.start_load_show_loop(
                                self.medialist.selected_track())
                    else:
                        # not at end just do next track
                        self.medialist.next(self.show_params['sequence'])
                        self.start_load_show_loop(
                            self.medialist.selected_track())

            # skip to previous track on user input or after subshow
            elif self.previous_track_signal is True or self.subshow_kickback_signal is True:
                # print 'skip backward test, subshow kickback is' ,self.subshow_kickback_signal
                self.subshow_kickback_signal = False
                self.previous_track_signal = False
                self.kickback_for_next_track = True
                # medialist_at_start can give false positive for shuffle
                if self.medialist.at_start() is True:
                    # print 'AT START'
                    if self.show_params[
                            'sequence'] == "ordered" and self.show_params[
                                'repeat'] == 'repeat':
                        self.kickback_for_next_track = True
                        self.wait_for_trigger()
                    elif self.show_params[
                            'sequence'] == "ordered" and self.show_params[
                                'repeat'] == 'single-run':
                        if self.level != 0:
                            self.kickback_for_next_track = True
                            self.subshow_kickback_signal = True
                            # print 'end subshow skip forward test, self. direction is ' ,self.kickback_for_next_track
                            self.end('normal', "Return from Sub Show")
                        else:
                            # end of single run and at top - exit the show
                            self.stop_timers()
                            self.ending_reason = 'user-stop'
                            Show.base_close_or_unload(self)
                    else:
                        # shuffling  - just do previous track
                        self.kickback_for_next_track = True
                        self.medialist.previous(self.show_params['sequence'])
                        self.start_load_show_loop(
                            self.medialist.selected_track())
                else:
                    # not at end just do next track
                    self.medialist.previous(self.show_params['sequence'])
                    self.start_load_show_loop(self.medialist.selected_track())

            # AT END OF MEDIALIST
            elif self.medialist.at_end() is True:
                # print 'MEDIALIST AT END'

                # interval>0 and list finished so wait for the interval timer
                if self.show_params[
                        'sequence'] == "ordered" and self.interval > 0 and self.interval_timer_signal == False:
                    self.waiting_for_interval = True
                    # print 'WAITING FOR INTERVAL'
                    Show.base_shuffle(self)
                    Show.base_track_ready_callback(self, False)
                    self.poll_for_interval_timer = self.canvas.after(
                        200, self.what_next_after_showing)

                # interval=0
                #elif self.show_params['sequence'] == "ordered" and self.show_params['repeat'] == 'repeat' and self.show_params['trigger-end-type']== 'interval' and int(self.show_params['trigger-end-param']) == 0:
                #self.medialist.next(self.show_params['sequence'])
                # self.start_load_show_loop(self.medialist.selected_track())

                # shuffling so there is no end condition, get out of end test
                elif self.show_params['sequence'] == "shuffle":
                    self.medialist.next(self.show_params['sequence'])
                    self.start_load_show_loop(self.medialist.selected_track())

                # nothing special to do at end of list, just repeat or exit
                elif self.show_params['sequence'] == "ordered":
                    if self.show_params['repeat'] == 'repeat':
                        self.wait_for_trigger()
                    else:
                        # single run
                        # if not at top return to parent
                        if self.level != 0:
                            self.end('normal', "End of Single Run")
                        else:
                            # at top so close the show
                            self.stop_timers()
                            self.ending_reason = 'user-stop'
                            Show.base_close_or_unload(self)

                else:
                    self.mon.err(
                        self, "Unhandled playing event at end of list: " +
                        self.show_params['sequence'] + ' with ' +
                        self.show_params['repeat'] + " of " +
                        self.show_params['trigger-end-param'])
                    self.end(
                        'error', "Unhandled playing event at end of list: " +
                        self.show_params['sequence'] + ' with ' +
                        self.show_params['repeat'] + " of " +
                        self.show_params['trigger-end-param'])

            elif self.medialist.at_end() is False:
                # nothing special just do the next track
                self.medialist.next(self.show_params['sequence'])
                self.start_load_show_loop(self.medialist.selected_track())

            else:
                # unhandled state
                self.mon.err(
                    self, "Unhandled playing event: " +
                    self.show_params['sequence'] + ' with ' +
                    self.show_params['repeat'] + " of " +
                    self.show_params['trigger-end-param'])
                self.end(
                    'error', "Unhandled playing event: " +
                    self.show_params['sequence'] + ' with ' +
                    self.show_params['repeat'] + " of " +
                    self.show_params['trigger-end-param'])

# *********************
# Interface with other shows/players to reduce black gaps
# *********************

# called just before a track is shown to remove the  previous track from the screen
# and if necessary close it

    def track_ready_callback(self, enable_show_background):
        self.delete_eggtimer()

        # get control bindings for this show
        # needs to be done for each track as track can override the show controls
        if self.show_params['disable-controls'] == 'yes':
            self.controls_list = []
        else:
            reason, message, self.controls_list = self.controlsmanager.get_controls(
                self.show_params['controls'])
            if reason == 'error':
                self.mon.err(self, message)
                self.end('error', "error in controls: " + message)
                return

            # print 'controls',reason,self.show_params['controls'],self.controls_list
            #merge controls from the track
            controls_text = self.current_player.get_links()
            reason, message, track_controls = self.controlsmanager.parse_controls(
                controls_text)
            if reason == 'error':
                self.mon.err(
                    self, message + " in track: " +
                    self.current_player.track_params['track-ref'])
                self.error_signal = True
                self.what_next_after_showing()
            self.controlsmanager.merge_controls(self.controls_list,
                                                track_controls)

        # enable the click-area that are in the list of controls
        self.sr.enable_click_areas(self.controls_list)
        Show.base_track_ready_callback(self, enable_show_background)

    # callback from begining of a subshow, provide previous player to called show
    def subshow_ready_callback(self):
        return Show.base_subshow_ready_callback(self)

# *********************
# End the show
# *********************

    def end(self, reason, message):
        Show.base_end(self, reason, message)

    def stop_timers(self):
        # clear outstanding time of day events for this show
        # self.tod.clear_times_list(id(self))

        if self.poll_for_interval_timer is not None:
            self.canvas.after_cancel(self.poll_for_interval_timer)
            self.poll_for_interval_timer = None

        if self.interval_timer is not None:
            self.canvas.after_cancel(self.interval_timer)
            self.interval_timer = None

        if self.duration_timer is not None:
            self.canvas.after_cancel(self.duration_timer)
            self.duration_timer = None
    def play(self,show_id,end_callback,ready_callback, top=False,command='nil'):
	global defaultDur
	if defaultDur == None:
		defaultDur = self.showlist.get_dur()

        #instantiate the arguments
        self.show_id=show_id
        self.end_callback=end_callback
        self.ready_callback=ready_callback
        self.top=top
        self.mon.log(self,"Starting show: " + self.show_params['show-ref'])



        # check  data files are available.
        self.media_file = self.pp_profile + os.sep + self.show_params['medialist']
        if not os.path.exists(self.media_file):
            self.mon.err(self,"Medialist file not found: "+ self.media_file)
            self.end_liveshow_signal=True

            
        self.options=command_options()
               
        self.pp_live_dir1 = self.pp_home + os.sep + 'pp_live_tracks'
        if not os.path.exists(self.pp_live_dir1):
            os.mkdir(self.pp_live_dir1)
            os.mkdir(self.pp_live_dir1+os.sep+ 'Archive')

        self.pp_live_dir2=''   
        if self.options['liveshow'] <>"":
            self.pp_live_dir2 = self.options['liveshow']
            if not os.path.exists(self.pp_live_dir2):
                self.mon.err(self,"live tracks directory not found " + self.pp_live_dir2)
                self.end('error',"live tracks directory not found")

        #create a medialist for the liveshow and read it.
        # it should be empty of anonymous tracks but read it to check its version.
        self.medialist=MediaList()

        if self.medialist.open_list(self.media_file,self.showlist.sissue())==False:
            self.mon.err(self,"Version of medialist different to Pi Presents")
            self.end('error',"Version of medialist different to Pi Presents")

        #get control bindings for this show if top level
        controlsmanager=ControlsManager()
        if self.top==True:
            self.controls_list=controlsmanager.default_controls()
            # and merge in controls from profile
            self.controls_list=controlsmanager.merge_show_controls(self.controls_list,self.show_params['controls'])

        #set up the time of day triggers for the show
        if self.show_params['trigger-start']in('time','time-quiet'):
            error_text=self.tod.add_times(self.show_params['trigger-start-time'],id(self),self.tod_start_callback,self.show_params['trigger-start'])
            if error_text<>'':
                self.mon.err(self,error_text)
                self.end('error',error_text)
                
        if self.show_params['trigger-end']=='time':
            error_text=self.tod.add_times(self.show_params['trigger-end-time'],id(self),self.tod_end_callback,'n/a')
            if error_text<>'':
                self.mon.err(self,error_text)
                self.end('error',error_text)

        if self.show_params['trigger-end']=='duration':
            error_text=self.calculate_duration(self.show_params['trigger-end-time'])
            if error_text<>'':
                self.mon.err(self,error_text)
                self.end('error',error_text)       

        self.wait_for_trigger()                
Example #18
0
    def play(self,
             show_id,
             end_callback,
             ready_callback,
             top=False,
             command='nil'):

        #instantiate the arguments
        self.show_id = show_id
        self.end_callback = end_callback
        self.ready_callback = ready_callback
        self.top = top
        self.mon.log(self, "Starting show: " + self.show_params['show-ref'])

        # check  data files are available.
        self.media_file = self.pp_profile + os.sep + self.show_params[
            'medialist']
        if not os.path.exists(self.media_file):
            self.mon.err(self, "Medialist file not found: " + self.media_file)
            self.end_liveshow_signal = True

        self.options = command_options()

        self.pp_live_dir1 = self.pp_home + os.sep + 'pp_live_tracks'
        if not os.path.exists(self.pp_live_dir1):
            os.mkdir(self.pp_live_dir1)

        self.pp_live_dir2 = ''
        if self.options['liveshow'] <> "":
            self.pp_live_dir2 = self.options['liveshow']
            if not os.path.exists(self.pp_live_dir2):
                self.mon.err(
                    self,
                    "live tracks directory not found " + self.pp_live_dir2)
                self.end('error', "live tracks directory not found")

        #create a medialist for the liveshow and read it.
        # it should be empty of anonymous tracks but read it to check its version.
        self.medialist = MediaList()
        if self.medialist.open_list(self.media_file,
                                    self.showlist.sissue()) == False:
            self.mon.err(self, "Version of medialist different to Pi Presents")
            self.end('error', "Version of medialist different to Pi Presents")

        #get control bindings for this show if top level
        controlsmanager = ControlsManager()
        if self.top == True:
            self.controls_list = controlsmanager.default_controls()
            # and merge in controls from profile
            self.controls_list = controlsmanager.merge_show_controls(
                self.controls_list, self.show_params['controls'])

        #set up the time of day triggers for the show
        if self.show_params['trigger-start'] in ('time', 'time-quiet'):
            error_text = self.tod.add_times(
                self.show_params['trigger-start-time'], id(self),
                self.tod_start_callback, self.show_params['trigger-start'])
            if error_text <> '':
                self.mon.err(self, error_text)
                self.end('error', error_text)

        if self.show_params['trigger-end'] == 'time':
            error_text = self.tod.add_times(
                self.show_params['trigger-end-time'], id(self),
                self.tod_end_callback, 'n/a')
            if error_text <> '':
                self.mon.err(self, error_text)
                self.end('error', error_text)

        if self.show_params['trigger-end'] == 'duration':
            error_text = self.calculate_duration(
                self.show_params['trigger-end-time'])
            if error_text <> '':
                self.mon.err(self, error_text)
                self.end('error', error_text)

        self.wait_for_trigger()
Example #19
0
class MenuShow(Show):
    def __init__(self, show_id, show_params, root, canvas, showlist, pp_dir,
                 pp_home, pp_profile, command_callback):
        """
            show_id - index of the top level show caling this (for debug only)
            show_params - dictionary section for the menu
            canvas - the canvas that the menu is to be written on
            showlist  - the showlist
            pp_dir - Pi Presents directory
            pp_home - Pi presents data_home directory
            pp_profile - Pi presents profile directory
        """

        # init the common bits
        Show.base__init__(self, show_id, show_params, root, canvas, showlist,
                          pp_dir, pp_home, pp_profile, command_callback)

        # instatiatate the screen driver - used only to access enable and hide click areas
        self.sr = ScreenDriver()

        self.controlsmanager = ControlsManager()

        # init variables
        self.show_timeout_timer = None
        self.track_timeout_timer = None
        self.next_track_signal = False
        self.next_track = None
        self.menu_index = 0
        self.menu_showing = True
        self.req_next = ''
        self.last_menu_index = 0
        self.return_to_zero = False

    def play(self, end_callback, show_ready_callback, parent_kickback_signal,
             level, controls_list):
        """ displays the menu 
              end_callback - function to be called when the menu exits
              show_ready_callback - callback when menu is ready to display (not used)
              level is 0 when the show is top level (run from [start] or from show control)
              parent_kickback_signal  - not used other than it being passed to a show
        """
        # need to instantiate the medialist here as not using gapshow
        self.medialist = MediaList('ordered')

        Show.base_play(self, end_callback, show_ready_callback,
                       parent_kickback_signal, level, controls_list)

        self.mon.trace(self, self.show_params['show-ref'])

        #parse the show and track timeouts
        reason, message, self.show_timeout = Show.calculate_duration(
            self, self.show_params['show-timeout'])
        if reason == 'error':
            self.mon.err(
                self, 'Show Timeout has bad time: ' +
                self.show_params['show-timeout'])
            self.end(
                'error',
                'show timeout, bad time: ' + self.show_params['show-timeout'])

        reason, message, self.track_timeout = Show.calculate_duration(
            self, self.show_params['track-timeout'])
        if reason == 'error':
            self.mon.err(
                self, 'Track Timeout has bad time: ' +
                self.show_params['track-timeout'])
            self.end(
                'error', 'track timeout, bad time: ' +
                self.show_params['track-timeout'])

        # and delete eggtimer
        if self.previous_shower is not None:
            self.previous_shower.delete_eggtimer()

        # and display the menu
        self.do_menu_track()

# ********************
# respond to inputs.
# ********************

# exit received from another concurrent show

    def exit(self):
        self.stop_timers()
        Show.base_exit(self)

    #  show timeout happened
    def show_timeout_stop(self):
        self.stop_timers()
        Show.base_show_timeout_stop(self)

    # terminate Pi Presents
    def terminate(self):
        self.stop_timers()
        Show.base_terminate(self)

    def handle_input_event(self, symbol):
        Show.base_handle_input_event(self, symbol)

    def handle_input_event_this_show(self, symbol):

        self.handle_show_control_event(symbol, self.show_control_controls)

        # menushow has only internal operation
        operation = self.base_lookup_control(symbol, self.controls_list)
        self.do_operation(operation)

    def do_operation(self, operation):
        # service the standard inputs for this show

        self.mon.trace(self, operation)
        if operation == 'exit':
            self.exit()

        elif operation == 'stop':
            self.stop_timers()
            if self.current_player is not None:
                if self.menu_showing is True and self.level != 0:
                    # if quiescent then set signal to stop the show when track has stopped
                    self.user_stop_signal = True
                self.current_player.input_pressed('stop')

        elif operation in ('up', 'down'):
            # stop show timeout
            if self.show_timeout_timer is not None:
                self.canvas.after_cancel(self.show_timeout_timer)
                # and start it again
                if self.show_timeout != 0:
                    self.show_timeout_timer = self.canvas.after(
                        self.show_timeout * 1000, self.show_timeout_stop)
            if operation == 'up':
                self.previous()
            else:
                next(self)

        elif operation == 'play':
            self.next_track_signal = True
            st = self.medialist.select_anon_by_index(self.menu_index)
            self.next_track = self.medialist.selected_track()
            self.current_player.stop()

            # cancel show timeout
            if self.show_timeout_timer is not None:
                self.canvas.after_cancel(self.show_timeout_timer)
                self.show_timeout_timer = None

            # stop current track (the menuplayer) if running or just start the next track
            if self.current_player is not None:
                self.current_player.input_pressed('stop')
            else:
                self.what_next_after_showing()

        elif operation in ('no-command', 'null'):
            return

        elif operation in ('pause', 'pause-on', 'pause-off', 'mute', 'unmute',
                           'go'):
            if self.current_player is not None:
                self.current_player.input_pressed(operation)

        elif operation[0:4] == 'omx-' or operation[
                0:6] == 'mplay-' or operation[0:5] == 'uzbl-':
            if self.current_player is not None:
                self.current_player.input_pressed(operation)

    def __next__(self):
        # remove highlight
        if self.current_player.__class__.__name__ == 'MenuPlayer':
            self.current_player.highlight_menu_entry(self.menu_index, False)
            self.medialist.next('ordered')
            if self.menu_index == self.menu_length - 1:
                self.menu_index = 0
            else:
                self.menu_index += 1
            # and highlight the new entry
            self.current_player.highlight_menu_entry(self.menu_index, True)

    def previous(self):
        # remove highlight
        if self.current_player.__class__.__name__ == 'MenuPlayer':
            self.current_player.highlight_menu_entry(self.menu_index, False)
            if self.menu_index == 0:
                self.menu_index = self.menu_length - 1
            else:
                self.menu_index -= 1
            self.medialist.previous('ordered')
            # and highlight the new entry
            self.current_player.highlight_menu_entry(self.menu_index, True)

# *********************
# Sequencing
# *********************

    def track_timeout_callback(self):
        self.do_operation('stop')

    def do_menu_track(self):
        self.menu_showing = True
        self.mon.trace(self, '')
        # start show timeout alarm if required
        if self.show_timeout != 0:
            self.show_timeout_timer = self.canvas.after(
                self.show_timeout * 1000, self.show_timeout_stop)

        index = self.medialist.index_of_track(
            self.show_params['menu-track-ref'])
        if index == -1:
            self.mon.err(
                self, "'menu-track' not in medialist: " +
                self.show_params['menu-track-ref'])
            self.end(
                'error', "menu-track not in medialist: " +
                self.show_params['menu-track-ref'])
            return

        #make the medialist available to the menuplayer for cursor scrolling
        self.show_params['medialist_obj'] = self.medialist

        # load the menu track
        self.start_load_show_loop(self.medialist.track(index))

# *********************
# Playing show or track loop
# *********************

    def start_load_show_loop(self, selected_track):
        # shuffle players
        Show.base_shuffle(self)
        self.mon.trace(self, '')
        self.display_eggtimer()

        # get control bindings for this show
        # needs to be done for each track as track can override the show controls
        if self.show_params['disable-controls'] == 'yes':
            self.controls_list = []
        else:
            reason, message, self.controls_list = self.controlsmanager.get_controls(
                self.show_params['controls'])
            if reason == 'error':
                self.mon.err(self, message)
                self.end('error', "error in controls: " + message)
                return

        # load the track or show
        Show.base_load_track_or_show(self, selected_track,
                                     self.what_next_after_load,
                                     self.end_shower, False)

# track has loaded (menu or otherwise) so show it.

    def what_next_after_load(self, status, message):

        if self.current_player.play_state == 'load-failed':
            self.req_next = 'error'
            self.what_next_after_showing()

        else:
            # get the calculated length of the menu for the loaded menu track
            if self.current_player.__class__.__name__ == 'MenuPlayer':
                if self.medialist.anon_length() == 0:
                    self.req_next = 'error'
                    self.what_next_after_showing()
                    return

                #highlight either first or returning entry and select appropiate medialist entry
                if self.return_to_zero is True:
                    # init the index used to hiighlight the selected menu entry by menuplayer
                    self.menu_index = 0
                    # print 'initial index',self.menu_index
                else:
                    self.menu_index = self.last_menu_index
                    # print ' return to last ',self.menu_index

                self.menu_length = self.current_player.menu_length
                self.current_player.highlight_menu_entry(self.menu_index, True)
            self.mon.trace(
                self, ' - load complete with status: ' + status +
                '  message: ' + message)

            if self.show_timeout_signal is True or self.terminate_signal is True or self.exit_signal is True or self.user_stop_signal is True:
                self.what_next_after_showing()
            else:
                self.mon.trace(self, '')
                self.current_player.show(self.track_ready_callback,
                                         self.finished_showing,
                                         self.closed_after_showing)

    def finished_showing(self, reason, message):
        # showing has finished with 'pause at end', showing the next track will close it after next has started showing
        self.mon.trace(self, '')
        self.mon.log(
            self, "pause at end of showing track with reason: " + reason +
            ' and message: ' + message)
        self.sr.hide_click_areas(self.controls_list, self.canvas)
        if self.current_player.play_state == 'show-failed':
            self.req_next = 'error'
        else:
            self.req_next = 'finished-player'
        self.what_next_after_showing()

    def closed_after_showing(self, reason, message):
        # showing has finished with closing of player but track instance is alive for hiding the x_content
        self.mon.trace(self, '')
        self.mon.log(
            self, "Closed after showing track with reason: " + reason +
            ' and message: ' + message)
        self.sr.hide_click_areas(self.controls_list, self.canvas)
        if self.current_player.play_state == 'show-failed':
            self.req_next = 'error'
        else:
            self.req_next = 'closed-player'
        self.what_next_after_showing()

    # subshow or child show has ended
    def end_shower(self, show_id, reason, message):
        self.mon.log(
            self, self.show_params['show-ref'] + ' ' + str(self.show_id) +
            ': Returned from shower with ' + reason + ' ' + message)
        self.sr.hide_click_areas(self.controls_list, self.canvas)
        self.req_next = reason
        Show.base_end_shower(self)
        self.what_next_after_showing()

    # at the end of a track check for terminations else re-display the menu
    def what_next_after_showing(self):
        self.mon.trace(self, '')
        # cancel track timeout timer
        if self.track_timeout_timer is not None:
            self.canvas.after_cancel(self.track_timeout_timer)
            self.track_timeout_timer = None

        # need to terminate?
        if self.terminate_signal is True:
            self.terminate_signal = False
            # set what to do when closed or unloaded
            self.ending_reason = 'killed'
            Show.base_close_or_unload(self)

        elif self.req_next == 'error':
            self.req_next = ''
            # set what to do after closed or unloaded
            self.ending_reason = 'error'
            Show.base_close_or_unload(self)

        # show timeout
        elif self.show_timeout_signal is True:
            self.show_timeout_signal = False
            # set what to do when closed or unloaded
            self.ending_reason = 'show-timeout'
            Show.base_close_or_unload(self)

        # used by exit for stopping show from other shows.
        elif self.exit_signal is True:
            self.exit_signal = False
            self.ending_reason = 'exit'
            Show.base_close_or_unload(self)

        # user wants to stop
        elif self.user_stop_signal is True:
            self.user_stop_signal = False
            self.ending_reason = 'user-stop'
            Show.base_close_or_unload(self)

        elif self.next_track_signal is True:
            self.next_track_signal = False
            self.menu_showing = False
            # start timeout for the track if required
            if self.track_timeout != 0:
                self.track_timeout_timer = self.canvas.after(
                    self.track_timeout * 1000, self.track_timeout_callback)
            self.last_menu_index = self.menu_index
            Show.write_stats(self, 'play', self.show_params, self.next_track)
            self.start_load_show_loop(self.next_track)

        else:
            # no stopping the show required so re-display the menu
            self.do_menu_track()

# *********************
# Interface with other shows/players to reduce black gaps
# *********************

# called just before a track is shown to remove the  previous track from the screen
# and if necessary close it

    def track_ready_callback(self, enable_show_background):
        self.delete_eggtimer()

        if self.show_params['disable-controls'] != 'yes':
            #merge controls from the track
            controls_text = self.current_player.get_links()
            reason, message, track_controls = self.controlsmanager.parse_controls(
                controls_text)
            if reason == 'error':
                self.mon.err(
                    self, message + " in track: " +
                    self.current_player.track_params['track-ref'])
                self.req_next = 'error'
                self.what_next_after_showing()
            self.controlsmanager.merge_controls(self.controls_list,
                                                track_controls)

        self.sr.enable_click_areas(self.controls_list, self.canvas)

        Show.base_track_ready_callback(self, enable_show_background)

    # callback from begining of a subshow, provide previous shower player to called show
    def subshow_ready_callback(self):
        return Show.base_subshow_ready_callback(self)

# *********************
# Ending the show
# *********************

    def end(self, reason, message):
        self.stop_timers()
        Show.base_end(self, reason, message)

    def stop_timers(self):
        if self.track_timeout_timer is not None:
            self.canvas.after_cancel(self.track_timeout_timer)
            self.track_timeout_timer = None
        if self.show_timeout_timer is not None:
            self.canvas.after_cancel(self.show_timeout_timer)
            self.show_timeout_timer = None
Example #20
0
class ArtShow(Show):
    
    """
        Automatically plays a set of tracks from a medialist. Does gapless and time of day trigger but little else.
    """
            
# *******************
# External interface
# ********************

    def __init__(self,
                 show_id,
                 show_params,
                 root,
                 canvas,
                 showlist,
                 pp_dir,
                 pp_home,
                 pp_profile,
                 command_callback):


    
        # init the common bits
        Show.base__init__(self,
                          show_id,
                          show_params,
                          root,
                          canvas,
                          showlist,
                          pp_dir,
                          pp_home,
                          pp_profile,
                          command_callback)

        # delay in mS before next track is loaded after showing a track.
        # can be reduced if animation is not required
        self.load_delay = 2000

        # Init variables for this show
        self.end_medialist_signal=False
        self.end_medialist_warning=False
        self.next_track_signal=False
        self.state='closed'
        self.req_next=''


    def play(self,end_callback,show_ready_callback, parent_kickback_signal,level,controls_list):
        self.mon.trace(self,self.show_params['show-ref'])
        Show.base_play(self,end_callback,show_ready_callback,parent_kickback_signal, level,controls_list)


        # get the previous shower and player from calling show
        # Show.base_get_previous_player_from_parent(self)

        # and delete eggtimer started by the parent
        if self.previous_shower is not None:
            self.previous_shower.delete_eggtimer()
            
        self.wait_for_trigger()   

   

# ********************************
# Respond to external events
# ********************************

    def exit(self):
        # set signal to stop the show when all  sub-shows and players have ended
        self.exit_signal=True
        # then stop track.
        if self.current_player is not None:
            self.current_player.input_pressed('stop')
        else:
            self.end('normal','ended by exit')

                
    # kill or error
    def terminate(self):
        self.terminate_signal=True
        if self.current_player is not None:
            self.ending_reason='killed'
            self.close_current_and_next()
        else:
            self.end('killed',' terminated with no shower or player to terminate')

 
   # respond to key presses.
    def handle_input_event(self,symbol):
        Show.base_handle_input_event(self,symbol)



    def handle_input_event_this_show(self,symbol):
        operation=self.base_lookup_control(symbol,self.controls_list)
        self.do_operation(operation)


    def do_trigger_or_link(self,symbol,edge,source):
        pass

    # service the standard operations for this show
    def do_operation(self,operation):
        self.mon.trace(self,operation)
        # service the standard inputs for this show
        if operation == 'exit':
            self.exit()
            
        elif operation == 'stop':
            if self.level != 0 :
                # not at top so stop the show
                self.user_stop_signal=True
                # and stop the track first
                if self.current_player is not None:
                    self.current_player.input_pressed('stop')
            else:
                # at top, just stop track if running
                if self.current_player is not None:
                    self.current_player.input_pressed('stop')

        elif operation == 'down':
            self.next()

        elif operation  ==  'pause':
            # pass down if show or track running.
            if self.current_player is not None:
                self.current_player.input_pressed('pause')

        elif operation  in ('no-command','null'):
            return
        
        elif operation[0:4] == 'omx-' or operation[0:6] == 'mplay-':
            if self.current_player is not None:
                self.current_player.input_pressed(operation)
     

    def next(self):
        # stop track if running and set signal
        self.next_track_signal=True
        if self.current_player is not None:
            self.current_player.input_pressed('stop')


# ***************************
# Sequencing
# ***************************
    def wait_for_trigger(self):
        self.start_show()            

    def start_show(self):
        self.load_first_track()

        
    # load the first track of the show
    def load_first_track(self):
        self.mon.trace(self,'')
        if self.medialist.start() is False:
            # list is empty - display a message for 5 secs and then retry
            Show.display_admin_message(self,self.show_params['empty-text'])
            self.canvas.after(5000,self.remove_list_empty_message)
        else:
            # otherwise load the first track
            # print "!!!!! artshow init first"
            self.next_player=Show.base_init_selected_player(self,self.medialist.selected_track())
            if self.next_player is None:
                self.mon.err(self,"Track Type cannot be played by this show: "+self.medialist.selected_track()['type'])
                self.req_next='error'
                self.what_next()
            else:
                # messageplayer passes the text not a file name
                if self.medialist.selected_track()['type'] == 'message':
                    track_file=self.medialist.selected_track()['text']
                else:
                    track_file=Show.base_complete_path(self,self.medialist.selected_track()['location'])
                # print "!!!!! artshow load first ",track_file
                self.next_player.load(track_file,
                                      self.loaded_callback,
                                      enable_menu=False)
                self.wait_for_load() 
            

    def remove_list_empty_message(self):
        Show.delete_admin_message(self)
        self.load_first_track()


    # start of the showing loop. Got here from the end of showing.        
    def wait_for_load(self):           
        # wait for load of next track and close of previous to complete
        # state after this is previous=None, current=closed or pause_at_end, next=loaded or load_failed
        # and is a good place to test for ending.
        # self.mon.trace(self,'')
        if self.next_player is not None:
            if self.next_player.get_play_state() == 'load-failed':
                self.req_next='error'
                self.what_next()
            else:
                if self.previous_player is  None  and self.next_player.get_play_state() == 'loaded':
                    self.mon.trace(self,' - next is loaded and previous closed')
                    self.canvas.after(10,self.what_next)
                else:
                    self.canvas.after(50,self.wait_for_load)
        else:
            self.canvas.after(200,self.wait_for_load)           

          
    def what_next(self):
        # do we need to end or restart, if so close the current, and unload the next, and wait
        # until next is unloaded and current has closed
        self.mon.trace(self,'')
        
        # terminate
        if self.terminate_signal is True:
            self.terminate_signal=False
            self.ending_reason='killed'
            self.close_current_and_next()

        elif self.req_next== 'error':
            self.req_next=''
            # set what to do after closed or unloaded
            self.ending_reason='error'
            self.close_current_and_next()

        # used  for stopping show from other shows  etc.
        elif self.exit_signal is True:
            self.exit_signal=False
            self.stop_timers()
            self.ending_reason='exit'
            self.close_current_and_next()

        # user wants to stop the show 
        elif self.user_stop_signal is True:
            self.user_stop_signal=False
            self.stop_timers()
            self.ending_reason='user-stop'
            self.close_current_and_next()
            
        elif self.medialist.length() == 0:
            self.load_first_track()

        # end of medialist
        elif self.end_medialist_signal is True:
            self.end_medialist_signal=False
            self.end_medialist_warning=False
            # test for ordered since medialist at end gives false positives for shuffle
            
            # repeat so go back to start
            if self.show_params['sequence'] == "ordered" and self.show_params['repeat'] == 'repeat':
                self.show_next_track()

            # single run so end
            elif self.show_params['sequence'] == "ordered" and self.show_params['repeat'] == 'single-run':
                self.ending_reason='end-of-medialist'
                self.close_current_and_next()

            else:
                # otherwise show the next track
                self.show_next_track()
        else:
            # otherwise show the next track
            self.show_next_track()

            
    def show_next_track(self):
        self.mon.trace(self,' - SHUFFLE')
        self.previous_player=self.current_player
        self.current_player=self.next_player
        self.next_player=None
        self.mon.trace(self,'AFTER SHUFFLE n-c-p' +  self.mon.pretty_inst(self.next_player) + ' ' + self.mon.pretty_inst(self.current_player) + ' ' + self.mon.pretty_inst(self.previous_player) )
        self.mon.trace(self, 'showing track')
        if self.end_medialist_warning is True:
            self.end_medialist_signal = True
        self.current_player.show(self.track_ready_callback,self.finished_showing,self.closed_after_showing)
        # wait a short time before loading next
        self.canvas.after(10,self.what_to_load_next)


    def finished_showing(self,reason,message):
        # showing has finished with 'pause at end', showing the next track will close it after next has started showing
        self.mon.trace(self,' - pause at end')
        self.mon.log(self,"finished_showing - pause at end of showing with reason: "+reason+ ' and message: '+ message)
    
        if self.current_player.play_state == 'show-failed':
            self.req_next = 'error'
            self.what_next()
        else:
            self.req_next='finished-player'
            self.wait_for_load()


    def closed_after_showing(self,reason,message):
        # showing has finished with closing of player but track instance is alive for hiding the x_content
        self.mon.trace(self,' - closed after showing')
        self.mon.log(self,"closed_after_showing - Closed after showing with reason: "+reason+ ' and message: '+ message)
        if self.current_player.play_state == 'show-failed':
            self.req_next = 'error'
            self.what_next()
        else:
            self.req_next='finished-player'
            self.wait_for_load()        

        
    # pre-load the next track. Runs concurrently to show. Control goes nowhere after completion, success is detected from the states.    
    def what_to_load_next(self):
        self.mon.trace(self,self.pretty_state ())

        # closing down so don't load anything
        if self.ending_reason in ('killed','error'):
            return

        # wanting to exit so don't load just skip to what-next
        if self.terminate_signal is True or self.exit_signal is True or self.req_next=='error':
            self.what_next()

        # has content of list been changed (replaced if it has, used for content of livelist)
        if self.medialist.replace_if_changed() is True:
            self.ending_reason='change-medialist'
            self.close_current_and_next()
        else:
            # get the next track and init player
            self.medialist.next(self.show_params['sequence'])
            if self.medialist.at_end() is True:
                self.end_medialist_warning=True
            # print "!!!!! artshow init next "
            self.next_player=Show.base_init_selected_player(self,self.medialist.selected_track())
            if self.next_player is None:
                self.mon.err(self,"Track Type cannot be played by this show: "+self.medialist.selected_track()['type'])
                self.req_next='error'
                self.what_next()
            else:
                # and load the next after a wait to allow animation etc to be timely.
                self.canvas.after(self.load_delay,self.load_next)

    def load_next(self):
        # load the next track while current is showing
        # messageplayer passes the text not a file name
        if self.medialist.selected_track()['type'] == 'message':
            track_file=self.medialist.selected_track()['text']
        else:
            track_file=Show.base_complete_path(self,self.medialist.selected_track()['location'])
        # print "!!!!! artshow load next ",track_file
        self.mon.trace(self, track_file)
        self.next_player.load(track_file,
                              self.loaded_callback,
                              enable_menu=False)

    def loaded_callback(self,reason,message):
        self.mon.trace(self,' - load complete with reason: ' + reason + '  message: ' + message)  


##    def end_close_previous(self,reason,message):
##        self.mon.log(self,"end_close_previous - Previous closed with reason: "+reason+ ' and message: '+ message)
##        self.mon.trace(self,' - previous closed')
##        self.previous_player=None    # safer to delete the player here rather than in player as play-state is read elsewhere.


    
    def close_current_and_next(self):
        # end of show so close current, next and previous before ending
        if self.current_player is not None and self.current_player.get_play_state() == 'showing':
            self.mon.trace(self,' - closing_current from ' + self.ending_reason)
            self.current_player.close(self.end_close_current)
        if self.next_player is not None and self.next_player.get_play_state() not in ('unloaded','closed','initialised','load-failed'):
            self.mon.trace(self, '- unloading next from ' + self.ending_reason)
            self.next_player.unload()
        self.wait_for_end()


    def end_close_current(self,reason,message):
        self.mon.log(self,"Current track closed with reason: "+ reason + ' and message: '+ message)
        self.mon.trace(self,' - current closed')
        self.current_player=None    # safer to delete the player here rather than in player as play-state is read elsewhere.


        
    # previous=None at this point,just wait for loading and closing to complete then end
    def wait_for_end(self):
        self.mon.trace(self, self.pretty_state())
        ok_to_end=0
        if self.current_player is None or self.current_player.get_play_state() == 'closed':
            self.current_player=None
            ok_to_end+=1
        if self.next_player is None or self.next_player.get_play_state() in ('initialised','unloaded','load-failed'):
            self.next_player=None
            ok_to_end+=1
        if ok_to_end != 2:
            self.canvas.after(50,self.wait_for_end)
        else:
            self.mon.trace(self,' - next and current closed ' + self.ending_reason)

            if self.ending_reason == 'killed':
                self.base_close_previous()

            elif self.ending_reason=='error':
                self.base_close_previous()
                
            elif self.ending_reason == 'exit':
                self.base_close_previous()

            elif self.ending_reason == 'end-trigger':
                self.state='waiting'
                self.wait_for_trigger()

            elif self.ending_reason in ('user-stop','end-of-medialist'):
                self.end('normal',"show quit by user or natural end")                

            elif self.ending_reason == 'change-medialist':
                self.load_first_track()   
            else:
                self.mon.err(self,"Unhandled ending_reason: ")
                self.end('error',"Unhandled ending_reason")                

    def track_ready_callback(self,enable_show_background):
        self.mon.trace(self, '')

        # get control bindings for this show
        self.controlsmanager=ControlsManager()
        if self.show_params['disable-controls'] == 'yes':
            self.controls_list=[]
        else:
            reason,message,self.controls_list= self.controlsmanager.get_controls(self.show_params['controls'])
            if reason=='error':
                self.mon.err(self,message)
                self.end('error',"error in controls")
                return
            # print '\nshow controls',self.show_params['controls']
   
            #merge controls from the track
            controls_text=self.current_player.get_links()
            # print 'current player controls',controls_text
            reason,message,track_controls=self.controlsmanager.parse_controls(controls_text)
            if reason == 'error':
                self.mon.err(self,message + " in track: "+ self.current_player.track_params['track-ref'])
                self.error_signal=True
                self.what_next_after_showing()
            self.controlsmanager.merge_controls(self.controls_list,track_controls)

        # show the show background done for every track but quick operation
        if enable_show_background is True:
            self.base_show_show_background()
        else:
            self.base_withdraw_show_background()
        # !!!!!!!!! withdraw the background from the parent show
        if self.previous_shower != None:
            self.previous_shower.base_withdraw_show_background()
            
        # close the player from the previous track
        if self.previous_player is not None:
            self.mon.trace(self, 'hiding previous: ' + self.mon.pretty_inst(self.previous_player))
            self.previous_player.hide()
            if self.previous_player.get_play_state() == 'showing':
                self.mon.trace(self,'closing previous: ' + self.mon.pretty_inst(self.previous_player))
                self.previous_player.close(self.closed_callback)
            else:
                self.mon.trace(self, 'previous is none')
                self.previous_player=None


    def closed_callback(self,reason,message):
        self.mon.trace(self, reason +' '+ message)
        self.previous_player=None


    def base_close_previous(self):
        self.mon.log(self,self.show_params['show-ref']+ ' '+ str(self.show_id)+ ": base close previous")
        self.mon.trace(self, '')
        # close the player from the previous track
        if self.previous_player is not  None:
            self.mon.trace(self, 'previous is not None ' + self.mon.pretty_inst(self.previous_player))
            if self.previous_player.get_play_state() == 'showing':
                # showing or frozen
                self.mon.trace(self,'closing previous ' + self.mon.pretty_inst(self.previous_player))
                self.previous_player.close(self._base_close_previous_callback)
            else:
                self.mon.trace(self, 'previous is not showing')
                self.previous_player.hide()
                self.previous_player=None
                self.end(self.ending_reason,'')
        else:
            self.mon.trace(self,'previous is None')
            self.end(self.ending_reason,'')
            
                
    def _base_close_previous_callback(self,status,message):
        self.mon.trace(self,' previous is None  - was ' + self.mon.pretty_inst(self.previous_player))
        self.previous_player.hide()
        self.previous_player=None
        self.end(self.ending_reason,'')


# ***************************
# end of show 
# ***************************

    def end(self,reason,message):
        self.base_withdraw_show_background()
        self.base_delete_show_background()
        self.mon.log(self,"Ending Mediashow: "+ self.show_params['show-ref'])
        self.end_callback(self.show_id,reason,message)
        self=None

    
    def stop_timers(self):
        pass
        #if self.duration_timer is not None:
            #self.canvas.after_cancel(self.duration_timer)
            #self.duration_timer=None
        # clear outstanding time of day events for this show
        # self.tod.clear_times_list(id(self))     


# ***************************
# debug 
# ***************************
  
    def pretty_state(self):
        state = '  n-c-p   -  '
        if self.next_player is not None:
            state += self.next_player.get_play_state()
        else:
            state += 'None'
        if self.current_player is not None:
            state += self.current_player.get_play_state()
        else:
            state += 'None'
        if self.previous_player is not None:
            state +=  self.previous_player.get_play_state()
        else:
            state += 'None'
        return state
Example #21
0
class GapShow(Show):
    """
    this is the parent class of mediashow and liveshow
    The two derived clases just select the appropriate medialist from pp_medialist and pp_livelist
    the parents control the monitoring
    """

# *******************
# External interface
# ********************

    def __init__(self,
                 show_id,
                 show_params,
                 root,
                 canvas,
                 showlist,
                 pp_dir,
                 pp_home,
                 pp_profile,
                 command_callback):


        # init the common bits
        Show.base__init__(self,
                          show_id,
                          show_params,
                          root,
                          canvas,
                          showlist,
                          pp_dir,
                          pp_home,
                          pp_profile,
                          command_callback)

        # instatiatate the screen driver - used only to access enable and hide click areas
        self.sr=ScreenDriver()

        self.controlsmanager=ControlsManager()

        # Init variables special to this show
        self.poll_for_interval_timer=None
        self.interval_timer_signal=False
        self.waiting_for_interval=False
        self.interval_timer=None
        self.duration_timer=None

        self.end_trigger_signal=False
        self.next_track_signal=False
        self.previous_track_signal=False
        self.play_child_signal = False
        self.error_signal=False
        self.show_timeout_signal=False
        
        self.req_next='nil'
        self.state='closed'

        self.count=0
        self.interval=0
        self.duration=0
        self.controls_list=[]
        self.enable_hint= True
        self.escapetrack_required=False
        

    def play(self,end_callback,show_ready_callback, parent_kickback_signal,level,controls_list):
        self.mon.newline(3)
        self.mon.trace(self, self.show_params['show-ref'])
             
        Show.base_play(self,end_callback,show_ready_callback,parent_kickback_signal, level,controls_list)

        # unpack show parameters

        reason,message,self.show_timeout = Show.calculate_duration(self,self.show_params['show-timeout'])
        if reason=='error':
            self.mon.err(self,'ShowTimeout has bad time: '+self.show_params['show-timeout'])
            self.end('error','ShowTimeout has bad time: '+self.show_params['show-timeout'])
            
        self.track_count_limit = int(self.show_params['track-count-limit'])
            
        reason,message,self.interval = Show.calculate_duration (self, self.show_params['interval'])
        if reason=='error':
            self.mon.err(self,'Interval has bad time: '+self.show_params['interval'])
            self.end('error','Interval has bad time: '+self.show_params['interval'])

        if self.medialist.anon_length()==0 and self.show_params['type'] not in ('liveshow','artliveshow'):
            self.mon.err(self,'No anonymous tracks in medialist ')
            self.end('error','No anonymous tracks in medialist ')
               

        # delete eggtimer started by the parent
        if self.previous_shower is not None:
            self.previous_shower.delete_eggtimer()
            
        self.start_show()


# ********************************
# Respond to external events
# ********************************

    # exit received from another concurrent show
    def exit(self):
        Show.base_exit(self)

    # terminate Pi Presents
    def terminate(self):
        Show.base_terminate(self)


   # respond to input events
    def handle_input_event(self,symbol):
        Show.base_handle_input_event(self,symbol)

    def handle_input_event_this_show(self,symbol):
        #  check symbol against mediashow triggers
        if self.state == 'waiting' and self.show_params['trigger-start-type'] in ('input','input-persist') and symbol  ==  self.show_params['trigger-start-param']:
            self.mon.stats(self.show_params['type'],self.show_params['show-ref'],self.show_params['title'],'start trigger',
                            '','','')
            Show.delete_admin_message(self)
            self.start_list()
            
        elif self.state == 'playing' and self.show_params['trigger-end-type'] == 'input' and symbol == self.show_params['trigger-end-param']:
            self.end_trigger_signal=True
            if self.shower is not None:
                self.shower.do_operation('stop')
            elif self.current_player is not None:
                self.current_player.input_pressed('stop')
                
        elif self.state == 'playing' and self.show_params['trigger-next-type'] == 'input' and symbol == self.show_params['trigger-next-param']:
            self.mon.stats(self.show_params['type'],self.show_params['show-ref'],self.show_params['title'],'next trigger',
                            '','','')
            self.next()
        else:
            # event is not a trigger so must be internal operation
            operation=self.base_lookup_control(symbol,self.controls_list)
            if operation != '':
                self.do_operation(operation)


    # overrides base
    # service the standard operations for this show
    def do_operation(self,operation):
        # print 'do_operation ',operation
        self.mon.trace(self, operation)
        if operation == 'exit':
            self.exit()
            
        elif operation == 'stop':
            if self.level != 0 :
                # not at top so stop the show
                self.user_stop_signal=True
                # and stop the track first
                if self.current_player is not None:
                    self.current_player.input_pressed('stop')
            else:
                # at top, just stop track if running
                if self.current_player is not None:
                    self.current_player.input_pressed('stop')                    

        elif operation == 'up' and self.state == 'playing':
            # print '\nUP'
            self.previous()
            
        elif operation == 'down' and self.state == 'playing':
            self.next()

        elif operation == 'play':
            # use 'play' to start child if state=playing or to trigger the show if waiting for trigger
            if self.state == 'playing':
                if self.show_params['child-track-ref'] != '':
                    # set a signal because must stop current track before running child show
                    self.play_child_signal=True
                    self.child_track_ref=self.show_params['child-track-ref']
                    # and stop the current track if its running
                    if self.current_player is not None:
                        self.current_player.input_pressed('stop')
            else:
                if self.state == 'waiting':
                    self.mon.stats(self.show_params['type'],self.show_params['show-ref'],self.show_params['title'],'start trigger',
                            '','','')
                    Show.delete_admin_message(self)
                    self.start_list()

        elif operation in ('pause','pause-on','pause-off','mute','unmute','go'):
            if self.current_player is not None:
                self.current_player.input_pressed(operation)

        elif operation in ('no-command','null'):
            return
                
        # if the operation is omxplayer mplayer or uzbl runtime control then pass it to player if running
        elif operation[0:4] == 'omx-' or operation[0:6] == 'mplay-'or operation[0:5] == 'uzbl-':
            if self.current_player is not None:
                self.current_player.input_pressed(operation)


    def next(self):
        # stop track if running and set signal
        self.next_track_signal=True
        if self.shower is not None:
            self.shower.do_operation('stop')
        else:
            if self.current_player is not None:
                self.current_player.input_pressed('stop')


    def previous(self):
        self.previous_track_signal=True
        if self.shower is not None:
            self.shower.do_operation('stop')
        else:
            if self.current_player is not None:
                self.current_player.input_pressed('stop')


# ***************************
# Show sequencing
# ***************************

    def start_show(self):
        # initial direction from parent show
        
        self.kickback_for_next_track=self.parent_kickback_signal
        # print '\n\ninital KICKBACK from parent', self.kickback_for_next_track
   
        # start duration timer
        if self.show_timeout  != 0:
            # print 'set alarm ', self.show_timeout
            self.duration_timer = self.canvas.after(self.show_timeout*1000,self.show_timeout_stop)

        self.first_list=True

        # and start the first list of the show
        self.wait_for_trigger()

    
    def wait_for_trigger(self):
        
        # wait for trigger sets the state to waiting so that trigger events can do a start_list.
        self.state='waiting'

        self.mon.log(self,self.show_params['show-ref']+ ' '+ str(self.show_id)+ ": Waiting for trigger: "+ self.show_params['trigger-start-type'])

  
        if self.show_params['trigger-start-type'] == "input":
            
            #close the previous track to display admin message
            Show.base_shuffle(self)
            Show.base_track_ready_callback(self,False)
            Show.display_admin_message(self,self.show_params['trigger-wait-text'])

        elif self.show_params['trigger-start-type'] == "input-persist":
            if self.first_list ==True:
                #first time through track list so play the track without waiting to get to end.
                self.start_list()
            else:
                #wait for trigger while displaying previous track
                pass

        elif self.show_params['trigger-start-type'] == "start":
            # don't close the previous track to give seamless repeat of the show
            self.start_list()
            
        else:
            self.mon.err(self,"Unknown trigger: "+ self.show_params['trigger-start-type'])
            self.end('error',"Unknown trigger: "+ self.show_params['trigger-start-type'])


    # timer for repeat=interval
    def end_interval_timer(self):
        self.interval_timer_signal=True
        # print 'INTERVAL TIMER ended'
        if self.shower is not None:
            self.shower.do_operation('stop')
        elif self.current_player is not None:
            self.current_player.input_pressed('stop')       

    #  show timeout happened
    def show_timeout_stop(self):
        self.stop_timers()
        Show.base_show_timeout_stop(self)
        

    def start_list(self):
        # starts the list or any repeat having waited for trigger first.
        self.state='playing'

        # initialise track counter for the list
        self.track_count=0
       
        # start interval timer
        self.interval_timer_signal = False
        if self.interval != 0:
            self.interval_timer=self.canvas.after(self.interval*1000,self.end_interval_timer)

        # print '\nSTART LIST', self.first_list
        if  self.first_list is True:
            # first list so go to what next
            self.what_next_after_showing()
        else:
            #get first or last track depending on direction
            if self.kickback_for_next_track is True:
                self.medialist.finish()
            else:
                self.medialist.start()
            self.start_load_show_loop(self.medialist.selected_track())



# ***************************
# Track load/show loop
# ***************************  

    # track playing loop starts here
    def start_load_show_loop(self,selected_track):

        # uncomment the next line to write stats for every track
        # Show.write_stats(self,'play a track',self.show_params,selected_track)
        
        # shuffle players
        Show.base_shuffle(self)
        
        self.delete_eggtimer()

        # is child track required
        if self.show_params['child-track-ref'] != '':
            self.enable_child=True
        else:
            self.enable_child=False

    

        # load the track or show
        # params - track,enable_menu
        enable=self.enable_child & self.enable_hint
        Show.base_load_track_or_show(self,selected_track,self.what_next_after_load,self.end_shower,enable)
        

    # track has loaded so show it.
    def what_next_after_load(self,status,message):
        self.mon.log(self,'Show Id ' + str(self.show_id)+' load complete with status: ' + status +'  message: ' +message)
        if self.current_player.play_state == 'load-failed':
            self.error_signal=True
            self.what_next_after_showing()

        else:
            if self.terminate_signal is True or self.exit_signal is True or self.user_stop_signal is True:
                self.what_next_after_showing()
            else:
                self.mon.trace(self, ' - showing track')
                self.current_player.show(self.track_ready_callback,self.finished_showing,self.closed_after_showing)


    def finished_showing(self,reason,message):
        self.sr.hide_click_areas(self.controls_list)
        if self.current_player.play_state == 'show-failed':
            self.error_signal=True
        else:
            self.req_next='finished-player'
        # showing has finished with 'pause at end', showing the next track will close it after next has started showing
        self.mon.trace(self, ' - pause at end ')
        self.mon.log(self,"pause at end of showing track with reason: "+reason+ ' and message: '+ message)
        self.what_next_after_showing()


    def closed_after_showing(self,reason,message):
        self.sr.hide_click_areas(self.controls_list)
        if self.current_player.play_state == 'show-failed':
            self.error_signal=True
        else:
            self.req_next='closed-player'
        # showing has finished with closing of player but track instance is alive for hiding the x_content
        self.mon.trace(self,' - closed')
        self.mon.log(self,"Closed after showing track with reason: "+reason+ ' and message: '+ message)
        self.what_next_after_showing()

        
    # subshow or child show has ended
    def end_shower(self,show_id,reason,message):
        self.mon.log(self,self.show_params['show-ref']+ ' '+ str(self.show_id)+ ': Returned from shower with ' + reason +' ' + message)
        self.sr.hide_click_areas(self.controls_list)
        self.req_next=reason
        Show.base_end_shower(self)
        self.what_next_after_showing()

    def pretty_what_next_after_showing_state(self):
        state = '\n* terminate signal ' + str(self.terminate_signal)
        state += '\n* error signal ' + str(self.error_signal)
        state += '\n* req_next used to indicate subshow reports an error ' + self.req_next
        state += '\n* exit signal ' +  str(self.exit_signal)
        state += '\n* show timeout  signal ' + str(self.show_timeout_signal)
        state += '\n* user stop  signal ' + str(self.user_stop_signal)
        state += '\n* previous track  signal ' + str(self.previous_track_signal)
        state += '\n* next track  signal ' + str(self.next_track_signal)
        state += '\n* kickback from subshow ' + str(self.subshow_kickback_signal)
        return state +'\n'
        

    def what_next_after_showing(self):
        # print 'WHAT NEXT'
        self.mon.trace(self,self.pretty_what_next_after_showing_state())
                        
        self.track_count+=1
        # set false when child rack is to be played
        self.enable_hint=True

        # first of all deal with conditions that do not require the next track to be shown
        # some of the conditions can happen at any time, others only when a track is closed or at pause_at_end

        # need to terminate
        if self.terminate_signal is True:
            self.terminate_signal=False
            self.stop_timers()
            # set what to do after closed or unloaded
            self.ending_reason='killed'
            Show.base_close_or_unload(self)

        elif self.error_signal== True or self.req_next=='error':
            self.error_signal=False
            self.req_next=''
            self.stop_timers()
            # set what to do after closed or unloaded
            self.ending_reason='error'
            Show.base_close_or_unload(self)

        # used for exiting show from other shows, time of day, external etc.
        elif self.exit_signal is True:
            self.exit_signal=False
            self.stop_timers()
            self.ending_reason='exit'
            Show.base_close_or_unload(self)

        #  show timeout
        elif self.show_timeout_signal is True:
            self.show_timeout_signal=False
            self.stop_timers()
            self.ending_reason='user-stop'
            Show.base_close_or_unload(self)

        # user wants to stop the show
        elif self.user_stop_signal is True:
            self.user_stop_signal=False
            # print 'user stop'
            self.stop_timers()
            self.ending_reason='user-stop'
            Show.base_close_or_unload(self)


       # interval > 0. If last track has finished we are waiting for interval timer before ending the list
       # note: if medialist finishes after interval is up then this route is used to start trigger. 
        elif self.waiting_for_interval is True:
            # interval_timer_signal set by alarm clock started in start_list
            if self.interval_timer_signal is True:
                self.interval_timer_signal=False
                self.waiting_for_interval=False
                # print 'RECEIVED INTERVAL TIMER SIGNAL'
                if self.show_params['repeat']=='repeat':
                    self.wait_for_trigger()
                else:
                    self.stop_timers()
                    self.ending_reason='user-stop'
                    Show.base_close_or_unload(self)
            else:
                self.poll_for_interval_timer=self.canvas.after(1000,self.what_next_after_showing)

        else:
            self.medialist.create_new_livelist()
            escapetrack_required=self.escapetrack_required
            self.escapetrack_required=False
            # print escapetrack_required,self.medialist.new_length()
            if escapetrack_required is True and self.medialist.new_length() == 0:
                # print 'use escape track'
                index = self.medialist.index_of_track(self.show_params['escape-track-ref'])
                self.mon.log(self,'Starting Escape Track: '+ self.show_params['escape-track-ref'])
                if index >=0:
                    # don't use select the track as need to preserve mediashow sequence for returning from esacpe track
                    escape_track=self.medialist.track(index)
                    Show.write_stats(self,'play escape track',self.show_params,escape_track)
                    self.display_eggtimer()
                    # use new empty livelist so if changed works OK when return from empty track
                    self.medialist.use_new_livelist()
                    self.start_load_show_loop(escape_track)
                else:
                    self.mon.err(self,"Escape Track empty")
                    self.end('error',"Escape Track empty")

            # print 'FOR IF CHANGED',self.first_list,self.medialist.length(),self.medialist.new_length(),self.medialist.livelist_changed()
            elif self.first_list is True or self.medialist.livelist_changed() is True or (self.medialist.length() == 0 and self.medialist.new_length() == 0):                            

                if self.first_list is False:
                    # do show control
                    if self.medialist.length() == 0 and self.medialist.new_length() != 0:
                            # print 'show control empty to not empty'
                            # do show control when goes from not empty to empty only
                            self.show_control(self.show_params['show-control-not-empty'])
                            
                    elif self.medialist.length() != 0 and self.medialist.new_length() == 0:
                            # print 'show control not empty to empty'
                            # do show control when goes from empty to not empty only
                            self.show_control(self.show_params['show-control-empty'])  

                self.first_list=False
                
                if self.medialist.new_length()==0 and self.show_params['repeat']=='repeat':
                    # start empty track/show
                    index = self.medialist.index_of_track(self.show_params['empty-track-ref'])
                    self.mon.log(self,'Starting Empty Track: '+ self.show_params['empty-track-ref'])
                    if index >=0:
                        # don't use select the track as need to preserve mediashow sequence for returning from empty track/show
                        empty_track=self.medialist.track(index)
                        # print 'play empty track', empty_track['title'],empty_track['type']
                        Show.write_stats(self,'play empty track',self.show_params,empty_track)
                        if empty_track['type'] =='show':
                            self.escapetrack_required=True
                        
                        self.display_eggtimer()
                        # use new empty livelist so if changed works OK when return from empty track
                        self.medialist.use_new_livelist()
                        self.start_load_show_loop(empty_track)
                    else:
                        self.mon.err(self,"List Empty Track not specified")
                        self.end('error',"List Empty Track not specified")
  

                elif self.medialist.new_length()==0 and self.show_params['repeat']=='single-run':
                    if self.level != 0:
                        self.kickback_for_next_track=False
                        self.subshow_kickback_signal=False
                        self.end('normal',"End of single run - Return from Sub Show")
                    else:
                        # end of single run and at top - exit the show
                        self.stop_timers()
                        self.ending_reason='user-stop'
                        Show.base_close_or_unload(self)

                else:
                    #changed but new is not zero
                    self.medialist.use_new_livelist()
                    # print 'livelist changed and not empty'
                    self.start_list()               


            # otherwise consider operation that might show the next track          
            else:
                # print 'ELSE',self.medialist.at_end()
                # report error if medilaist is empty (liveshow will not get this far
                if self.medialist.length()==0:
                    self.mon.err(self,"Medialist empty")
                    self.end('error',"Medialist empty")
                    
                # setup default direction for next track as normally goes forward unless kicked back
                self.kickback_for_next_track=False
                # print 'init direction to False at begin of what_next_after showing', self.kickback_for_next_track
                # end trigger from input, or track count
                if self.end_trigger_signal is True or (self.track_count_limit >0  and self.track_count == self.track_count_limit):
                    self.end_trigger_signal=False
                    # repeat so test start trigger
                    if self.show_params['repeat'] == 'repeat':
                        self.stop_timers()
                        # print 'END TRIGGER restart'
                        self.wait_for_trigger()
                    else:
                        # single run so exit show
                        if self.level != 0:
                            self.kickback_for_next_track=False
                            self.subshow_kickback_signal=False
                            # print 'single run exit subshow'
                            self.end('normal',"End of single run - Return from Sub Show")
                        else:
                            # end of single run and at top - exit the show
                            self.stop_timers()
                            # print 'ENDING'
                            self.ending_reason='user-stop'
                            Show.base_close_or_unload(self)                   

                # user wants to play child
                elif self.play_child_signal is True:
                    self.play_child_signal=False
                    index = self.medialist.index_of_track(self.child_track_ref)
                    if index >=0:
                        # don't use select the track as need to preserve mediashow sequence for returning from child
                        child_track=self.medialist.track(index)
                        Show.write_stats(self,'play child',self.show_params,child_track)
                        self.display_eggtimer()
                        self.enable_hint=False
                        self.start_load_show_loop(child_track)
                    else:
                        self.mon.err(self,"Child not found in medialist: "+ self.child_track_ref)
                        self.ending_reason='error'
                        Show.base_close_or_unload(self)



                # skip to next track on user input or after subshow
                elif self.next_track_signal is True:
                    # print 'skip forward test' ,self.subshow_kickback_signal
                    if self.next_track_signal is True or self.subshow_kickback_signal is False:
                        self.next_track_signal=False
                        self.kickback_for_next_track=False
                        if self.medialist.at_end() is True:
                            # medialist_at_end can give false positive for shuffle
                            if  self.show_params['sequence'] == "ordered" and self.show_params['repeat'] == 'repeat':
                                self.wait_for_trigger()
                            elif  self.show_params['sequence'] == "ordered" and self.show_params['repeat'] == 'single-run':
                                if self.level != 0:
                                    self.kickback_for_next_track=False
                                    self.subshow_kickback_signal=False
                                    # print 'end subshow skip forward test, self. direction is ' ,self.kickback_for_next_track
                                    self.end('normal',"Return from Sub Show")
                                else:
                                    # end of single run and at top - exit the show
                                    self.stop_timers()
                                    self.ending_reason='user-stop'
                                    Show.base_close_or_unload(self)
                            else:
                                # shuffling  - just do next track
                                self.kickback_for_next_track=False
                                self.medialist.next(self.show_params['sequence'])
                                self.start_load_show_loop(self.medialist.selected_track())      
                        else:
                            # not at end just do next track
                            self.medialist.next(self.show_params['sequence'])
                            self.start_load_show_loop(self.medialist.selected_track())


                # skip to previous track on user input or after subshow
                elif self.previous_track_signal is True or self.subshow_kickback_signal is True:
                    # print 'skip backward test, subshow kickback is' ,self.subshow_kickback_signal
                    self.subshow_kickback_signal=False
                    self.previous_track_signal=False
                    self.kickback_for_next_track=True
                    # medialist_at_start can give false positive for shuffle
                    if self.medialist.at_start() is True:
                        # print 'AT START'
                        if  self.show_params['sequence'] == "ordered" and self.show_params['repeat'] == 'repeat':
                            self.kickback_for_next_track=True
                            self.wait_for_trigger()
                        elif  self.show_params['sequence'] == "ordered" and self.show_params['repeat'] == 'single-run':
                            if self.level != 0:
                                self.kickback_for_next_track=True
                                self.subshow_kickback_signal=True
                                # print 'end subshow skip forward test, self. direction is ' ,self.kickback_for_next_track
                                self.end('normal',"Return from Sub Show")
                            else:
                                # end of single run and at top - exit the show
                                self.stop_timers()
                                self.ending_reason='user-stop'
                                Show.base_close_or_unload(self)
                        else:
                            # shuffling  - just do previous track
                            self.kickback_for_next_track=True
                            self.medialist.previous(self.show_params['sequence'])
                            self.start_load_show_loop(self.medialist.selected_track())               
                    else:
                        # not at end just do next track
                        self.medialist.previous(self.show_params['sequence'])              
                        self.start_load_show_loop(self.medialist.selected_track())


                    

                # AT END OF MEDIALIST
                elif self.medialist.at_end() is True:
                    # print 'MEDIALIST AT END'

                    # interval>0 and list finished so wait for the interval timer
                    if self.show_params['sequence'] == "ordered"  and self.interval > 0 and self.interval_timer_signal==False:
                        self.waiting_for_interval=True
                        # print 'WAITING FOR INTERVAL'
                        Show.base_shuffle(self)
                        Show.base_track_ready_callback(self,False)
                        self.poll_for_interval_timer=self.canvas.after(200,self.what_next_after_showing) 

                    # interval=0   
                    #elif self.show_params['sequence'] == "ordered" and self.show_params['repeat'] == 'repeat' and self.show_params['trigger-end-type']== 'interval' and int(self.show_params['trigger-end-param']) == 0:
                        #self.medialist.next(self.show_params['sequence'])
                        # self.start_load_show_loop(self.medialist.selected_track())

                    # shuffling so there is no end condition, get out of end test
                    elif self.show_params['sequence'] == "shuffle":
                        self.medialist.next(self.show_params['sequence'])
                        self.start_load_show_loop(self.medialist.selected_track())
                        
                    # nothing special to do at end of list, just repeat or exit
                    elif self.show_params['sequence'] == "ordered":
                        if self.show_params['repeat'] == 'repeat':
                            # print 'repeating at end of list'
                            self.wait_for_trigger()
                        else:
                            # single run
                            # if not at top return to parent
                            if self.level !=0:
                                self.end('normal',"End of Single Run")
                            else:
                                # at top so close the show
                                # print 'closing show'
                                self.stop_timers()
                                self.ending_reason='user-stop'
                                Show.base_close_or_unload(self)
                            
                    else:
                        self.mon.err(self,"Unhandled playing event at end of list: "+self.show_params['sequence'] +' with ' + self.show_params['repeat']+" of "+ self.show_params['trigger-end-param'])
                        self.end('error',"Unhandled playing event at end of list: "+self.show_params['sequence'] +' with ' + self.show_params['repeat']+" of "+ self.show_params['trigger-end-param'])
                    
                elif self.medialist.at_end() is False:
                    # nothing special just do the next track
                    # print 'nothing special'
                    self.medialist.next(self.show_params['sequence'])
                    self.start_load_show_loop(self.medialist.selected_track())
                          
                else:
                    # unhandled state
                    self.mon.err(self,"Unhandled playing event: "+self.show_params['sequence'] +' with ' + self.show_params['repeat']+" of "+ self.show_params['trigger-end-param'])
                    self.end('error',"Unhandled playing event: "+self.show_params['sequence'] +' with ' + self.show_params['repeat']+" of "+ self.show_params['trigger-end-param'])

   
   
# *********************
# Interface with other shows/players to reduce black gaps
# *********************

    # called just before a track is shown to remove the  previous track from the screen
    # and if necessary close it
    def track_ready_callback(self,enable_show_background):
        self.delete_eggtimer()

        # get control bindings for this show
        # needs to be done for each track as track can override the show controls
        if self.show_params['disable-controls'] == 'yes':
            self.controls_list=[]
        else:
            reason,message,self.controls_list= self.controlsmanager.get_controls(self.show_params['controls'])
            if reason=='error':
                self.mon.err(self,message)
                self.end('error',"error in controls: " + message)
                return

            # print 'controls',reason,self.show_params['controls'],self.controls_list
            #merge controls from the track
            controls_text=self.current_player.get_links()
            reason,message,track_controls=self.controlsmanager.parse_controls(controls_text)
            if reason == 'error':
                self.mon.err(self,message + " in track: "+ self.current_player.track_params['track-ref'])
                self.error_signal=True
                self.what_next_after_showing()
            self.controlsmanager.merge_controls(self.controls_list,track_controls)

        # enable the click-area that are in the list of controls
        self.sr.enable_click_areas(self.controls_list)
        Show.base_track_ready_callback(self,enable_show_background)

   
    # callback from begining of a subshow, provide previous player to called show        
    def subshow_ready_callback(self):
        return Show.base_subshow_ready_callback(self)


# *********************
# End the show
# *********************
    def end(self,reason,message):
        Show.base_end(self,reason,message)



    def stop_timers(self):
        # clear outstanding time of day events for this show
        # self.tod.clear_times_list(id(self))

        if self.poll_for_interval_timer is not None:
            self.canvas.after_cancel(self.poll_for_interval_timer)
            self.poll_for_interval_timer=None
            
        if self.interval_timer is not None:
            self.canvas.after_cancel(self.interval_timer)
            self.interval_timer=None
            
        if self.duration_timer is not None:
            self.canvas.after_cancel(self.duration_timer)
            self.duration_timer=None
Example #22
0
    def __init__(self):

        self.pipresents_issue = "1.2"
        self.pipresents_minorissue = '1.2.3f'
        self.nonfull_window_width = 0.5  # proportion of width
        self.nonfull_window_height = 0.6  # proportion of height
        self.nonfull_window_x = 0  # position of top left corner
        self.nonfull_window_y = 0  # position of top left corner

        StopWatch.global_enable = False

        #****************************************
        # Initialisation
        # ***************************************
        # get command line options
        self.options = command_options()

        # get pi presents code directory
        pp_dir = sys.path[0]
        self.pp_dir = pp_dir

        if not os.path.exists(pp_dir + "/pipresents.py"):
            tkMessageBox.showwarning("Pi Presents",
                                     "Bad Application Directory")
            exit()

        #Initialise logging
        Monitor.log_path = pp_dir
        self.mon = Monitor()
        self.mon.on()
        # 0  - errors only
        # 1  - errors and warnings
        # 2  - everything
        if self.options['debug'] == True:
            Monitor.global_enable = 2
        else:
            Monitor.global_enable = 0

        # UNCOMMENT THIS TO LOG WARNINGS AND ERRORS ONLY
        # Monitor.global_enable=1

        self.mon.log(
            self,
            "\n\n\n\n\n*****************\nPi Presents is starting, Version:" +
            self.pipresents_minorissue)
        self.mon.log(self, "Version: " + self.pipresents_minorissue)
        self.mon.log(self, " OS and separator:" + os.name + '  ' + os.sep)
        self.mon.log(self, "sys.path[0] -  location of code: " + sys.path[0])
        # self.mon.log(self,"os.getenv('HOME') -  user home directory (not used): " + os.getenv('HOME'))
        # self.mon.log(self,"os.path.expanduser('~') -  user home directory: " + os.path.expanduser('~'))

        # optional other classes used
        self.ppio = None
        self.tod = None

        #get profile path from -p option
        if self.options['profile'] <> "":
            self.pp_profile_path = "/pp_profiles/" + self.options['profile']
        else:
            self.pp_profile_path = "/pp_profiles/pp_profile"

    #get directory containing pp_home from the command,
        if self.options['home'] == "":
            home = os.path.expanduser('~') + os.sep + "pp_home"
        else:
            home = self.options['home'] + os.sep + "pp_home"
        self.mon.log(self, "pp_home directory is: " + home)

        #check if pp_home exists.
        # try for 10 seconds to allow usb stick to automount
        # fall back to pipresents/pp_home
        self.pp_home = pp_dir + "/pp_home"
        found = False
        for i in range(1, 10):
            self.mon.log(self,
                         "Trying pp_home at: " + home + " (" + str(i) + ')')
            if os.path.exists(home):
                found = True
                self.pp_home = home
                break
            time.sleep(1)
        if found == True:
            self.mon.log(
                self,
                "Found Requested Home Directory, using pp_home at: " + home)
        else:
            self.mon.log(
                self,
                "FAILED to find requested home directory, using default to display error message: "
                + self.pp_home)

        #check profile exists, if not default to error profile inside pipresents
        self.pp_profile = self.pp_home + self.pp_profile_path
        if os.path.exists(self.pp_profile):
            self.mon.log(
                self, "Found Requested profile - pp_profile directory is: " +
                self.pp_profile)
        else:
            self.pp_profile = pp_dir + "/pp_home/pp_profiles/pp_profile"
            self.mon.log(
                self,
                "FAILED to find requested profile, using default to display error message: pp_profile"
            )

        if self.options['verify'] == True:
            val = Validator()
            if val.validate_profile(None, pp_dir, self.pp_home,
                                    self.pp_profile, self.pipresents_issue,
                                    False) == False:
                tkMessageBox.showwarning("Pi Presents", "Validation Failed")
                exit()

        # open the resources
        self.rr = ResourceReader()
        # read the file, done once for all the other classes to use.
        if self.rr.read(pp_dir, self.pp_home, self.pp_profile) == False:
            self.end('error', 'cannot find resources.cfg')

        #initialise and read the showlist in the profile
        self.showlist = ShowList()
        self.showlist_file = self.pp_profile + "/pp_showlist.json"
        if os.path.exists(self.showlist_file):
            self.showlist.open_json(self.showlist_file)
        else:
            self.mon.err(self, "showlist not found at " + self.showlist_file)
            self.end('error', 'showlist not found')

        # check profile and Pi Presents issues are compatible
        if float(self.showlist.sissue()) <> float(self.pipresents_issue):
            self.mon.err(
                self, "Version of profile " + self.showlist.sissue() +
                " is not  same as Pi Presents, must exit")
            self.end('error', 'wrong version of profile')

        # get the 'start' show from the showlist
        index = self.showlist.index_of_show('start')
        if index >= 0:
            self.showlist.select(index)
            self.starter_show = self.showlist.selected_show()
        else:
            self.mon.err(self, "Show [start] not found in showlist")
            self.end('error', 'start show not found')

# ********************
# SET UP THE GUI
# ********************
#turn off the screenblanking and saver
        if self.options['noblank'] == True:
            call(["xset", "s", "off"])
            call(["xset", "s", "-dpms"])

        self.root = Tk()

        self.title = 'Pi Presents - ' + self.pp_profile
        self.icon_text = 'Pi Presents'
        self.root.title(self.title)
        self.root.iconname(self.icon_text)
        self.root.config(bg='black')

        # get size of the screen
        self.screen_width = self.root.winfo_screenwidth()
        self.screen_height = self.root.winfo_screenheight()

        # set window dimensions and decorations
        if self.options['fullscreen'] == True:

            self.root.attributes('-fullscreen', True)
            os.system('unclutter &')
            self.window_width = self.screen_width
            self.window_height = self.screen_height
            self.window_x = 0
            self.window_y = 0
            self.root.geometry("%dx%d%+d%+d" %
                               (self.window_width, self.window_height,
                                self.window_x, self.window_y))
            self.root.attributes('-zoomed', '1')
        else:
            self.window_width = int(self.screen_width *
                                    self.nonfull_window_width)
            self.window_height = int(self.screen_height *
                                     self.nonfull_window_height)
            self.window_x = self.nonfull_window_x
            self.window_y = self.nonfull_window_y
            self.root.geometry("%dx%d%+d%+d" %
                               (self.window_width, self.window_height,
                                self.window_x, self.window_y))

        #canvas covers the whole window
        self.canvas_height = self.screen_height
        self.canvas_width = self.screen_width

        # make sure focus is set.
        self.root.focus_set()

        #define response to main window closing.
        self.root.protocol("WM_DELETE_WINDOW", self.exit_pressed)

        #setup a canvas onto which will be drawn the images or text
        self.canvas = Canvas(self.root, bg='black')

        self.canvas.config(height=self.canvas_height,
                           width=self.canvas_width,
                           highlightthickness=0)
        # self.canvas.pack()
        self.canvas.place(x=0, y=0)

        self.canvas.focus_set()

        # ****************************************
        # INITIALISE THE INPUT DRIVERS
        # ****************************************

        # looks after bindings between symbolic names and internal operations
        controlsmanager = ControlsManager()
        if controlsmanager.read(pp_dir, self.pp_home,
                                self.pp_profile) == False:
            self.end('error', 'cannot find or error in controls.cfg.cfg')
        else:
            controlsmanager.parse_defaults()

        # each driver takes a set of inputs, binds them to symboic names
        # and sets up a callback which returns the symbolic name when an input event occurs/

        # use keyboard driver to bind keys to symbolic names and to set up callback
        kbd = KbdDriver()
        if kbd.read(pp_dir, self.pp_home, self.pp_profile) == False:
            self.end('error', 'cannot find or error in keys.cfg')
        kbd.bind_keys(self.root, self.input_pressed)

        self.sr = ScreenDriver()
        # read the screen click area config file
        if self.sr.read(pp_dir, self.pp_home, self.pp_profile) == False:
            self.end('error', 'cannot find screen.cfg')

        # create click areas on the canvas, must be polygon as outline rectangles are not filled as far as find_closest goes
        reason, message = self.sr.make_click_areas(self.canvas,
                                                   self.input_pressed)
        if reason == 'error':
            self.mon.err(self, message)
            self.end('error', message)

# ****************************************
# INITIALISE THE APPLICATION AND START
# ****************************************
        self.shutdown_required = False

        #kick off GPIO if enabled by command line option
        if self.options['gpio'] == True:
            from pp_gpio import PPIO
            # initialise the GPIO
            self.ppio = PPIO()
            # PPIO.gpio_enabled=False
            if self.ppio.init(pp_dir, self.pp_home, self.pp_profile,
                              self.canvas, 50, self.gpio_pressed) == False:
                self.end('error', 'gpio error')

            # and start polling gpio
            self.ppio.poll()

        #kick off the time of day scheduler
        self.tod = TimeOfDay()
        self.tod.init(pp_dir, self.pp_home, self.canvas, 500)
        self.tod.poll()

        # Create list of start shows initialise them and then run them
        self.run_start_shows()

        #start tkinter
        self.root.mainloop()