def check_cache(zip_list): """Check to see if any zipfiles are invalid, and if so extract the cache.""" global copy_process from BEE2_config import GEN_OPTS LOGGER.info('Checking cache...') cache_packs = GEN_OPTS.get_int('General', 'cache_pack_count') # We need to match the number of packages too, to account for removed ones. cache_stale = (len(packageLoader.packages) == cache_packs) or any( pack.is_stale() for pack in packageLoader.packages.values() ) if not cache_stale: # We've already done the copying.. LOGGER.info('Cache is still fresh, skipping extraction') done_callback() return copy_process = multiprocessing.Process( target=do_copy, args=(zip_list, currently_done), ) copy_process.daemon = True LOGGER.info('Starting background extraction process!') copy_process.start() TK_ROOT.after(UPDATE_INTERVAL, update)
def check_cache(zip_list): """Check to see if any zipfiles are invalid, and if so extract the cache.""" global copy_process from BEE2_config import GEN_OPTS LOGGER.info('Checking cache...') cache_packs = GEN_OPTS.get_int('General', 'cache_pack_count') # We need to match the number of packages too, to account for removed ones. cache_stale = (len(packageLoader.packages) == cache_packs) or any( pack.is_stale() for pack in packageLoader.packages.values()) if not cache_stale: # We've already done the copying.. LOGGER.info('Cache is still fresh, skipping extraction') done_callback() return copy_process = multiprocessing.Process( target=do_copy, args=(zip_list, currently_done), ) copy_process.daemon = True LOGGER.info('Starting background extraction process!') copy_process.start() TK_ROOT.after(UPDATE_INTERVAL, update)
def load_backup(zip_file): """Load in a backup file.""" maps = [] puzzles = [ file[:-4] # Strip extension for file in zip_names(zip_file) if file.endswith('.p2c') ] # Each P2C init requires reading in the properties file, so this may take # some time. Use a loading screen. reading_loader.set_length('READ', len(puzzles)) LOGGER.info('Loading {} maps..', len(puzzles)) with reading_loader: for file in puzzles: new_map = P2C.from_file(file, zip_file) maps.append(new_map) LOGGER.debug( 'Loading {} map "{}"', 'coop' if new_map.is_coop else 'sp', new_map.title, ) reading_loader.step('READ') LOGGER.info('Done!') # It takes a while before the detail headers update positions, # so delay a refresh call. TK_ROOT.after(500, UI['game_details'].refresh) return maps
def start_copying(zip_list): global copy_process copy_process = multiprocessing.Process( target=do_copy, args=(zip_list, currently_done), ) copy_process.daemon = True LOGGER.info('Starting background process!') copy_process.start() TK_ROOT.after(UPDATE_INTERVAL, update)
def fx_blockable(sound: str) -> None: """Play a sound effect. This waits for a certain amount of time between retriggering sounds so they don't overlap. """ global _play_repeat_sfx if play_sound and _play_repeat_sfx: fx(sound) _play_repeat_sfx = False TK_ROOT.after(75, _reset_fx_blockable)
def fx_blockable(sound): """Play a sound effect. This waits for a certain amount of time between retriggering sounds so they don't overlap. """ global _play_repeat_sfx if play_sound and _play_repeat_sfx: fx(sound) _play_repeat_sfx = False TK_ROOT.after(75, _reset_fx_blockable)
def play_sample(self, e=None): pass """Play a sample of music. If music is being played it will be stopped instead. """ if self.cur_file is None: return if self.sample is not None: self.stop() return try: sound = pyglet.media.load(self.cur_file, streaming=False) # AVbin raises it's own error if the file isn't found.. except (FileNotFoundError, pyglet.media.MediaFormatException): self.stop_callback() LOGGER.error('Sound sample not found: "{}"', self.cur_file) return # Abort if music isn't found.. self.sample = sound.play() self.after = TK_ROOT.after( int(sound.duration * 1000), self._finished, ) self.start_callback()
def flash_count(): """Flash the counter between 0 and 100 when on.""" should_cont = False for var in (count_brush, count_entity, count_overlay): if not var.should_flash: continue # Abort when it shouldn't be flashing if var.get() == 0: var.set(100) else: var.set(0) should_cont = True if should_cont: TK_ROOT.after(750, flash_count)
def update(): """Check the progress of the copying until it's done. """ progress_var.set(1000 * currently_done.value / res_count, ) export_btn_text.set('Extracting Resources ({!s}/{!s})...'.format( currently_done.value, res_count, )) if not copy_process.is_alive(): # We've finished copying export_btn_text.set('Export...') update_modtimes() done_callback() else: # Coninuously tell TK to re-run this, so we update # without deadlocking the CPU TK_ROOT.after(UPDATE_INTERVAL, update)
def play_sample(self, e=None): pass """Play a sample of music. If music is being played it will be stopped instead. """ if self.cur_file is None: return if self.sample is not None: self.stop() return with self.system: try: file = self.system[self.cur_file] except (KeyError, FileNotFoundError): self.stop_callback() LOGGER.error('Sound sample not found: "{}"', self.cur_file) return # Abort if music isn't found.. # TODO: Pyglet doesn't support direct streams, so we have to # TODO: extract sounds to disk first. fsystem = self.system.get_system(file) if isinstance(fsystem, RawFileSystem): # Special case, it's directly lying on the disk - # We can just pass that along. disk_filename = os.path.join(fsystem.path, file.path) LOGGER.info('Directly playing sample "{}"...', disk_filename) else: # In a filesystem, we need to extract it. # SAMPLE_WRITE_PATH + the appropriate extension. disk_filename = str(SAMPLE_WRITE_PATH.with_suffix(os.path.splitext(self.cur_file)[1])) LOGGER.info('Extracting music sample to "{}"...', disk_filename) with self.system.get_system(file), file.open_bin() as fsrc: with open(disk_filename, 'wb') as fdest: shutil.copyfileobj(fsrc, fdest) try: sound = pyglet.media.load(disk_filename, streaming=False) # type: Source except MediaFormatException: self.stop_callback() LOGGER.exception('Sound sample not valid: "{}"', self.cur_file) return # Abort if music isn't found.. if self.start_time: try: sound.seek(self.start_time) except CannotSeekException: LOGGER.exception('Cannot seek in "{}"!', self.cur_file) self.sample = sound.play() self.after = TK_ROOT.after( int(sound.duration * 1000), self._finished, ) self.start_callback()
def play_sample(self, e=None): pass """Play a sample of music. If music is being played it will be stopped instead. """ if self.cur_file is None: return if self.sample is not None: self.stop() return with self.system: try: file = self.system[self.cur_file] except (KeyError, FileNotFoundError): self.stop_callback() LOGGER.error('Sound sample not found: "{}"', self.cur_file) return # Abort if music isn't found.. # TODO: Pyglet doesn't support direct streams, so we have to # TODO: extract sounds to disk first. fsystem = self.system.get_system(file) if isinstance(fsystem, RawFileSystem): # Special case, it's directly lying on the disk - # We can just pass that along. disk_filename = os.path.join(fsystem.path, file.path) else: # In a filesystem, we need to extract it. # SAMPLE_WRITE_PATH + the appropriate extension. disk_filename = SAMPLE_WRITE_PATH.with_suffix( os.path.splitext(self.cur_file)[1]) with self.system.get_system(file), file.open_bin() as fsrc: with open(disk_filename, 'wb') as fdest: shutil.copyfileobj(fsrc, fdest) try: sound = pyglet.media.load(disk_filename, streaming=False) # type: Source except MediaFormatException: self.stop_callback() LOGGER.exception('Sound sample not valid: "{}"', self.cur_file) return # Abort if music isn't found.. if self.start_time: try: sound.seek(self.start_time) except CannotSeekException: LOGGER.exception('Cannot seek in "{}"!', self.cur_file) self.sample = sound.play() self.after = TK_ROOT.after( int(sound.duration * 1000), self._finished, ) self.start_callback()
def play_sample(self, e: Event = None) -> None: pass """Play a sample of music. If music is being played it will be stopped instead. """ if self.cur_file is None: return if self.sample is not None: self.stop() return self._close_handles() with self.system: try: file = self.system[self.cur_file] except (KeyError, FileNotFoundError): self.stop_callback() LOGGER.error('Sound sample not found: "{}"', self.cur_file) return # Abort if music isn't found.. child_sys = self.system.get_system(file) # Special case raw filesystems - Pyglet is more efficient # if it can just open the file itself. if isinstance(child_sys, RawFileSystem): load_path = os.path.join(child_sys.path, file.path) self._cur_sys = self._handle = None LOGGER.debug('Loading music directly from {!r}', load_path) else: # Use the file objects directly. load_path = self.cur_file self._cur_sys = child_sys self._cur_sys.open_ref() self._handle = file.open_bin() LOGGER.debug('Loading music via {!r}', self._handle) try: sound = pyglet.media.load(load_path, self._handle) except (MediaDecodeException, MediaFormatException): self.stop_callback() LOGGER.exception('Sound sample not valid: "{}"', self.cur_file) return # Abort if music isn't found.. if self.start_time: try: sound.seek(self.start_time) except CannotSeekException: LOGGER.exception('Cannot seek in "{}"!', self.cur_file) self.sample = sound.play() self.after = TK_ROOT.after( int(sound.duration * 1000), self._finished, ) self.start_callback()
def enter_handler(e): """Schedule showing the tooltip.""" nonlocal event_id if targ_widget.tooltip_text: if hasattr(targ_widget, 'instate'): if not targ_widget.instate(('!disabled',)): return event_id = TK_ROOT.after( delay, after_complete, )
def enter_handler(event: tk.Event): """Schedule showing the tooltip.""" nonlocal event_id if targ_widget.tooltip_text: if check_disabled and not targ_widget.instate(('!disabled',)): return event_id = TK_ROOT.after( delay, after_complete, event.x_root, event.y_root, )
def update(): """Check the progress of the copying until it's done. """ progress_var.set( 1000 * currently_done.value / res_count, ) export_btn_text.set( 'Extracting Resources ({!s}/{!s})...'.format( currently_done.value, res_count, ) ) if not copy_process.is_alive(): # We've finished copying export_btn_text.set( 'Export...' ) done_callback() else: # Coninuously tell TK to re-run this, so we update # without deadlocking the CPU TK_ROOT.after(UPDATE_INTERVAL, update)
def enter_handler(event): """Schedule showing the tooltip.""" nonlocal event_id # noinspection PyUnresolvedReferences, PyProtectedMember if targ_widget._bee2_tooltip_text or targ_widget._bee2_tooltip_img is not None: # We know it has this method from above! # noinspection PyUnresolvedReferences if check_disabled and not targ_widget.instate(('!disabled',)): return event_id = TK_ROOT.after( delay, after_complete, event.x_root, event.y_root, )
def enter_handler(event): """Schedule showing the tooltip.""" nonlocal event_id # noinspection PyUnresolvedReferences, PyProtectedMember if targ_widget._bee2_tooltip_text or targ_widget._bee2_tooltip_img is not None: # We know it has this method from above! # noinspection PyUnresolvedReferences if check_disabled and not targ_widget.instate(('!disabled', )): return event_id = TK_ROOT.after( delay, after_complete, event.x_root, event.y_root, )
def play_sample(self, e=None): pass """Play a sample of music. If music is being played it will be stopped instead. """ if self.cur_file is None: return if self.sample is not None: self.stop() return try: file = self.system[self.cur_file] except KeyError: self.stop_callback() LOGGER.error('Sound sample not found: "{}"', self.cur_file) return # Abort if music isn't found.. # TODO: Pyglet doesn't support direct streams, so we have to # TODO: extract sounds to disk first. with self.system.get_system(file), file.open_bin() as fsrc, open( SAMPLE_WRITE_PATH + os.path.splitext(self.cur_file)[1], 'wb', ) as fdest: shutil.copyfileobj(fsrc, fdest) try: sound = pyglet.media.load(fdest.name, streaming=False) except pyglet.media.MediaFormatException: self.stop_callback() LOGGER.exception('Sound sample not valid: "{}"', self.cur_file) return # Abort if music isn't found.. self.sample = sound.play() self.after = TK_ROOT.after( int(sound.duration * 1000), self._finished, ) self.start_callback()
def block_fx(): """Block fx_blockable() for a short time.""" global _play_repeat_sfx _play_repeat_sfx = False TK_ROOT.after(50, _reset_fx_blockable)
if __name__ == '__main__': utils.init_logging() LOGGER = utils.getLogger('BEE2') init(True, log_level='DEBUG') # Generate a bunch of log messages to test the window. def errors(): # Use a generator to easily run these functions with a delay. yield LOGGER.info('Info Message') yield LOGGER.critical('Critical Message') yield LOGGER.warning('Warning') try: raise ValueError('An error') except ValueError: yield LOGGER.exception('Error message') yield LOGGER.warning('Post-Exception warning') yield LOGGER.info('Info') yield LOGGER.debug('Debug Message') err_iterator = errors() def next_error(): # Use False since functions return None usually if next(err_iterator, False) is not False: TK_ROOT.after(1000, next_error) TK_ROOT.after(1000, next_error) TK_ROOT.mainloop()
def next_error(): # Use False since functions return None usually if next(err_iterator, False) is not False: TK_ROOT.after(1000, next_error)
toolbar_frame.grid(row=0, column=0, columnspan=3, sticky='W') ui_new_backup() @atexit.register def deinit(): """When shutting down, we need to close the backup zipfile.""" for name in ('backup_zip', 'unsaved_file'): obj = BACKUPS[name] if obj is not None: obj.close() if __name__ == '__main__': # Run this standalone. init_application() TK_ROOT.deiconify() def fix_details(): # It takes a while before the detail headers update positions, # so delay a refresh call. TK_ROOT.update_idletasks() UI['game_details'].refresh() TK_ROOT.after(500, fix_details) TK_ROOT.mainloop()
width=11, ).grid(row=0, column=2) ttk.Button( toolbar_frame, text='.. As', command=ui_save_backup_as, width=5, ).grid(row=0, column=3) toolbar_frame.grid(row=0, column=0, columnspan=3, sticky='W') ui_new_backup() if __name__ == '__main__': # Run this standalone. init_application() TK_ROOT.deiconify() def fix_details(): # It takes a while before the detail headers update positions, # so delay a refresh call. TK_ROOT.update_idletasks() UI['game_details'].refresh() TK_ROOT.after(500, fix_details) TK_ROOT.mainloop()
if __name__ == '__main__': utils.init_logging() init(True, log_level=logging.DEBUG) # Generate a bunch of log messages to test the window. def errors(): # Use a generator to easily run these functions with a delay. yield LOGGER.info('Info Message') yield LOGGER.critical('Critical Message') yield LOGGER.warning('Warning') try: raise ValueError('An error') except ValueError: yield LOGGER.exception('Error message') yield LOGGER.warning('Post-Exception warning') yield LOGGER.info('Info') yield LOGGER.debug('Debug Message') err_iterator = errors() def next_error(): # Use False since functions return None usually if next(err_iterator, False) is not False: TK_ROOT.after(1000, next_error) TK_ROOT.after(1000, next_error) TK_ROOT.mainloop()