Esempio n. 1
0
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
Esempio n. 2
0
    def check_queue():
        """Update stages from the parent process."""
        nonlocal force_ontop
        had_values = False
        while PIPE_REC.poll():  # Pop off all the values.
            had_values = True
            operation, scr_id, args = PIPE_REC.recv()
            if operation == 'init':
                # Create a new loadscreen.
                is_main, title, stages = args
                screen = (SplashScreen if is_main else LoadScreen)(scr_id,
                                                                   title,
                                                                   force_ontop,
                                                                   stages)
                SCREENS[scr_id] = screen
            elif operation == 'set_force_ontop':
                [force_ontop] = args
                for screen in SCREENS.values():
                    screen.win.attributes('-topmost', force_ontop)
            else:
                try:
                    func = getattr(SCREENS[scr_id], 'op_' + operation)
                except AttributeError:
                    raise ValueError('Bad command "{}"!'.format(operation))
                try:
                    func(*args)
                except Exception:
                    raise Exception(operation)

        # Continually re-run this function in the TK loop.
        # If we didn't find anything in the pipe, wait longer.
        # Otherwise we hog the CPU.
        TK_ROOT.after(1 if had_values else 200, check_queue)
Esempio n. 3
0
    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)
Esempio n. 4
0
def run_screen(
    pipe_send: multiprocessing.connection.Connection,
    pipe_rec: multiprocessing.connection.Connection,
    # Pass in various bits of translated text
    # so we don't need to do it here.
    translations,
):
    """Runs in the other process, with an end of a pipe for input."""
    global PIPE_REC, PIPE_SEND
    PIPE_SEND = pipe_send
    PIPE_REC = pipe_rec
    TRANSLATION.update(translations)

    force_ontop = True

    def check_queue():
        """Update stages from the parent process."""
        nonlocal force_ontop
        had_values = False
        while PIPE_REC.poll():  # Pop off all the values.
            had_values = True
            operation, scr_id, args = PIPE_REC.recv()
            if operation == 'init':
                # Create a new loadscreen.
                is_main, title, stages = args
                screen = (SplashScreen if is_main else LoadScreen)(scr_id,
                                                                   title,
                                                                   force_ontop,
                                                                   stages)
                SCREENS[scr_id] = screen
            elif operation == 'set_force_ontop':
                [force_ontop] = args
                for screen in SCREENS.values():
                    screen.win.attributes('-topmost', force_ontop)
            else:
                try:
                    func = getattr(SCREENS[scr_id], 'op_' + operation)
                except AttributeError:
                    raise ValueError('Bad command "{}"!'.format(operation))
                try:
                    func(*args)
                except Exception:
                    raise Exception(operation)

        # Continually re-run this function in the TK loop.
        # If we didn't find anything in the pipe, wait longer.
        # Otherwise we hog the CPU.
        TK_ROOT.after(1 if had_values else 200, check_queue)

    TK_ROOT.after(10, check_queue)
    TK_ROOT.mainloop()  # Infinite loop, until the entire process tree quits.
Esempio n. 5
0
    def on_type(*args) -> None:
        """Re-search whenever text is typed."""
        nonlocal refresh_tim, result
        text = search_var.get().casefold()
        words = text.split()
        if not words:
            refresh_cback(None)
            return

        found: set[tuple[str, int]] = set()
        *words, last = words
        for word in words:
            try:
                found |= word_to_ids[word]
            except KeyError:
                pass
        if last:
            try:
                for group in word_to_ids.itervalues(last):
                    found |= group
            except KeyError:
                pass

        # The callback causes us to be deselected, so delay it until the user
        # stops typing.
        result = found
        if refresh_tim is not None:
            TK_ROOT.after_cancel(refresh_tim)
        refresh_tim = TK_ROOT.after(500, trigger_cback)
Esempio n. 6
0
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)
Esempio n. 7
0
        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()
Esempio n. 8
0
    def check_queue():
        """Update stages from the parent process."""
        nonlocal force_ontop
        had_values = False
        try:
            while PIPE_REC.poll():  # Pop off all the values.
                had_values = True
                operation, scr_id, args = PIPE_REC.recv()
                if operation == 'init':
                    # Create a new loadscreen.
                    is_main, title, stages = args
                    screen = (SplashScreen if is_main else LoadScreen)(
                        scr_id, title, force_ontop, stages)
                    SCREENS[scr_id] = screen
                elif operation == 'quit_daemon':
                    # Shutdown.
                    TK_ROOT.quit()
                    return
                elif operation == 'set_force_ontop':
                    [force_ontop] = args
                    for screen in SCREENS.values():
                        screen.win.attributes('-topmost', force_ontop)
                else:
                    try:
                        func = getattr(SCREENS[scr_id], 'op_' + operation)
                    except AttributeError:
                        raise ValueError(f'Bad command "{operation}"!')
                    try:
                        func(*args)
                    except Exception:
                        raise Exception(operation)
            while log_pipe_rec.poll():
                log_window.handle(log_pipe_rec.recv())
        except BrokenPipeError:
            # A pipe failed, means the main app quit. Terminate ourselves.
            print('BG: Lost pipe!')
            TK_ROOT.quit()
            return

        # Continually re-run this function in the TK loop.
        # If we didn't find anything in the pipe, wait longer.
        # Otherwise we hog the CPU.
        TK_ROOT.after(1 if had_values else 200, check_queue)
Esempio n. 9
0
 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,
         )
Esempio n. 10
0
    def play_sample(self, _: Event = None) -> None:
        """Play a sample of music.

        If music is being played it will be stopped instead.
        """
        if self.cur_file is None:
            return

        if self.player is not None:
            self.stop()
            return

        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)
            LOGGER.debug('Loading music directly from {!r}', load_path)
        else:
            # In a filesystem, we need to extract it.
            # SAMPLE_WRITE_PATH + the appropriate extension.
            sample_fname = SAMPLE_WRITE_PATH.with_suffix(
                os.path.splitext(self.cur_file)[1])
            with file.open_bin() as fsrc, sample_fname.open('wb') as fdest:
                shutil.copyfileobj(fsrc, fdest)
            LOGGER.debug('Loading music {} as {}', self.cur_file, sample_fname)
            load_path = str(sample_fname)
        try:
            sound = decoder.decode(None, load_path)
        except Exception:
            self.stop_callback()
            LOGGER.exception('Sound sample not valid: "{}"', self.cur_file)
            return  # Abort if music isn't found or can't be loaded.

        self.player = sound.play()
        self.after = TK_ROOT.after(
            int(sound.duration * 1000),
            self._finished,
        )
        self.start_callback()
Esempio n. 11
0
 def hover_toggle() -> None:
     """Toggle between arrows and dual icons."""
     nonlocal hover_arrow, hover_toggle_id
     hover_arrow = not hover_arrow
     if hover_sign is None:
         return
     if hover_arrow and sign_arrow:
         left = hover_sign.dnd_icon
         right = sign_arrow.dnd_icon
     else:
         try:
             left = Signage.by_id(hover_sign.prim_id or '').dnd_icon
         except KeyError:
             left = hover_sign.dnd_icon
         try:
             right = Signage.by_id(hover_sign.sec_id or '').dnd_icon
         except KeyError:
             right = IMG_BLANK
     img.apply(preview_left, left)
     img.apply(preview_right, right)
     hover_toggle_id = TK_ROOT.after(1000, hover_toggle)
Esempio n. 12
0
 def hover_toggle() -> None:
     """Toggle between arrows and dual icons."""
     nonlocal hover_arrow, hover_toggle_id
     hover_arrow = not hover_arrow
     if hover_sign is None:
         return
     if hover_arrow and sign_arrow:
         preview_left['image'] = hover_sign.dnd_icon
         preview_right['image'] = sign_arrow.dnd_icon
     else:
         try:
             preview_left['image'] = Signage.by_id(hover_sign.prim_id
                                                   or '').dnd_icon
         except KeyError:
             preview_left['image'] = hover_sign.dnd_icon
         try:
             preview_right['image'] = Signage.by_id(hover_sign.sec_id
                                                    or '').dnd_icon
         except KeyError:
             preview_right['image'] = blank_sign
     hover_toggle_id = TK_ROOT.after(1000, hover_toggle)
Esempio n. 13
0
 def next_error():
     # Use False since functions return None usually
     if next(err_iterator, False) is not False:
         TK_ROOT.after(1000, next_error)
Esempio n. 14
0
if __name__ == '__main__':
    srctools.logger.init_logging()
    LOGGER = srctools.logger.get_logger('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()
Esempio n. 15
0
def run_background(
    pipe_send: multiprocessing.connection.Connection,
    pipe_rec: multiprocessing.connection.Connection,
    log_pipe_send: multiprocessing.connection.Connection,
    log_pipe_rec: multiprocessing.connection.Connection,
    # Pass in various bits of translated text
    # so we don't need to do it here.
    translations: dict,
):
    """Runs in the other process, with an end of a pipe for input."""
    global PIPE_REC, PIPE_SEND
    PIPE_SEND = pipe_send
    PIPE_REC = pipe_rec
    TRANSLATION.update(translations)

    force_ontop = True

    log_window = LogWindow(translations, log_pipe_send)

    def check_queue():
        """Update stages from the parent process."""
        nonlocal force_ontop
        had_values = False
        try:
            while PIPE_REC.poll():  # Pop off all the values.
                had_values = True
                operation, scr_id, args = PIPE_REC.recv()
                if operation == 'init':
                    # Create a new loadscreen.
                    is_main, title, stages = args
                    screen = (SplashScreen if is_main else LoadScreen)(
                        scr_id, title, force_ontop, stages)
                    SCREENS[scr_id] = screen
                elif operation == 'quit_daemon':
                    # Shutdown.
                    TK_ROOT.quit()
                    return
                elif operation == 'set_force_ontop':
                    [force_ontop] = args
                    for screen in SCREENS.values():
                        screen.win.attributes('-topmost', force_ontop)
                else:
                    try:
                        func = getattr(SCREENS[scr_id], 'op_' + operation)
                    except AttributeError:
                        raise ValueError(f'Bad command "{operation}"!')
                    try:
                        func(*args)
                    except Exception:
                        raise Exception(operation)
            while log_pipe_rec.poll():
                log_window.handle(log_pipe_rec.recv())
        except BrokenPipeError:
            # A pipe failed, means the main app quit. Terminate ourselves.
            print('BG: Lost pipe!')
            TK_ROOT.quit()
            return

        # Continually re-run this function in the TK loop.
        # If we didn't find anything in the pipe, wait longer.
        # Otherwise we hog the CPU.
        TK_ROOT.after(1 if had_values else 200, check_queue)

    TK_ROOT.after(10, check_queue)
    TK_ROOT.mainloop()  # Infinite loop, until the entire process tree quits.
Esempio n. 16
0
 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)