Example #1
0
 def exit_handler(e):
     """When the user leaves, cancel the event."""
     # We only want to cancel if the event hasn't expired already
     nonlocal event_id
     window.withdraw()
     if event_id is not None:
         TK_ROOT.after_cancel(event_id)
Example #2
0
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)
Example #3
0
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)
Example #4
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
Example #5
0
def show(widget: tk.Misc, text, mouse_x, mouse_y):
    """Show the context window."""
    context_label['text'] = text
    window.deiconify()
    window.update_idletasks()
    window.lift()

    # We're going to position tooltips towards the center of the main window.
    # That way they don't tend to stick out, even in multi-window setups.

    # To decide where to put the tooltip, we first want the center of the
    # main window.
    cent_x = TK_ROOT.winfo_rootx() + TK_ROOT.winfo_width() / 2
    cent_y = TK_ROOT.winfo_rooty() + TK_ROOT.winfo_height() / 2

    x_centered = y_centered = True

    # If the widget is smaller than the context window, always center.
    if widget.winfo_width() > window.winfo_width():
        if cent_x > mouse_x + CENT_DIST:
            # Left of center, so place right of the target
            x = widget.winfo_rootx() + widget.winfo_width() + PADDING
            x_centered = False
        elif cent_x < mouse_x - CENT_DIST:
            # Right of center, so place left of the target
            x = widget.winfo_rootx() - window.winfo_width() - PADDING
            x_centered = False

    if widget.winfo_height() > window.winfo_height():
        if cent_y > mouse_y + CENT_DIST:
            # Above center, so place below target
            y = widget.winfo_rooty() + widget.winfo_height() + PADDING
            y_centered = False
        elif cent_y < mouse_y - CENT_DIST:
            # Below center, so place above target
            y = widget.winfo_rooty() - window.winfo_height() - PADDING
            y_centered = False

    if x_centered:  # Center horizontally
        x = (
            widget.winfo_rootx() +
            (widget.winfo_width() - window.winfo_width()) // 2
        )

    if y_centered:
        y = (
            widget.winfo_rooty() +
            (widget.winfo_height() - window.winfo_height()) // 2
        )

        # If both X and Y are centered, the tooltip will appear on top of
        # the mouse and immediately hide. Offset it to fix that.
        if x_centered:
            if mouse_y < cent_y:
                y = widget.winfo_rooty() + widget.winfo_height() + PADDING
            else:
                y = widget.winfo_rooty() - window.winfo_height() - PADDING

    window.geometry('+{}+{}'.format(int(x), int(y)))
Example #6
0
 def exit_handler(e):
     """When the user leaves, cancel the event."""
     # We only want to cancel if the event hasn't expired already
     nonlocal event_id
     hide()
     if event_id is not None:
         TK_ROOT.after_cancel(
             event_id
         )
Example #7
0
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)
Example #8
0
def init_application():
    """Initialise when standalone."""
    global window
    window = TK_ROOT
    window.title(_('Compiler Options - {}').format(utils.BEE_VERSION))
    window.resizable(True, False)

    make_widgets()

    TK_ROOT.deiconify()
Example #9
0
def init_toplevel():
    """Initialise the window as part of the BEE2."""
    global window
    window = tk.Toplevel(TK_ROOT)
    window.transient(TK_ROOT)
    window.withdraw()
    window.title(_('Backup/Restore Puzzles'))

    def quit_command():
        from BEE2_config import GEN_OPTS
        window.withdraw()
        GEN_OPTS.save_check()

    # Don't destroy window when quit!
    window.protocol("WM_DELETE_WINDOW", quit_command)

    init()
    init_backup_settings()

    # When embedded in the BEE2, use regular buttons and a dropdown!
    toolbar_frame = ttk.Frame(
        window,
    )
    ttk.Button(
        toolbar_frame,
        text=_('New Backup'),
        command=ui_new_backup,
        width=14,
    ).grid(row=0, column=0)

    ttk.Button(
        toolbar_frame,
        text=_('Open Backup'),
        command=ui_load_backup,
        width=13,
    ).grid(row=0, column=1)

    ttk.Button(
        toolbar_frame,
        text=_('Save Backup'),
        command=ui_save_backup,
        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')

    TK_ROOT.update()
    ui_new_backup()
Example #10
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)
Example #11
0
    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)
Example #12
0
        def stop(self):
            """Cancel the music, if it's playing."""
            if self.sample is None:
                return

            self.sample.pause()
            self.sample = None
            self.stop_callback()

            if self.after is not None:
                TK_ROOT.after_cancel(self.after)
                self.after = None
Example #13
0
        def stop(self):
            """Cancel the music, if it's playing."""
            if self.sample is None:
                return

            self.sample.pause()
            self.sample = None
            self.stop_callback()

            if self.after is not None:
                TK_ROOT.after_cancel(self.after)
                self.after = None
Example #14
0
def init_application():
    """Initialise the standalone application."""
    import gameMan
    global window
    window = TK_ROOT
    TK_ROOT.title(
        _('BEEMOD {} - Backup / Restore Puzzles').format(utils.BEE_VERSION)
    )

    init()

    UI['bar'] = bar = tk.Menu(TK_ROOT)
    window.option_add('*tearOff', False)

    if utils.MAC:
        # Name is used to make this the special 'BEE2' menu item
        file_menu = menus['file'] = tk.Menu(bar, name='apple')
    else:
        file_menu = menus['file'] = tk.Menu(bar)
    file_menu.add_command(label=_('New Backup'), command=ui_new_backup)
    file_menu.add_command(label=_('Open Backup'), command=ui_load_backup)
    file_menu.add_command(label=_('Save Backup'), command=ui_save_backup)
    file_menu.add_command(label=_('Save Backup As'), command=ui_save_backup_as)

    bar.add_cascade(menu=file_menu, label=_('File'))

    game_menu = menus['game'] = tk.Menu(bar)

    game_menu.add_command(label=_('Add Game'), command=gameMan.add_game)
    game_menu.add_command(label=_('Remove Game'), command=gameMan.remove_game)
    game_menu.add_separator()

    bar.add_cascade(menu=game_menu, label=_('Game'))
    gameMan.game_menu = game_menu

    import helpMenu
    # Add the 'Help' menu here too.
    helpMenu.make_help_menu(bar)

    window['menu'] = bar

    window.deiconify()
    window.update()

    gameMan.load()
    ui_new_backup()

    # UI.py isn't present, so we use this callback
    gameMan.setgame_callback = load_game

    gameMan.add_menu_opts(game_menu)
Example #15
0
    def open_win(self, _=None, force_open=False):
        if self._readonly and not force_open:
            TK_ROOT.bell()
            return 'break'  # Tell tk to stop processing this event

        self.win.deiconify()
        self.win.lift(self.parent)
        self.win.grab_set()
        self.win.focus_force()  # Focus here to deselect the textbox

        utils.center_win(self.win, parent=self.parent)

        self.sel_item(self.selected)
        self.win.after(2, self.flow_items)
Example #16
0
    def open_win(self, e=None, force_open=False):
        if self._readonly and not force_open:
            TK_ROOT.bell()
            return 'break'  # Tell tk to stop processing this event

        self.win.deiconify()
        self.win.lift(self.parent)
        if self.modal:
            self.win.grab_set()
        self.win.focus_force()  # Focus here to deselect the textbox

        utils.center_win(self.win, parent=self.parent)

        self.sel_item(self.selected)
        self.win.after(2, self.flow_items)
Example #17
0
def show_prop(widget, warp_cursor=False):
    """Show the properties window for an item.

    wid should be the UI.PalItem widget that represents the item.
    If warp_cursor is  true, the cursor will be moved relative to this window so
    it stays on top of the selected subitem.
    """
    global selected_item, selected_sub_item, is_open
    if warp_cursor and is_open:
        cursor_x, cursor_y = prop_window.winfo_pointerxy()
        off_x = cursor_x-prop_window.winfo_rootx()
        off_y = cursor_y-prop_window.winfo_rooty()
    else:
        off_x, off_y = None, None
    prop_window.deiconify()
    prop_window.lift(TK_ROOT)
    selected_item = widget.item
    selected_sub_item = widget
    is_open = True

    icon_widget = wid['subitem'][pos_for_item()]

    # Calculate the pixel offset between the window and the subitem in
    # the properties dialog, and shift if needed to keep it inside the
    # window
    loc_x, loc_y = utils.adjust_inside_screen(
        x=(
            widget.winfo_rootx()
            + prop_window.winfo_rootx()
            - icon_widget.winfo_rootx()
        ),
        y=(
            widget.winfo_rooty()
            + prop_window.winfo_rooty()
            - icon_widget.winfo_rooty()
        ),
        win=prop_window,
    )

    prop_window.geometry('+{x!s}+{y!s}'.format(x=loc_x, y=loc_y))
    prop_window.relX = loc_x-TK_ROOT.winfo_x()
    prop_window.relY = loc_y-TK_ROOT.winfo_y()

    if off_x is not None and off_y is not None:
        # move the mouse cursor
        prop_window.event_generate('<Motion>', warp=True, x=off_x, y=off_y)

    load_item_data()
Example #18
0
        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 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()
Example #20
0
def init_application():
    """Initialise the standalone application."""
    global window
    window = TK_ROOT
    TK_ROOT.title(
        _('BEEMOD {} - Backup / Restore Puzzles').format(utils.BEE_VERSION)
    )

    init()

    UI['bar'] = bar = tk.Menu(TK_ROOT)
    window.option_add('*tearOff', False)

    gameMan.load()
    ui_new_backup()

    # UI.py isn't present, so we use this callback
    gameMan.setgame_callback = load_game

    if utils.MAC:
        # Name is used to make this the special 'BEE2' menu item
        file_menu = menus['file'] = tk.Menu(bar, name='apple')
    else:
        file_menu = menus['file'] = tk.Menu(bar)
    file_menu.add_command(label=_('New Backup'), command=ui_new_backup)
    file_menu.add_command(label=_('Open Backup'), command=ui_load_backup)
    file_menu.add_command(label=_('Save Backup'), command=ui_save_backup)
    file_menu.add_command(label=_('Save Backup As'), command=ui_save_backup_as)

    bar.add_cascade(menu=file_menu, label=_('File'))

    game_menu = menus['game'] = tk.Menu(bar)

    game_menu.add_command(label=_('Add Game'), command=gameMan.add_game)
    game_menu.add_command(label=_('Remove Game'), command=gameMan.remove_game)
    game_menu.add_separator()

    bar.add_cascade(menu=game_menu, label=_('Game'))

    import helpMenu
    # Add the 'Help' menu here too.
    helpMenu.make_help_menu(bar)

    window['menu'] = bar

    gameMan.add_menu_opts(game_menu)
    gameMan.game_menu = game_menu
Example #21
0
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)
Example #22
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)
Example #23
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)
Example #24
0
        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()
Example #25
0
        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()
Example #26
0
def expand(_):
    """Expand the filter view."""
    global is_expanded
    is_expanded = True
    wid["expand_frame"].grid(row=2, column=0, columnspan=2, sticky="NSEW")
    wid["tag_list"]["height"] = TK_ROOT.winfo_height() / 48

    snd.fx("expand")
    UI.flow_picker()
Example #27
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()
Example #28
0
 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,
         )
Example #29
0
 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,
         )
Example #30
0
    def open_win(self, e=None, force_open=False):
        if self._readonly and not force_open:
            TK_ROOT.bell()
            return 'break'  # Tell tk to stop processing this event

        self.win.deiconify()
        self.win.lift(self.parent)
        if self.modal:
            self.win.grab_set()
        self.win.focus_force()  # Focus here to deselect the textbox

        # If we have a sound sampler, hold the system open while the window
        # is so it doesn't snap open/closed while finding files.
        if self.sampler is not None and self.sampler_held_open is False:
            self.sampler_held_open = True
            self.sampler.system.open_ref()

        utils.center_win(self.win, parent=self.parent)

        self.sel_item(self.selected)
        self.win.after(2, self.flow_items)
Example #31
0
    def open_win(self, e=None, force_open=False):
        if self._readonly and not force_open:
            TK_ROOT.bell()
            return 'break'  # Tell tk to stop processing this event

        self.win.deiconify()
        self.win.lift(self.parent)
        if self.modal:
            self.win.grab_set()
        self.win.focus_force()  # Focus here to deselect the textbox

        # If we have a sound sampler, hold the system open while the window
        # is so it doesn't snap open/closed while finding files.
        if self.sampler is not None and self.sampler_held_open is False:
            self.sampler_held_open = True
            self.sampler.system.open_ref()

        utils.center_win(self.win, parent=self.parent)

        self.sel_item(self.selected)
        self.win.after(2, self.flow_items)
Example #32
0
 def show_more_info():
     url = selected_item.url
     if url is not None:
         try:
             webbrowser.open(url, new=OPEN_IN_TAB, autoraise=True)
         except webbrowser.Error:
             if messagebox.askyesno(
                     icon="error",
                     title="BEE2 - Error",
                     message=_('Failed to open a web browser. Do you wish '
                               'for the URL to be copied to the clipboard '
                               'instead?'),
                     detail='"{!s}"'.format(url),
                     parent=prop_window):
                 LOGGER.info("Saving {} to clipboard!", url)
                 TK_ROOT.clipboard_clear()
                 TK_ROOT.clipboard_append(url)
         # Either the webbrowser or the messagebox could cause the
         # properties to move behind the main window, so hide it
         # so it doesn't appear there.
         hide_context(None)
Example #33
0
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)
Example #34
0
 def show_more_info():
     url = selected_item.url
     if url is not None:
         try:
             webbrowser.open(url, new=OPEN_IN_TAB, autoraise=True)
         except webbrowser.Error:
             if messagebox.askyesno(
                     icon="error",
                     title="BEE2 - Error",
                     message='Failed to open a web browser. Do you wish for '
                             'the URL to be copied to the clipboard '
                             'instead?',
                     detail='"{!s}"'.format(url),
                     parent=prop_window
                     ):
                 LOGGER.info("Saving {} to clipboard!", url)
                 TK_ROOT.clipboard_clear()
                 TK_ROOT.clipboard_append(url)
         # Either the webbrowser or the messagebox could cause the
         # properties to move behind the main window, so hide it
         # so it doesn't appear there.
         hide_context(None)
Example #35
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,
         )
Example #36
0
def expand(_):
    """Expand the filter view."""
    global is_expanded
    is_expanded = True
    wid['expand_frame'].grid(
        row=2,
        column=0,
        columnspan=2,
        sticky='NSEW',
    )
    wid['tag_list']['height'] = TK_ROOT.winfo_height() / 48

    snd.fx('expand')
    UI.flow_picker()
def expand(_):
    """Expand the filter view."""
    global is_expanded
    is_expanded = True
    wid['expand_frame'].grid(
        row=2,
        column=0,
        columnspan=2,
        sticky='NSEW',
    )
    wid['tag_list']['height'] = TK_ROOT.winfo_height() / 48

    snd.fx('expand')
    UI.flow_picker()
Example #38
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,
         )
Example #39
0
        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()
Example #40
0
            else:  # Not found
                self.suggested = None

        if self.suggested is not None:
            self._set_context_font(
                self.suggested,
                font=self.sugg_font,
            )
        self.set_disp()  # Update the textbox if needed
        self.flow_items()  # Refresh


if __name__ == '__main__':  # test the window if directly executing this file
    lbl = ttk.Label(TK_ROOT, text="I am a demo window.")
    lbl.grid()
    TK_ROOT.geometry("+500+500")

    test_list = [
        Item(
            "SKY_BLACK",
            "Black",
            long_name="Darkness",
            icon="skies/black",
            authors=["Valve"],
            desc='Pure black darkness. Nothing to see here.',
        ),
        Item(
            "SKY_BTS",
            "BTS",
            long_name="Behind The Scenes - Factory",
            icon="voices/glados",
Example #41
0
def _test() -> None:
    """Test the GUI."""
    from srctools.logger import init_logging
    from tk_tools import TK_ROOT
    from BEE2_config import GEN_OPTS
    from packageLoader import find_packages, PACKAGE_SYS

    init_logging()

    # Setup images to read from packages.
    print('Loading packages for images.')
    GEN_OPTS.load()
    find_packages(GEN_OPTS['Directories']['package'])
    img.load_filesystems(PACKAGE_SYS.values())
    print('Done.')

    left_frm = ttk.Frame(TK_ROOT)
    right_canv = tkinter.Canvas(TK_ROOT)

    left_frm.grid(row=0, column=0, sticky='NSEW', padx=8)
    right_canv.grid(row=0, column=1, sticky='NSEW', padx=8)
    TK_ROOT.rowconfigure(0, weight=1)
    TK_ROOT.columnconfigure(1, weight=1)

    slot_dest = []
    slot_src = []

    class TestItem:
        def __init__(
            self,
            name: str,
            icon: str,
            group: str=None,
            group_icon: str=None,
        ) -> None:
            self.name = name
            self.dnd_icon = img.png('items/clean/{}.png'.format(icon))
            self.dnd_group = group
            if group_icon:
                self.dnd_group_icon = img.png('items/clean/{}.png'.format(group_icon))

        def __repr__(self) -> str:
            return '<Item {}>'.format(self.name)

    manager = Manager[TestItem](TK_ROOT, config_icon=True)

    def func(ev):
        def call(slot):
            print('Cback: ', ev, slot)
        return call

    for event in Event:
        manager.reg_callback(event, func(event))

    items = [
        TestItem('Dropper', 'dropper'),
        TestItem('Entry', 'entry_door'),
        TestItem('Exit', 'exit_door'),
        TestItem('Large Obs', 'large_obs_room'),
        TestItem('Faith Plate', 'faithplate'),

        TestItem('Standard Cube', 'cube', 'ITEM_CUBE', 'cubes'),
        TestItem('Companion Cube', 'companion_cube', 'ITEM_CUBE', 'cubes'),
        TestItem('Reflection Cube', 'reflection_cube', 'ITEM_CUBE', 'cubes'),
        TestItem('Edgeless Cube', 'edgeless_safety_cube', 'ITEM_CUBE', 'cubes'),
        TestItem('Franken Cube', 'frankenturret', 'ITEM_CUBE', 'cubes'),

        TestItem('Repulsion Gel', 'paintsplat_bounce', 'ITEM_PAINT_SPLAT', 'paints'),
        TestItem('Propulsion Gel', 'paintsplat_speed', 'ITEM_PAINT_SPLAT', 'paints'),
        TestItem('Reflection Gel', 'paintsplat_reflection', 'ITEM_PAINT_SPLAT', 'paints'),
        TestItem('Conversion Gel', 'paintsplat_portal', 'ITEM_PAINT_SPLAT', 'paints'),
        TestItem('Cleansing Gel', 'paintsplat_water', 'ITEM_PAINT_SPLAT', 'paints'),
    ]

    for y in range(8):
        for x in range(4):
            slot = manager.slot(left_frm, source=False, label=(format(x + 4*y, '02') if y < 3 else ''))
            slot.grid(column=x, row=y, padx=1, pady=1)
            slot_dest.append(slot)

    for i, item in enumerate(items):
            slot = manager.slot(right_canv, source=True, label=format(i+1, '02'))
            slot_src.append(slot)
            slot.contents = item

    def configure(e):
        manager.flow_slots(right_canv, slot_src)

    configure(None)
    right_canv.bind('<Configure>', configure)

    ttk.Button(
        TK_ROOT,
        text='Debug',
        command=lambda: print('Dest:', [slot.contents for slot in slot_dest])
    ).grid(row=2, column=0)
    ttk.Button(
        TK_ROOT,
        text='Debug',
        command=lambda: print('Source:', [slot.contents for slot in slot_src])
    ).grid(row=2, column=1)

    name_lbl = ttk.Label(TK_ROOT, text='')
    name_lbl.grid(row=3, column=0)

    def enter(slot):
        if slot.contents is not None:
            name_lbl['text'] = 'Name: ' + slot.contents.name

    def exit(slot):
        name_lbl['text'] = ''

    manager.reg_callback(Event.HOVER_ENTER, enter)
    manager.reg_callback(Event.HOVER_EXIT, exit)
    manager.reg_callback(Event.CONFIG, lambda slot: messagebox.showinfo('Hello World', str(slot.contents)))

    TK_ROOT.deiconify()
    TK_ROOT.mainloop()
Example #42
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)
Example #43
0
    # window
    icon_widget = wid['subitem', pos_for_item()]

    loc_x, loc_y = utils.adjust_inside_screen(
        x=(selected_sub_item.winfo_rootx() + prop_window.winfo_rootx() -
           icon_widget.winfo_rootx()),
        y=(selected_sub_item.winfo_rooty() + prop_window.winfo_rooty() -
           icon_widget.winfo_rooty()),
        win=prop_window,
    )

    prop_window.geometry('+{x!s}+{y!s}'.format(x=loc_x, y=loc_y))


# When the main window moves, move the context window also.
TK_ROOT.bind("<Configure>", adjust_position, add='+')


def hide_context(e=None):
    """Hide the properties window, if it's open."""
    global is_open, selected_item, selected_sub_item
    if is_open:
        is_open = False
        prop_window.withdraw()
        snd.fx('contract')
        selected_item = selected_sub_item = None


def init_widgets():
    """Initiallise all the window components."""
    global prop_window
Example #44
0
    win.after(50, reset_sfx)

    widgets['titleLabel'].configure(text='Settings for "' + item_name + '"')
    win.title('BEE2 - ' + item_name)
    win.transient(master=parent)
    win.deiconify()
    win.lift(parent)
    win.grab_set()
    win.geometry(
        '+' + str(parent.winfo_rootx() - 30) +
        '+' + str(parent.winfo_rooty() - win.winfo_reqheight() - 30)
        )

# load the window if directly executing this file
if __name__ == '__main__':
    TK_ROOT.geometry('+250+250')

    def callback(vals):
        for key, value in sorted(vals.items()):
            print(key + ' = ' + repr(value))

    init(callback)
    all_vals = {
        'startup': '1',
        'toplevel': '4',
        'bottomlevel': '3',
        'angledpanelanimation': 'ramp_45_deg_open',
        'startenabled': '1',
        'startreversed': '0',
        'startdeployed': '1',
        'startactive': '1',
Example #45
0
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()
Example #46
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)
Example #47
0
def follow_main(_=None):
    """Move the properties window to keep a relative offset to the main window.

    """
    prop_window.geometry('+'+str(prop_window.relX+TK_ROOT.winfo_x()) +
                         '+'+str(prop_window.relY+TK_ROOT.winfo_y()))
Example #48
0
def init(cback):
    global callback, labels, win, is_open
    callback = cback
    is_open = False
    win = Toplevel(TK_ROOT)
    win.title("BEE2")
    win.resizable(False, False)
    win.iconbitmap('../BEE2.ico')
    win.protocol("WM_DELETE_WINDOW", exit_win)
    win.transient(TK_ROOT)
    win.withdraw()

    if utils.MAC:
        # Switch to use the 'modal' window style on Mac.
        TK_ROOT.call(
            '::tk::unsupported::MacWindowStyle',
            'style',
            win,
            'moveableModal',
            ''
        )

    frame = ttk.Frame(win, padding=10)
    frame.grid(row=0, column=0, sticky='NSEW')
    frame.rowconfigure(0, weight=1)
    frame.columnconfigure(0, weight=1)

    labels['noOptions'] = ttk.Label(frame, text='No Properties avalible!')
    widgets['saveButton'] = ttk.Button(frame, text='Close', command=exit_win)
    widgets['titleLabel'] = ttk.Label(frame, text='')
    widgets['titleLabel'].grid(columnspan=9)

    widgets['div_1'] = ttk.Separator(frame, orient="vertical")
    widgets['div_2'] = ttk.Separator(frame, orient="vertical")
    widgets['div_h'] = ttk.Separator(frame, orient="horizontal")

    for key, (prop_type, prop_name) in PROP_TYPES.items():
        labels[key] = ttk.Label(frame, text=prop_name+':')
        if prop_type == 'checkbox':
            values[key] = IntVar(value=DEFAULTS[key])
            out_values[key] = utils.bool_as_int(DEFAULTS[key])
            widgets[key] = ttk.Checkbutton(
                frame,
                variable=values[key],
                command=func_partial(set_check, key),
                )
            widgets[key].bind(
                '<Return>',
                func_partial(
                    toggleCheck,
                    key,
                    values[key],
                    )
                )

        elif prop_type == 'railLift':
            values[key] = IntVar(value=DEFAULTS[key])
            out_values[key] = utils.bool_as_int(DEFAULTS[key])
            widgets[key] = ttk.Checkbutton(
                frame,
                variable=values[key],
                command=func_partial(save_rail, key),
                )

        elif prop_type == 'panAngle':
            frm = ttk.Frame(frame)
            widgets[key] = frm
            values[key] = StringVar(value=DEFAULTS[key])
            for pos, angle in enumerate(['30', '45', '60', '90']):
                ttk.Radiobutton(
                    frm,
                    variable=values[key],
                    value=angle,
                    text=angle,
                    command=func_partial(save_angle, key, angle),
                    ).grid(row=0, column=pos)
                frm.columnconfigure(pos, weight=1)

        elif prop_type == 'gelType':
            frm = ttk.Frame(frame)
            widgets[key] = frm
            values[key] = IntVar(value=DEFAULTS[key])
            for pos, text in enumerate(PAINT_OPTS):
                ttk.Radiobutton(
                    frm,
                    variable=values[key],
                    value=pos,
                    text=text,
                    command=func_partial(save_paint, key, pos),
                    ).grid(row=0, column=pos)
                frm.columnconfigure(pos, weight=1)
            out_values[key] = str(DEFAULTS[key])

        elif prop_type == 'pistPlat':
            widgets[key] = Scale(
                frame,
                from_=0,
                to=4,
                orient="horizontal",
                showvalue=False,
                command=func_partial(save_pist, key),
                )
            values[key] = DEFAULTS[key]
            out_values[key] = str(DEFAULTS[key])
            if ((key == 'toplevel' and DEFAULTS['startup']) or
                    (key == 'bottomlevel' and not DEFAULTS['startup'])):
                widgets[key].set(max(
                    DEFAULTS['toplevel'],
                    DEFAULTS['bottomlevel']
                    ))
            if ((key == 'toplevel' and not DEFAULTS['startup']) or
                    (key == 'bottomlevel' and DEFAULTS['startup'])):
                widgets[key].set(min(
                    DEFAULTS['toplevel'],
                    DEFAULTS['bottomlevel']))

        elif prop_type == 'timerDel':
            widgets[key] = ttk.Scale(
                frame,
                from_=0,
                to=30,
                orient="horizontal",
                command=func_partial(save_tim, key),
                )
            values[key] = DEFAULTS[key]

        elif prop_type == 'railPlat':
            widgets[key] = ttk.Checkbutton(frame)
    values['startup'] = DEFAULTS['startup']
Example #49
0
    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()
Example #50
0
 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()
Example #51
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)
Example #52
0
    win.title('BEE2 - ' + item_name)
    win.deiconify()
    win.lift(parent)
    win.grab_set()
    win.attributes("-topmost", True)
    win.geometry('+' + str(parent.winfo_rootx() - 30) + '+' +
                 str(parent.winfo_rooty() - win.winfo_reqheight() - 30))

    if contextWin.is_open:
        # Temporarily hide the context window while we're open.
        contextWin.prop_window.withdraw()


# load the window if directly executing this file
if __name__ == '__main__':
    TK_ROOT.geometry('+250+250')

    def callback(vals):
        for key, value in sorted(vals.items()):
            print(key + ' = ' + repr(value))

    init(callback)
    all_vals = {
        'startup': '1',
        'toplevel': '4',
        'bottomlevel': '3',
        'angledpanelanimation': 'ramp_45_deg_open',
        'startenabled': '1',
        'startreversed': '0',
        'startdeployed': '1',
        'startactive': '1',
Example #53
0
            selected_sub_item.winfo_rootx()
            + prop_window.winfo_rootx()
            - icon_widget.winfo_rootx()
        ),
        y=(
            selected_sub_item.winfo_rooty()
            + prop_window.winfo_rooty()
            - icon_widget.winfo_rooty()
        ),
        win=prop_window,
    )

    prop_window.geometry('+{x!s}+{y!s}'.format(x=loc_x, y=loc_y))

# When the main window moves, move the context window also.
TK_ROOT.bind("<Configure>", adjust_position, add='+')


def hide_context(_=None):
    """Hide the properties window, if it's open."""
    global is_open, selected_item, selected_sub_item
    if is_open:
        is_open = False
        prop_window.withdraw()
        snd.fx('contract')
        selected_item = selected_sub_item = None


def init_widgets():
    """Initiallise all the window components."""
    global prop_window
Example #54
0
        title=_('Compile Options'),
        name='compiler',
        resize_x=True,
        resize_y=False,
        tool_frame=tool_frame,
        tool_img=img.png('icons/win_compiler'),
        tool_col=4,
    )
    window.columnconfigure(0, weight=1)
    window.rowconfigure(0, weight=1)
    make_widgets()


def init_application():
    """Initialise when standalone."""
    global window
    window = TK_ROOT
    window.title(_('Compiler Options - {}').format(utils.BEE_VERSION))
    window.resizable(True, False)

    make_widgets()


if __name__ == '__main__':
    # Run this standalone.

    init_application()

    TK_ROOT.deiconify()
    TK_ROOT.mainloop()
Example #55
0
                    break
            else:  # Not found
                self.suggested = None

        if self.suggested is not None:
            self.set_context_font(
                self.suggested,
                font=self.sugg_font,
            )
        self.set_disp()  # Update the textbox if needed
        self.flow_items()  # Refresh

if __name__ == '__main__':  # test the window if directly executing this file
    lbl = ttk.Label(TK_ROOT, text="I am a demo window.")
    lbl.grid()
    TK_ROOT.geometry("+500+500")

    test_list = [
        Item(
            "SKY_BLACK",
            "Black",
            long_name="Darkness",
            icon="skies/black",
            authors=["Valve"],
            desc=[
                ('line', 'Pure black darkness. Nothing to see here.'),
            ],
        ),
        Item(
            "SKY_BTS",
            "BTS",
Example #56
0
        # Show the log window on startup
        'show_log_win': '0',
        # The lowest level which will be shown.
        'window_log_level': 'INFO',
    },
}

GEN_OPTS.load()
GEN_OPTS.set_defaults(DEFAULT_SETTINGS)

loadScreen.main_loader.set_length('UI', 14)
loadScreen.show_main_loader(GEN_OPTS.get_bool('General', 'compact_splash'))

# OS X starts behind other windows, fix that.
if utils.MAC:
    TK_ROOT.lift()

logWindow.init(
    GEN_OPTS.get_bool('Debug', 'show_log_win'),
    GEN_OPTS['Debug']['window_log_level']
)

UI.load_settings()

gameMan.load()
gameMan.set_game_by_name(
    GEN_OPTS.get_val('Last_Selected', 'Game', ''),
    )
gameMan.scan_music_locs()

LOGGER.info('Loading Packages...')
Example #57
0
        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()
Example #58
0
def init(cback):
    global callback, labels, win, is_open
    callback = cback
    is_open = False
    win = Toplevel(TK_ROOT)
    win.title("BEE2")
    win.resizable(False, False)
    tk_tools.set_window_icon(win)
    win.protocol("WM_DELETE_WINDOW", exit_win)
    win.transient(TK_ROOT)
    win.withdraw()

    if utils.MAC:
        # Switch to use the 'modal' window style on Mac.
        TK_ROOT.call(
            '::tk::unsupported::MacWindowStyle',
            'style',
            win,
            'moveableModal',
            ''
        )

    frame = ttk.Frame(win, padding=10)
    frame.grid(row=0, column=0, sticky='NSEW')
    frame.rowconfigure(0, weight=1)
    frame.columnconfigure(0, weight=1)

    labels['noOptions'] = ttk.Label(frame, text=_('No Properties available!'))
    widgets['saveButton'] = ttk.Button(frame, text=_('Close'), command=exit_win)
    widgets['titleLabel'] = ttk.Label(frame, text='')
    widgets['titleLabel'].grid(columnspan=9)

    widgets['div_1'] = ttk.Separator(frame, orient="vertical")
    widgets['div_2'] = ttk.Separator(frame, orient="vertical")
    widgets['div_h'] = ttk.Separator(frame, orient="horizontal")

    for key, (prop_type, prop_name) in PROP_TYPES.items():
        # Translate property names from Valve's files.
        if prop_name.startswith('PORTAL2_'):
            prop_name = gameMan.translate(prop_name) + ':'

        labels[key] = ttk.Label(frame, text=prop_name)
        if prop_type is PropTypes.CHECKBOX:
            values[key] = IntVar(value=DEFAULTS[key])
            out_values[key] = srctools.bool_as_int(DEFAULTS[key])
            widgets[key] = ttk.Checkbutton(
                frame,
                variable=values[key],
                command=func_partial(set_check, key),
                )
            widgets[key].bind(
                '<Return>',
                func_partial(
                    toggleCheck,
                    key,
                    values[key],
                    )
                )

        elif prop_type is PropTypes.OSCILLATE:
            values[key] = IntVar(value=DEFAULTS[key])
            out_values[key] = srctools.bool_as_int(DEFAULTS[key])
            widgets[key] = ttk.Checkbutton(
                frame,
                variable=values[key],
                command=func_partial(save_rail, key),
                )

        elif prop_type is PropTypes.PANEL:
            frm = ttk.Frame(frame)
            widgets[key] = frm
            values[key] = StringVar(value=DEFAULTS[key])
            for pos, (angle, disp_angle) in enumerate(PANEL_ANGLES):
                ttk.Radiobutton(
                    frm,
                    variable=values[key],
                    value=angle,
                    text=gameMan.translate(disp_angle),
                    command=func_partial(save_angle, key, angle),
                    ).grid(row=0, column=pos)
                frm.columnconfigure(pos, weight=1)

        elif prop_type is PropTypes.GELS:
            frm = ttk.Frame(frame)
            widgets[key] = frm
            values[key] = IntVar(value=DEFAULTS[key])
            for pos, text in enumerate(PAINT_OPTS):
                ttk.Radiobutton(
                    frm,
                    variable=values[key],
                    value=pos,
                    text=gameMan.translate(text),
                    command=func_partial(save_paint, key, pos),
                    ).grid(row=0, column=pos)
                frm.columnconfigure(pos, weight=1)
            out_values[key] = str(DEFAULTS[key])

        elif prop_type is PropTypes.PISTON:
            widgets[key] = Scale(
                frame,
                from_=0,
                to=4,
                orient="horizontal",
                showvalue=False,
                command=func_partial(save_pist, key),
                )
            values[key] = DEFAULTS[key]
            out_values[key] = str(DEFAULTS[key])
            if ((key == 'toplevel' and DEFAULTS['startup']) or
                    (key == 'bottomlevel' and not DEFAULTS['startup'])):
                widgets[key].set(max(
                    DEFAULTS['toplevel'],
                    DEFAULTS['bottomlevel']
                    ))
            if ((key == 'toplevel' and not DEFAULTS['startup']) or
                    (key == 'bottomlevel' and DEFAULTS['startup'])):
                widgets[key].set(min(
                    DEFAULTS['toplevel'],
                    DEFAULTS['bottomlevel']))

        elif prop_type is PropTypes.TIMER:
            widgets[key] = ttk.Scale(
                frame,
                from_=0,
                to=30,
                orient="horizontal",
                command=func_partial(save_tim, key),
                )
            values[key] = DEFAULTS[key]

    values['startup'] = DEFAULTS['startup']
Example #59
0
def init(cback):
    global callback, labels, win, is_open
    callback = cback
    is_open = False
    win = Toplevel(TK_ROOT)
    win.title("BEE2")
    win.resizable(False, False)
    tk_tools.set_window_icon(win)
    win.protocol("WM_DELETE_WINDOW", exit_win)
    win.transient(TK_ROOT)
    win.withdraw()

    if utils.MAC:
        # Switch to use the 'modal' window style on Mac.
        TK_ROOT.call('::tk::unsupported::MacWindowStyle', 'style', win,
                     'moveableModal', '')
    # Stop our init from triggering UI sounds.
    sound.block_fx()

    frame = ttk.Frame(win, padding=10)
    frame.grid(row=0, column=0, sticky='NSEW')
    frame.rowconfigure(0, weight=1)
    frame.columnconfigure(0, weight=1)

    labels['noOptions'] = ttk.Label(frame, text=_('No Properties available!'))
    widgets['saveButton'] = ttk.Button(frame,
                                       text=_('Close'),
                                       command=exit_win)
    widgets['titleLabel'] = ttk.Label(frame, text='')
    widgets['titleLabel'].grid(columnspan=9)

    widgets['div_1'] = ttk.Separator(frame, orient="vertical")
    widgets['div_2'] = ttk.Separator(frame, orient="vertical")
    widgets['div_h'] = ttk.Separator(frame, orient="horizontal")

    for key, (prop_type, prop_name) in PROP_TYPES.items():
        # Translate property names from Valve's files.
        if prop_name.startswith('PORTAL2_'):
            prop_name = gameMan.translate(prop_name) + ':'

        labels[key] = ttk.Label(frame, text=prop_name)
        if prop_type is PropTypes.CHECKBOX:
            values[key] = IntVar(value=DEFAULTS[key])
            out_values[key] = srctools.bool_as_int(DEFAULTS[key])
            widgets[key] = ttk.Checkbutton(
                frame,
                variable=values[key],
                command=func_partial(set_check, key),
            )
            widgets[key].bind('<Return>',
                              func_partial(
                                  toggleCheck,
                                  key,
                                  values[key],
                              ))

        elif prop_type is PropTypes.OSCILLATE:
            values[key] = IntVar(value=DEFAULTS[key])
            out_values[key] = srctools.bool_as_int(DEFAULTS[key])
            widgets[key] = ttk.Checkbutton(
                frame,
                variable=values[key],
                command=func_partial(save_rail, key),
            )

        elif prop_type is PropTypes.PANEL:
            frm = ttk.Frame(frame)
            widgets[key] = frm
            values[key] = StringVar(value=DEFAULTS[key])
            for pos, (angle, disp_angle) in enumerate(PANEL_ANGLES):
                ttk.Radiobutton(
                    frm,
                    variable=values[key],
                    value=angle,
                    text=gameMan.translate(disp_angle),
                    command=func_partial(save_angle, key, angle),
                ).grid(row=0, column=pos)
                frm.columnconfigure(pos, weight=1)

        elif prop_type is PropTypes.GELS:
            frm = ttk.Frame(frame)
            widgets[key] = frm
            values[key] = IntVar(value=DEFAULTS[key])
            for pos, text in enumerate(PAINT_OPTS):
                ttk.Radiobutton(
                    frm,
                    variable=values[key],
                    value=pos,
                    text=gameMan.translate(text),
                    command=func_partial(save_paint, key, pos),
                ).grid(row=0, column=pos)
                frm.columnconfigure(pos, weight=1)
            out_values[key] = str(DEFAULTS[key])

        elif prop_type is PropTypes.PISTON:
            widgets[key] = pist_scale = ttk.Scale(
                frame,
                from_=0,
                to=4,
                orient="horizontal",
                command=func_partial(save_pist, key),
            )
            values[key] = DEFAULTS[key]
            out_values[key] = str(DEFAULTS[key])
            if ((key == 'toplevel' and DEFAULTS['startup'])
                    or (key == 'bottomlevel' and not DEFAULTS['startup'])):
                pist_scale.set(
                    max(DEFAULTS['toplevel'], DEFAULTS['bottomlevel']))
            if ((key == 'toplevel' and not DEFAULTS['startup'])
                    or (key == 'bottomlevel' and DEFAULTS['startup'])):
                pist_scale.set(
                    min(DEFAULTS['toplevel'], DEFAULTS['bottomlevel']))

        elif prop_type is PropTypes.TIMER:
            widgets[key] = ttk.Scale(
                frame,
                from_=0,
                to=30,
                orient="horizontal",
                command=func_partial(save_tim, key),
            )
            values[key] = DEFAULTS[key]

    values['startup'] = DEFAULTS['startup']
Example #60
0
 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()