Пример #1
0
    def __init__(
        self,
        master,
        is_dir: bool = False,
        loc: str = '',
        callback: Callable[[str], None] = None,
    ) -> None:
        """Initialise the field.

        - Set is_dir to true to look for directories, instead of files.
        - width sets the number of characters to display.
        - callback is a function to be called with the new path whenever it
          changes.
        """
        from tooltip import add_tooltip

        super(FileField, self).__init__(master)

        self._location = loc
        self.is_dir = is_dir

        self._text_var = tk.StringVar(master=self, value='')
        if is_dir:
            self.browser = filedialog.Directory(
                self,
                initialdir=loc,
            )  # type: commondialog.Dialog
        else:
            self.browser = filedialog.SaveAs(
                self,
                initialdir=loc,
            )

        if callback is None:
            callback = self._nop_callback

        self.callback = callback

        self.textbox = ReadOnlyEntry(
            self,
            textvariable=self._text_var,
            font=_file_field_font,
            cursor=utils.CURSORS['regular'],
        )
        self.textbox.grid(row=0, column=0, sticky='ew')
        self.columnconfigure(0, weight=1)
        utils.bind_leftclick(self.textbox, self.browse)
        # The full location is displayed in a tooltip.
        add_tooltip(self.textbox, self._location)
        self.textbox.bind('<Configure>', self._text_configure)

        self.browse_btn = ttk.Button(
            self,
            text="...",
            width=1.5,
            command=self.browse,
        )
        self.browse_btn.grid(row=0, column=1)

        self._text_var.set(self._truncate(loc))
Пример #2
0
def widget_color_multi(
        parent: tk.Frame, values: List[Tuple[str, tk.StringVar]], conf: Property):
    """For color swatches, display in a more compact form."""
    for row, column, tim_text, var in multi_grid(values):
        swatch = make_color_swatch(parent, var)
        swatch.grid(row=row, column=column)
        add_tooltip(swatch, tim_text, delay=0)
Пример #3
0
def widget_minute_seconds_multi(
        parent: tk.Frame, values: List[Tuple[str, tk.StringVar]], conf: Property):
    """For timers, display in a more compact form."""
    for row, column, tim_text, var in multi_grid(values, columns=5):
        timer = widget_minute_seconds(parent, var, conf)
        timer.grid(row=row, column=column)
        add_tooltip(timer, tim_text, delay=0)
Пример #4
0
def init_gen_tab(f):

    if sound.initiallised:
        UI['mute'] = mute = make_checkbox(
            f,
            section='General',
            item='play_sounds',
            desc=_('Play Sounds'),
            var=PLAY_SOUND,
        )
    else:
        UI['mute'] = mute = ttk.Checkbutton(
            f,
            text=_('Play Sounds'),
            state='disabled',
        )
        add_tooltip(
            UI['mute'],
            _('Pyglet is either not installed or broken.\n'
              'Sound effects have been disabled.')
        )
    mute.grid(row=0, column=0, sticky=W)

    UI['reset_cache'] = reset_cache = ttk.Button(
        f,
        text=_('Reset Package Caches'),
        command=clear_caches,
    )
    reset_cache.grid(row=2, column=0, columnspan=2, sticky='SEW')
    add_tooltip(
        reset_cache,
        _('Force re-extracting all package resources. This requires a restart.'),
    )
def init_gen_tab(f):

    if sound.initiallised:
        UI['mute'] = mute = make_checkbox(
            f,
            section='General',
            item='play_sounds',
            desc=_('Play Sounds'),
            var=PLAY_SOUND,
        )
    else:
        UI['mute'] = mute = ttk.Checkbutton(
            f,
            text=_('Play Sounds'),
            state='disabled',
        )
        add_tooltip(
            UI['mute'],
            _('Pyglet is either not installed or broken.\n'
              'Sound effects have been disabled.'))
    mute.grid(row=0, column=0, sticky=W)

    UI['reset_cache'] = reset_cache = ttk.Button(
        f,
        text=_('Reset Package Caches'),
        command=clear_caches,
    )
    reset_cache.grid(row=2, column=0, columnspan=2, sticky='SEW')
    add_tooltip(
        reset_cache,
        _('Force re-extracting all package resources. This requires a restart.'
          ),
    )
Пример #6
0
    def widget(self, frame) -> ttk.Entry:
        """Create the special textbox used to open the selector window.

        Use like 'selWin.widget(parent).grid(row=0, column=1)' to create
        and place the textbox.
        """

        self.display = tk_tools.ReadOnlyEntry(
            frame,
            textvariable=self.disp_label,
            cursor=utils.CURSORS['regular'],
        )
        utils.bind_leftclick(
            self.display,
            self.open_win,
        )
        self.display.bind("<Key>", self.set_disp)
        utils.bind_rightclick(
            self.display,
            self.open_context,
        )

        self.disp_btn = ttk.Button(
            self.display,
            text="...",
            width=1.5,
            command=self.open_win,
        )
        self.disp_btn.pack(side=RIGHT)

        add_tooltip(self.display, self.description, show_when_disabled=True)

        self.save()

        return self.display
Пример #7
0
def init_gen_tab(f):

    if sound.initiallised:
        UI['mute'] = mute = make_checkbox(
            f,
            section='General',
            item='play_sounds',
            desc='Play Sounds',
            var=PLAY_SOUND,
        )
    else:
        UI['mute'] = mute = ttk.Checkbutton(
            f,
            text='Play Sounds',
            state='disabled',
        )
        add_tooltip(
            UI['mute'],
            'PyGame is either not installed or broken.\n'
            'Sound effects have been disabled.'
        )
    mute.grid(row=0, column=0, sticky=W)

    make_checkbox(
        f,
        section='General',
        item='show_wip_items',
        desc='Show WIP items',
        tooltip='Show items and item versions marked Work In Progress. '
                'These may be buggy or incomplete.',
        var=SHOW_WIP,
    ).grid(row=1, column=0, sticky=W)
Пример #8
0
def widget_checkmark(parent: tk.Frame, values: List[Tuple[str, tk.StringVar]],
                     conf: Property):
    """For timers, display in a more compact form."""
    for row, column, tim_text, var in multi_grid(values):
        checkbox = widget_checkmark(parent, var, conf)
        checkbox.grid(row=row, column=column)
        add_tooltip(checkbox, tim_text, delay=0)
Пример #9
0
    def widget(self, frame) -> ttk.Entry:
        """Create the special textbox used to open the selector window.

        Use like 'selWin.widget(parent).grid(row=0, column=1)' to create
        and place the textbox.
        """

        self.display = tk_tools.ReadOnlyEntry(
            frame,
            textvariable=self.disp_label,
            cursor=utils.CURSORS['regular'],
        )
        utils.bind_leftclick(
            self.display,
            self.open_win,
        )
        self.display.bind("<Key>", self.set_disp)
        utils.bind_rightclick(
            self.display,
            self.open_context,
        )

        self.disp_btn = ttk.Button(
            self.display,
            text="...",
            width=1.5,
            command=self.open_win,
        )
        self.disp_btn.pack(side=RIGHT)

        add_tooltip(self.display, self.description, show_when_disabled=True)

        self.save()

        return self.display
Пример #10
0
def init_gen_tab(f):

    if sound.initiallised:
        UI['mute'] = mute = make_checkbox(
            f,
            section='General',
            item='play_sounds',
            desc='Play Sounds',
            var=PLAY_SOUND,
        )
    else:
        UI['mute'] = mute = ttk.Checkbutton(
            f,
            text='Play Sounds',
            state='disabled',
        )
        add_tooltip(
            UI['mute'], 'PyGame is either not installed or broken.\n'
            'Sound effects have been disabled.')
    mute.grid(row=0, column=0, sticky=W)

    make_checkbox(
        f,
        section='General',
        item='show_wip_items',
        desc='Show WIP items',
        tooltip='Show items and item versions marked Work In Progress. '
        'These may be buggy or incomplete.',
        var=SHOW_WIP,
    ).grid(row=1, column=0, sticky=W)
Пример #11
0
def widget_color_multi(parent: tk.Frame,
                       values: List[Tuple[str, tk.StringVar]], conf: Property):
    """For color swatches, display in a more compact form."""
    for row, column, tim_text, var in multi_grid(values):
        swatch = make_color_swatch(parent, var)
        swatch.grid(row=row, column=column)
        add_tooltip(swatch, tim_text, delay=0)
Пример #12
0
    def __init__(
        self,
        master,
        is_dir=False,
        loc='',
        callback=None,
    ):
        """Initialise the field.

        - Set is_dir to true to look for directories, instead of files.
        - width sets the number of characters to display.
        - callback is a function to be called with the new path whenever it
          changes.
        """
        from tooltip import add_tooltip

        super(FileField, self).__init__(master)

        self._location = loc
        self.is_dir = is_dir

        self._text_var = tk.StringVar(master=self, value='')
        if is_dir:
            self.browser = filedialog.Directory(
                self,
                initialdir=loc,
            )
        else:
            self.browser = filedialog.SaveAs(
                self,
                initialdir=loc,
            )

        if callback is not None:
            self.callback = callback


        self.textbox = ReadOnlyEntry(
            self,
            textvariable=self._text_var,
            font=_file_field_font,
            cursor=utils.CURSORS['regular'],
        )
        self.textbox.grid(row=0, column=0, sticky='ew')
        self.columnconfigure(0, weight=1)
        utils.bind_leftclick(self.textbox, self.browse)
        # The full location is displayed in a tooltip.
        add_tooltip(self.textbox, self._location)
        self.textbox.bind('<Configure>', self._text_configure)

        self.browse_btn = ttk.Button(
            self,
            text="...",
            width=1.5,
            command=self.browse,
        )
        self.browse_btn.grid(row=0, column=1)

        self._text_var.set(self._truncate(loc))
Пример #13
0
def widget_minute_seconds_multi(parent: tk.Frame,
                                values: List[Tuple[str, tk.StringVar]],
                                conf: Property):
    """For timers, display in a more compact form."""
    for row, column, tim_text, var in multi_grid(values, columns=5):
        timer = widget_minute_seconds(parent, var, conf)
        timer.grid(row=row, column=column)
        add_tooltip(timer, tim_text, delay=0)
Пример #14
0
def make_checkbox(
    frame: Misc,
    section: str,
    item: str,
    desc: str,
    default: bool=False,
    var: BooleanVar=None,
    tooltip='',
) -> ttk.Checkbutton:
    """Add a checkbox to the given frame which toggles an option.

    section and item are the location in GEN_OPTS for this config.
    If var is set, it'll be used instead of an auto-created variable.
    desc is the text put next to the checkbox.
    default is the default value of the variable, if var is None.
    frame is the parent frame.
    """
    if var is None:
        var = BooleanVar(
            value=default,
            name='opt_' + section.casefold() + '_' + item,
        )
    else:
        default = var.get()

    VARS[section, item] = var

    def save_opt():
        """Save the checkbox's values."""
        GEN_OPTS[section][item] = srctools.bool_as_int(
            var.get()
        )

    def load_opt():
        """Load the checkbox's values."""
        var.set(GEN_OPTS.get_bool(
            section,
            item,
            default,
        ))
    load_opt()

    var.save = save_opt
    var.load = load_opt
    widget = ttk.Checkbutton(
        frame,
        variable=var,
        text=desc,
    )

    if tooltip:
        add_tooltip(widget, tooltip)

    UI[section, item] = widget
    return widget
Пример #15
0
def make_checkbox(
        frame,
        section,
        item,
        desc,
        default=False,
        var: BooleanVar=None,
        tooltip='',
        ):
    """Add a checkbox to the given frame which toggles an option.

    section and item are the location in GEN_OPTS for this config.
    If var is set, it'll be used instead of an auto-created variable.
    desc is the text put next to the checkbox.
    default is the default value of the variable, if var is None.
    frame is the parent frame.
    """
    if var is None:
        var = BooleanVar(
            value=default,
            name='opt_' + section.casefold() + '_' + item,
        )
    else:
        default = var.get()

    VARS[section, item] = var

    def save_opt():
        """Save the checkbox's values."""
        GEN_OPTS[section][item] = utils.bool_as_int(
            var.get()
        )

    def load_opt():
        """Load the checkbox's values."""
        var.set(GEN_OPTS.get_bool(
            section,
            item,
            default,
        ))
    load_opt()

    var.save = save_opt
    var.load = load_opt
    widget = ttk.Checkbutton(
        frame,
        variable=var,
        text=desc,
    )

    if tooltip:
        add_tooltip(widget, tooltip)

    UI[section, item] = widget
    return widget
Пример #16
0
def widget_checkmark_multi(
    parent: tk.Frame,
    values: List[Tuple[str, tk.StringVar]],
    conf: Property,
) -> tk.Widget:
    """For checkmarks, display in a more compact form."""
    for row, column, tim_text, var in multi_grid(values):
        checkbox = widget_checkmark(parent, var, conf)
        checkbox.grid(row=row, column=column)
        add_tooltip(checkbox, tim_text, delay=0)
    return parent
Пример #17
0
    def make_widgets(self, master: 'CheckDetails'):
        if self.master is not None:
            # If we let items move between lists, the old widgets will become
            # orphaned!
            raise ValueError(
                "Can't move Item objects between lists!"
            )

        self.master = master
        self.check = ttk.Checkbutton(
            master.wid_frame,
            variable=self.state_var,
            onvalue=1,
            offvalue=0,
            takefocus=False,
            width=0,
            style='CheckDetails.TCheckbutton',
            command=self.master.update_allcheck,
        )
        if self.locked:
            self.check.state(['disabled'])

        self.val_widgets = []
        for value in self.values:
            wid = tk.Label(
                master.wid_frame,
                text=value,
                justify=tk.LEFT,
                anchor=tk.W,
                background='white',
            )
            add_tooltip(wid)
            if self.hover_text:
                wid.tooltip_text = self.hover_text
                wid.hover_override = True
            else:
                wid.tooltip_text = ''
                wid.hover_override = False

            if not self.locked:
                # Allow clicking on the row to toggle the checkbox
                wid.bind('<Enter>', self.hover_start, add='+')
                wid.bind('<Leave>', self.hover_stop, add='+')
                utils.bind_leftclick(wid, self.row_click, add='+')
                wid.bind(utils.EVENTS['LEFT_RELEASE'], self.row_unclick, add='+')

            self.val_widgets.append(wid)

        utils.add_mousewheel(
            self.master.wid_canvas,
            self.check,
            *self.val_widgets
        )
Пример #18
0
    def __init__(
        self,
        parent: Misc,
        *,
        tool_frame: Frame,
        tool_img: PhotoImage,
        menu_bar: Menu,
        tool_col: int = 0,
        title: str = '',
        resize_x: bool = False,
        resize_y: bool = False,
        name: str = '',
    ) -> None:
        self.visible = BooleanVar(parent, True)
        self.win_name = name
        self.allow_snap = False
        self.can_save = False
        self.parent = parent
        self.relX = 0
        self.relY = 0
        self.can_resize_x = resize_x
        self.can_resize_y = resize_y
        super().__init__(parent, name='pane_' + name)
        self.withdraw()  # Hide by default

        self.tool_button = make_tool_button(
            frame=tool_frame,
            img=tool_img,
            command=self.toggle_win,
        )
        self.tool_button.state(('pressed', ))
        self.tool_button.grid(
            row=0,
            column=tool_col,
            # Contract the spacing to allow the icons to fit.
            padx=(2 if utils.MAC else (5, 2)),
        )
        tooltip.add_tooltip(self.tool_button,
                            text=_('Hide/Show the "{}" window.').format(title))
        menu_bar.add_checkbutton(label=title,
                                 variable=self.visible,
                                 command=self.toggle_win)
        self.transient(master=parent)
        self.resizable(resize_x, resize_y)
        self.title(title)
        tk_tools.set_window_icon(self)

        self.protocol("WM_DELETE_WINDOW", self.hide_win)
        parent.bind('<Configure>', self.follow_main, add='+')
        self.bind('<Configure>', self.snap_win)
        self.bind('<FocusIn>', self.enable_snap)
Пример #19
0
    def __init__(
            self,
            parent,
            tool_frame,
            tool_img,
            options,
            tool_col=0,
            title='',
            resize_x=False,
            resize_y=False,
            name='',
            ):
        self.visible = True
        self.win_name = name
        self.allow_snap = False
        self.can_save = False
        self.parent = parent
        self.relX = 0
        self.relY = 0
        self.can_resize_x = resize_x
        self.can_resize_y = resize_y
        self.config_file = options
        super().__init__(parent, name='pane_' + name)
        self.withdraw()  # Hide by default

        self.tool_button = make_tool_button(
            frame=tool_frame,
            img=tool_img,
            command=self.toggle_win,
        )
        self.tool_button.state(('pressed',))
        self.tool_button.grid(
            row=0,
            column=tool_col,
            # Contract the spacing to allow the icons to fit.
            padx=(2 if utils.MAC else (5, 2)),
        )
        tooltip.add_tooltip(
            self.tool_button,
            text='Hide/Show the "{}" window.'.format(title))

        self.transient(master=parent)
        self.resizable(resize_x, resize_y)
        self.title(title)
        self.iconbitmap('../BEE2.ico')

        self.protocol("WM_DELETE_WINDOW", self.hide_win)
        parent.bind('<Configure>', self.follow_main, add='+')
        self.bind('<Configure>', self.snap_win)
        self.bind('<FocusIn>', self.enable_snap)
Пример #20
0
    def make_widgets(self, master: 'CheckDetails'):
        if self.master is not None:
            # If we let items move between lists, the old widgets will become
            # orphaned!
            raise ValueError("Can't move Item objects between lists!")

        self.master = master
        self.check = ttk.Checkbutton(
            master.wid_frame,
            variable=self.state_var,
            onvalue=1,
            offvalue=0,
            takefocus=False,
            width=0,
            style='CheckDetails.TCheckbutton',
            command=self.master.update_allcheck,
        )
        if self.locked:
            self.check.state(['disabled'])

        self.val_widgets = []
        for value in self.values:
            wid = tk.Label(
                master.wid_frame,
                text=value,
                justify=tk.LEFT,
                anchor=tk.W,
                background='white',
            )
            add_tooltip(wid)
            if self.hover_text:
                set_tooltip(wid, self.hover_text)
                wid.hover_override = True
            else:
                set_tooltip(wid)
                wid.hover_override = False

            if not self.locked:
                # Allow clicking on the row to toggle the checkbox
                wid.bind('<Enter>', self.hover_start, add='+')
                wid.bind('<Leave>', self.hover_stop, add='+')
                utils.bind_leftclick(wid, self.row_click, add='+')
                wid.bind(utils.EVENTS['LEFT_RELEASE'],
                         self.row_unclick,
                         add='+')

            self.val_widgets.append(wid)

        utils.add_mousewheel(self.master.wid_canvas, self.check,
                             *self.val_widgets)
Пример #21
0
    def __init__(
            self,
            parent,
            tool_frame,
            tool_img,
            options,
            tool_col=0,
            title='',
            resize_x=False,
            resize_y=False,
            name='',
            ):
        self.visible = True
        self.win_name = name
        self.allow_snap = False
        self.can_save = False
        self.parent = parent
        self.relX = 0
        self.relY = 0
        self.can_resize_x = resize_x
        self.can_resize_y = resize_y
        self.config_file = options
        super().__init__(parent, name='pane_' + name)
        self.withdraw()  # Hide by default

        self.tool_button = make_tool_button(
            frame=tool_frame,
            img=tool_img,
            command=self.toggle_win,
        )
        self.tool_button.state(('pressed',))
        self.tool_button.grid(
            row=0,
            column=tool_col,
            # Contract the spacing to allow the icons to fit.
            padx=(2 if utils.MAC else (5, 2)),
        )
        tooltip.add_tooltip(
            self.tool_button,
            text=_('Hide/Show the "{}" window.').format(title))

        self.transient(master=parent)
        self.resizable(resize_x, resize_y)
        self.title(title)
        tk_tools.set_window_icon(self)

        self.protocol("WM_DELETE_WINDOW", self.hide_win)
        parent.bind('<Configure>', self.follow_main, add='+')
        self.bind('<Configure>', self.snap_win)
        self.bind('<FocusIn>', self.enable_snap)
Пример #22
0
def init_gen_tab(f):

    if sound.initiallised:
        UI['mute'] = mute = make_checkbox(
            f,
            section='General',
            item='play_sounds',
            desc='Play Sounds',
            var=PLAY_SOUND,
        )
    else:
        UI['mute'] = mute = ttk.Checkbutton(
            f,
            text='Play Sounds',
            state='disabled',
        )
        add_tooltip(
            UI['mute'],
            'PyGame is either not installed or broken.\n'
            'Sound effects have been disabled.'
        )
    mute.grid(row=0, column=0, sticky=W)

    make_checkbox(
        f,
        section='General',
        item='show_wip_items',
        desc='Show WIP items',
        tooltip='Show items and item versions marked Work In Progress. '
                'These may be buggy or incomplete.',
        var=SHOW_WIP,
    ).grid(row=1, column=0, sticky=W)

    UI['reset_cache'] = reset_cache = ttk.Button(
        f,
        text='Reset Package Caches',
        command=clear_caches,
    )
    reset_cache.grid(row=2, column=0, columnspan=2, sticky='SEW')
    add_tooltip(
        reset_cache,
        'Force re-extracting all package resources. This requires a restart.'
    )
Пример #23
0
def init_widgets():
    """Initiallise all the window components."""
    global prop_window
    prop_window = Toplevel(TK_ROOT)
    prop_window.overrideredirect(1)
    prop_window.resizable(False, False)
    prop_window.transient(master=TK_ROOT)
    prop_window.attributes('-topmost', 1)
    prop_window.withdraw()  # starts hidden

    f = ttk.Frame(prop_window, relief="raised", borderwidth="4")
    f.grid(row=0, column=0)

    ttk.Label(
        f,
        text="Properties:",
        anchor="center",
    ).grid(
        row=0,
        column=0,
        columnspan=3,
        sticky="EW",
    )

    wid['name'] = ttk.Label(f, text="", anchor="center")
    wid['name'].grid(row=1, column=0, columnspan=3, sticky="EW")

    wid['ent_count'] = ttk.Label(
        f,
        text="",
        anchor="e",
        compound="left",
        image=img.spr('gear_ent'),
    )
    wid['ent_count'].grid(row=0, column=2, rowspan=2, sticky=E)
    tooltip.add_tooltip(
        wid['ent_count'],
        _('The number of entities used for this item. The Source engine '
          'limits this to 2048 in total. This provides a guide to how many of '
          'these items can be placed in a map at once.'))

    wid['author'] = ttk.Label(f, text="", anchor="center", relief="sunken")
    wid['author'].grid(row=2, column=0, columnspan=3, sticky="EW")

    sub_frame = ttk.Frame(f, borderwidth=4, relief="sunken")
    sub_frame.grid(column=0, columnspan=3, row=3)
    for i in range(5):
        wid['subitem', i] = ttk.Label(
            sub_frame,
            image=img.invis_square(64),
        )
        wid['subitem', i].grid(row=0, column=i)
        utils.bind_leftclick(
            wid['subitem', i],
            functools.partial(sub_sel, i),
        )
        utils.bind_rightclick(
            wid['subitem', i],
            functools.partial(sub_open, i),
        )

    ttk.Label(f, text=_("Description:"), anchor="sw").grid(
        row=4,
        column=0,
        sticky="SW",
    )

    spr_frame = ttk.Frame(f, borderwidth=4, relief="sunken")
    spr_frame.grid(column=1, columnspan=2, row=4, sticky=W)
    # sprites: inputs, outputs, rotation handle, occupied/embed state,
    # desiredFacing
    for spr_id in SPR:
        wid['sprite', spr_id] = sprite = ttk.Label(
            spr_frame,
            image=img.spr('ap_grey'),
            relief="raised",
        )
        sprite.grid(row=0, column=spr_id.value)
        tooltip.add_tooltip(sprite)

    desc_frame = ttk.Frame(f, borderwidth=4, relief="sunken")
    desc_frame.grid(row=5, column=0, columnspan=3, sticky="EW")
    desc_frame.columnconfigure(0, weight=1)

    wid['desc'] = tkRichText(desc_frame, width=40, height=16)
    wid['desc'].grid(row=0, column=0, sticky="EW")

    desc_scroll = tk_tools.HidingScroll(
        desc_frame,
        orient=VERTICAL,
        command=wid['desc'].yview,
    )
    wid['desc']['yscrollcommand'] = desc_scroll.set
    desc_scroll.grid(row=0, column=1, sticky="NS")

    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)

    wid['moreinfo'] = ttk.Button(f,
                                 text=_("More Info>>"),
                                 command=show_more_info)
    wid['moreinfo'].grid(row=6, column=2, sticky=E)
    tooltip.add_tooltip(wid['moreinfo'])

    menu_info = Menu(wid['moreinfo'])
    menu_info.add_command(label='', state='disabled')

    def show_item_props():
        snd.fx('expand')
        itemPropWin.show_window(
            selected_item.get_properties(),
            wid['changedefaults'],
            selected_sub_item.name,
        )

    wid['changedefaults'] = ttk.Button(
        f,
        text=_("Change Defaults..."),
        command=show_item_props,
    )
    wid['changedefaults'].grid(row=6, column=1)
    tooltip.add_tooltip(
        wid['changedefaults'],
        _('Change the default settings for this item when placed.'))

    wid['variant'] = ttk.Combobox(
        f,
        values=['VERSION'],
        exportselection=0,
        # On Mac this defaults to being way too wide!
        width=7 if utils.MAC else None,
    )
    wid['variant'].state(['readonly'])  # Prevent directly typing in values
    wid['variant'].bind('<<ComboboxSelected>>', set_item_version)
    wid['variant'].current(0)
    wid['variant'].grid(row=6, column=0, sticky=W)

    itemPropWin.init(hide_item_props)
Пример #24
0
def make_map_widgets(frame: ttk.Frame):
    """Create widgets for the map settings pane.

    These are things which mainly affect the geometry or gameplay of the map.
    """
    frame.columnconfigure(0, weight=1)

    voice_frame = ttk.LabelFrame(
        frame,
        text=_('Voicelines:'),
        labelanchor=NW,
    )
    voice_frame.grid(row=1, column=0, sticky=EW)

    UI['voice_priority'] = voice_priority = ttk.Checkbutton(
        voice_frame,
        text=_("Use voiceline priorities"),
        variable=VOICE_PRIORITY_VAR,
        command=make_setter('General', 'use_voice_priority', VOICE_PRIORITY_VAR),
    )
    voice_priority.grid(row=0, column=0)
    add_tooltip(
        voice_priority,
        _("Only choose the highest-priority voicelines. This means more "
          "generic lines will can only be chosen if few test elements are in "
          "the map. If disabled any applicable lines will be used."),
    )

    elev_frame = ttk.LabelFrame(
        frame,
        text=_('Spawn at:'),
        labelanchor=N,
    )

    elev_frame.grid(row=2, column=0, sticky=EW)
    elev_frame.columnconfigure(0, weight=1)
    elev_frame.columnconfigure(1, weight=1)

    UI['elev_preview'] = ttk.Radiobutton(
        elev_frame,
        text=_('Entry Door'),
        value=0,
        variable=start_in_elev,
        command=make_setter('General', 'spawn_elev', start_in_elev),
    )

    UI['elev_elevator'] = ttk.Radiobutton(
        elev_frame,
        text=_('Elevator'),
        value=1,
        variable=start_in_elev,
        command=make_setter('General', 'spawn_elev', start_in_elev),
    )

    UI['elev_preview'].grid(row=0, column=0, sticky=W)
    UI['elev_elevator'].grid(row=0, column=1, sticky=W)

    add_tooltip(
        UI['elev_elevator'],
        _("When previewing in SP, spawn inside the entry elevator. "
          "This also disables the map restarts when you reach the "
          "exit door. Use this to examine the entry and exit corridors.")
    )
    add_tooltip(
        UI['elev_preview'],
        _("When previewing in SP, spawn just before the entry door. "
          "When you reach the exit door, the map will restart.")
    )

    corr_frame = ttk.LabelFrame(
        frame,
        width=18,
        text=_('Corridor:'),
        labelanchor=N,
    )
    corr_frame.grid(row=3, column=0, sticky=EW)
    corr_frame.columnconfigure(0, weight=1)
    corr_frame.columnconfigure(1, weight=1)

    make_corr_wid('sp_entry')
    make_corr_wid('sp_exit')
    make_corr_wid('coop')

    load_corridors()

    CORRIDOR['sp_entry'].widget(corr_frame).grid(row=1, column=0, sticky=EW)
    CORRIDOR['sp_exit'].widget(corr_frame).grid(row=1, column=1, sticky=EW)
    CORRIDOR['coop'].widget(corr_frame).grid(row=2, column=1, sticky=EW)

    ttk.Label(
        corr_frame,
        text=_('SP Entry:'),
        anchor=CENTER,
    ).grid(row=0, column=0, sticky=EW)
    ttk.Label(
        corr_frame,
        text=_('SP Exit:'),
        anchor=CENTER,
    ).grid(row=0, column=1, sticky=EW)
    ttk.Label(
        corr_frame,
        text=_('Coop:'),
        anchor=CENTER,
    ).grid(row=2, column=0, sticky=EW)

    model_frame = ttk.LabelFrame(
        frame,
        text=_('Player Model (SP):'),
        labelanchor=N,
    )
    model_frame.grid(row=4, column=0, sticky=EW)
    UI['player_mdl'] = ttk.Combobox(
        model_frame,
        exportselection=0,
        textvariable=player_model_var,
        values=[PLAYER_MODELS[mdl] for mdl in PLAYER_MODEL_ORDER],
        width=20,
    )
    # Users can only use the dropdown
    UI['player_mdl'].state(['readonly'])
    UI['player_mdl'].grid(row=0, column=0, sticky=EW)

    UI['player_mdl'].bind('<<ComboboxSelected>>', set_model)
    model_frame.columnconfigure(0, weight=1)
Пример #25
0
def make_comp_widgets(frame: ttk.Frame):
    """Create widgets for the compiler settings pane.

    These are generally things that are aesthetic, and to do with the file and
    compilation process.
    """
    frame.columnconfigure(0, weight=1)

    thumb_frame = ttk.LabelFrame(
        frame,
        text=_('Thumbnail'),
        labelanchor=N,
    )
    thumb_frame.grid(row=0, column=0, sticky=EW)
    thumb_frame.columnconfigure(0, weight=1)

    UI['thumb_auto'] = ttk.Radiobutton(
        thumb_frame,
        text=_('Auto'),
        value='AUTO',
        variable=chosen_thumb,
        command=set_screen_type,
    )

    UI['thumb_peti'] = ttk.Radiobutton(
        thumb_frame,
        text=_('PeTI'),
        value='PETI',
        variable=chosen_thumb,
        command=set_screen_type,
    )

    UI['thumb_custom'] = ttk.Radiobutton(
        thumb_frame,
        text=_('Custom:'),
        value='CUST',
        variable=chosen_thumb,
        command=set_screen_type,
    )

    UI['thumb_label'] = ttk.Label(
        thumb_frame,
        anchor=CENTER,
        cursor=utils.CURSORS['link'],
    )
    UI['thumb_label'].bind(
        utils.EVENTS['LEFT'],
        find_screenshot,
    )

    UI['thumb_cleanup'] = ttk.Checkbutton(
        thumb_frame,
        text=_('Cleanup old screenshots'),
        variable=cleanup_screenshot,
        command=make_setter('Screenshot', 'del_old', cleanup_screenshot),
    )

    UI['thumb_auto'].grid(row=0, column=0, sticky='W')
    UI['thumb_peti'].grid(row=0, column=1, sticky='W')
    UI['thumb_custom'].grid(row=1, column=0, columnspan=2, sticky='NEW')
    UI['thumb_cleanup'].grid(row=3, columnspan=2, sticky='W')
    add_tooltip(
        UI['thumb_auto'],
        _("Override the map image to use a screenshot automatically taken "
          "from the beginning of a chamber. Press F5 to take a new "
          "screenshot. If the map has not been previewed recently "
          "(within the last few hours), the default PeTI screenshot "
          "will be used instead.")
    )
    add_tooltip(
        UI['thumb_peti'],
        _("Use the normal editor view for the map preview image.")
    )
    custom_tooltip = _(
        "Use a custom image for the map preview image. Click the "
        "screenshot to select.\n"
        "Images will be converted to JPEGs if needed."
    )
    add_tooltip(
        UI['thumb_custom'],
        custom_tooltip,
    )

    add_tooltip(
        UI['thumb_label'],
        custom_tooltip,
    )

    add_tooltip(
        UI['thumb_cleanup'],
        _('Automatically delete unused Automatic screenshots. '
          'Disable if you want to keep things in "portal2/screenshots". ')
    )

    if chosen_thumb.get() == 'CUST':
        # Show this if the user has set it before
        UI['thumb_label'].grid(row=2, column=0, columnspan=2, sticky='EW')
    set_screenshot()  # Load the last saved screenshot

    vrad_frame = ttk.LabelFrame(
        frame,
        text=_('Lighting:'),
        labelanchor=N,
    )
    vrad_frame.grid(row=1, column=0, sticky=EW)

    UI['light_fast'] = ttk.Radiobutton(
        vrad_frame,
        text=_('Fast'),
        value=0,
        variable=vrad_light_type,
        command=make_setter('General', 'vrad_force_full', vrad_light_type),
    )
    UI['light_fast'].grid(row=0, column=0)
    UI['light_full'] = ttk.Radiobutton(
        vrad_frame,
        text=_('Full'),
        value=1,
        variable=vrad_light_type,
        command=make_setter('General', 'vrad_force_full', vrad_light_type),
    )
    UI['light_full'].grid(row=0, column=1)

    add_tooltip(
        UI['light_fast'],
        _("Compile with lower-quality, fast lighting. This speeds "
          "up compile times, but does not appear as good. Some "
          "shadows may appear wrong.\n"
          "When publishing, this is ignored.")
    )
    add_tooltip(
        UI['light_full'],
        _("Compile with high-quality lighting. This looks correct, "
          "but takes longer to compute. Use if you're arranging lights. "
          "When publishing, this is always used.")
    )

    packfile_enable = ttk.Checkbutton(
        frame,
        text=_('Dump packed files to:'),
        variable=packfile_dump_enable,
        command=set_pack_dump_enabled,
    )

    packfile_frame = ttk.LabelFrame(
        frame,
        labelwidget=packfile_enable,
    )
    packfile_frame.grid(row=2, column=0, sticky=EW)

    UI['packfile_filefield'] = packfile_filefield = FileField(
        packfile_frame,
        is_dir=True,
        loc=COMPILE_CFG.get_val('General', 'packfile_dump_dir', ''),
        callback=set_pack_dump_dir,
    )
    packfile_filefield.grid(row=0, column=0, sticky=EW)
    packfile_frame.columnconfigure(0, weight=1)
    ttk.Frame(packfile_frame).grid(row=1)

    set_pack_dump_enabled()

    add_tooltip(
        packfile_enable,
        _("When compiling, dump all files which were packed into the map. Useful"
          " if you're intending to edit maps in Hammer.")
    )

    count_frame = ttk.LabelFrame(
        frame,
        text=_('Last Compile:'),
        labelanchor=N,
    )

    count_frame.grid(row=7, column=0, sticky=EW)
    count_frame.columnconfigure(0, weight=1)
    count_frame.columnconfigure(2, weight=1)

    ttk.Label(
        count_frame,
        text=_('Entity'),
        anchor=N,
    ).grid(row=0, column=0, columnspan=3, sticky=EW)

    UI['count_entity'] = ttk.Progressbar(
        count_frame,
        maximum=100,
        variable=count_entity,
        length=120,
    )
    UI['count_entity'].grid(
        row=1,
        column=0,
        columnspan=3,
        sticky=EW,
        padx=5,
    )

    ttk.Label(
        count_frame,
        text=_('Overlay'),
        anchor=CENTER,
    ).grid(row=2, column=0, sticky=EW)
    UI['count_overlay'] = ttk.Progressbar(
        count_frame,
        maximum=100,
        variable=count_overlay,
        length=50,
    )
    UI['count_overlay'].grid(row=3, column=0, sticky=EW, padx=5)

    UI['refresh_counts'] = SubPane.make_tool_button(
        count_frame,
        img.png('icons/tool_sub', resize_to=16),
        refresh_counts,
    )
    UI['refresh_counts'].grid(row=3, column=1)
    add_tooltip(
        UI['refresh_counts'],
        _("Refresh the compile progress bars. Press after a compile has been "
          "performed to show the new values."),
    )

    ttk.Label(
        count_frame,
        text=_('Brush'),
        anchor=CENTER,
    ).grid(row=2, column=2, sticky=EW)
    UI['count_brush'] = ttk.Progressbar(
        count_frame,
        maximum=100,
        variable=count_brush,
        length=50,
    )
    UI['count_brush'].grid(row=3, column=2, sticky=EW, padx=5)

    for wid_name in ('count_overlay', 'count_entity', 'count_brush'):
        # Add in tooltip logic to the widgets.
        add_tooltip(UI[wid_name])

    refresh_counts(reload=False)
Пример #26
0
def make_pane(tool_frame):
    """Create the styleVar pane.

    """
    global window
    window = SubPane(
        TK_ROOT,
        options=GEN_OPTS,
        title="Style Properties",
        name="style",
        resize_y=True,
        tool_frame=tool_frame,
        tool_img=png.png("icons/win_stylevar"),
        tool_col=3,
    )

    UI["style_can"] = Canvas(window, highlightthickness=0)
    # need to use a canvas to allow scrolling
    UI["style_can"].grid(sticky="NSEW")
    window.rowconfigure(0, weight=1)

    UI["style_scroll"] = ttk.Scrollbar(window, orient=VERTICAL, command=UI["style_can"].yview)
    UI["style_scroll"].grid(column=1, row=0, rowspan=2, sticky="NS")
    UI["style_can"]["yscrollcommand"] = UI["style_scroll"].set
    canvas_frame = ttk.Frame(UI["style_can"])

    frame_all = ttk.Labelframe(canvas_frame, text="All:")
    frame_all.grid(row=0, sticky="EW")

    frm_chosen = ttk.Labelframe(canvas_frame, text="Selected Style:")
    frm_chosen.grid(row=1, sticky="EW")

    ttk.Separator(canvas_frame, orient=HORIZONTAL).grid(row=2, sticky="EW", pady=(10, 5))

    frm_other = ttk.Labelframe(canvas_frame, text="Other Styles:")
    frm_other.grid(row=3, sticky="EW")

    UI["stylevar_chosen_none"] = ttk.Label(frm_chosen, text="No Options!", font="TkMenuFont", justify="center")
    UI["stylevar_other_none"] = ttk.Label(frm_other, text="None!", font="TkMenuFont", justify="center")

    for pos, var in enumerate(styleOptions):
        # Add the special stylevars which apply to all styles
        tk_vars[var.id] = IntVar(value=GEN_OPTS.get_bool("StyleVar", var.id, var.enabled))
        checkbox_special[var.id] = ttk.Checkbutton(
            frame_all, variable=tk_vars[var.id], text=var.name, command=functools.partial(set_stylevar, var.id)
        )
        checkbox_special[var.id].grid(row=pos, column=0, sticky="W", padx=3)

        if var.desc:
            tooltip.add_tooltip(checkbox_special[var.id], var.desc)

    for var in var_list:
        tk_vars[var.id] = IntVar(value=var.default)
        args = {"variable": tk_vars[var.id], "text": var.name, "command": functools.partial(set_stylevar, var.id)}
        checkbox_chosen[var.id] = ttk.Checkbutton(frm_chosen, **args)
        checkbox_other[var.id] = ttk.Checkbutton(frm_other, **args)
        if var.desc:
            tooltip.add_tooltip(checkbox_chosen[var.id], var.desc)
            tooltip.add_tooltip(checkbox_other[var.id], var.desc)

    UI["style_can"].create_window(0, 0, window=canvas_frame, anchor="nw")
    UI["style_can"].update_idletasks()
    UI["style_can"].config(scrollregion=UI["style_can"].bbox(ALL), width=canvas_frame.winfo_reqwidth())
    ttk.Sizegrip(window, cursor=utils.CURSORS["stretch_vert"]).grid(row=1, column=0)

    UI["style_can"].bind("<Configure>", flow_stylevar)

    # Scroll globally even if canvas is not selected.
    if utils.WIN:
        window.bind("<MouseWheel>", lambda e: scroll(int(-1 * (e.delta / 120))))
    elif utils.MAC:
        window.bind("<Button-4>", lambda e: scroll(1))
        window.bind("<Button-5>", lambda e: scroll(-1))
Пример #27
0
def make_pane(tool_frame):
    """Create the styleVar pane.

    """
    global window
    window = SubPane(
        TK_ROOT,
        options=BEE2_config.GEN_OPTS,
        title=_('Style/Item Properties'),
        name='style',
        resize_y=True,
        tool_frame=tool_frame,
        tool_img=img.png('icons/win_stylevar'),
        tool_col=3,
    )

    UI['nbook'] = nbook = ttk.Notebook(window)

    nbook.grid(row=0, column=0, sticky=NSEW)
    window.rowconfigure(0, weight=1)
    window.columnconfigure(0, weight=1)
    nbook.enable_traversal()

    stylevar_frame = ttk.Frame(nbook)
    stylevar_frame.rowconfigure(0, weight=1)
    stylevar_frame.columnconfigure(0, weight=1)
    nbook.add(stylevar_frame, text=_('Styles'))

    UI['style_can'] = Canvas(stylevar_frame, highlightthickness=0)
    # need to use a canvas to allow scrolling
    UI['style_can'].grid(sticky='NSEW')
    window.rowconfigure(0, weight=1)

    UI['style_scroll'] = ttk.Scrollbar(
        stylevar_frame,
        orient=VERTICAL,
        command=UI['style_can'].yview,
        )
    UI['style_scroll'].grid(column=1, row=0, rowspan=2, sticky="NS")
    UI['style_can']['yscrollcommand'] = UI['style_scroll'].set

    utils.add_mousewheel(UI['style_can'], stylevar_frame)

    canvas_frame = ttk.Frame(UI['style_can'])

    frame_all = ttk.Labelframe(canvas_frame, text=_("All:"))
    frame_all.grid(row=0, sticky='EW')

    frm_chosen = ttk.Labelframe(canvas_frame, text=_("Selected Style:"))
    frm_chosen.grid(row=1, sticky='EW')

    ttk.Separator(
        canvas_frame,
        orient=HORIZONTAL,
        ).grid(row=2, sticky='EW', pady=(10, 5))

    frm_other = ttk.Labelframe(canvas_frame, text=_("Other Styles:"))
    frm_other.grid(row=3, sticky='EW')

    UI['stylevar_chosen_none'] = ttk.Label(
        frm_chosen,
        text=_('No Options!'),
        font='TkMenuFont',
        justify='center',
        )
    UI['stylevar_other_none'] = ttk.Label(
        frm_other,
        text=_('None!'),
        font='TkMenuFont',
        justify='center',
        )

    all_pos = 0
    for all_pos, var in enumerate(styleOptions):
        # Add the special stylevars which apply to all styles
        tk_vars[var.id] = int_var = IntVar(value=var.default)
        checkbox_all[var.id] = ttk.Checkbutton(
            frame_all,
            variable=int_var,
            text=var.name,
        )
        checkbox_all[var.id].grid(row=all_pos, column=0, sticky="W", padx=3)

        # Special case - this needs to refresh the filter when swapping,
        # so the items disappear or reappear.
        if var.id == 'UnlockDefault':
            def cmd():
                update_filter()
            checkbox_all[var.id]['command'] = cmd

        tooltip.add_tooltip(
            checkbox_all[var.id],
            make_desc(var, is_hardcoded=True),
        )

    for var in VAR_LIST:
        tk_vars[var.id] = IntVar(value=var.enabled)
        args = {
            'variable': tk_vars[var.id],
            'text': var.name,
            }
        desc = make_desc(var)
        if var.applies_to_all():
            # Available in all styles - put with the hardcoded variables.
            all_pos += 1

            checkbox_all[var.id] = check = ttk.Checkbutton(frame_all, **args)
            check.grid(row=all_pos, column=0, sticky="W", padx=3)
            tooltip.add_tooltip(check, desc)
        else:
            # Swap between checkboxes depending on style.
            checkbox_chosen[var.id] = ttk.Checkbutton(frm_chosen, **args)
            checkbox_other[var.id] = ttk.Checkbutton(frm_other, **args)
            tooltip.add_tooltip(
                checkbox_chosen[var.id],
                desc,
            )
            tooltip.add_tooltip(
                checkbox_other[var.id],
                desc,
            )

    UI['style_can'].create_window(0, 0, window=canvas_frame, anchor="nw")
    UI['style_can'].update_idletasks()
    UI['style_can'].config(
        scrollregion=UI['style_can'].bbox(ALL),
        width=canvas_frame.winfo_reqwidth(),
    )

    if utils.USE_SIZEGRIP:
        ttk.Sizegrip(
            window,
            cursor=utils.CURSORS['stretch_vert'],
        ).grid(row=1, column=0)

    UI['style_can'].bind('<Configure>', flow_stylevar)

    item_config_frame = ttk.Frame(nbook)
    nbook.add(item_config_frame, text=_('Items'))
    itemconfig.make_pane(item_config_frame)
Пример #28
0
    def __init__(
        self,
        tk,
        lst,
        *,  # Make all keyword-only for readability
        has_none=True,
        has_def=True,
        sound_sys: FileSystemChain = None,
        modal=False,
        # i18n: 'None' item description
        none_desc=_('Do not add anything.'),
        none_attrs=EmptyMapping,
        none_icon='BEE2/none_96.png',
        # i18n: 'None' item name.
        none_name=_("<None>"),
        title='BEE2',
        desc='',
        readonly_desc='',
        callback=None,
        callback_params=(),
        attributes=()):
        """Create a window object.

        Read from .selected_id to get the currently-chosen Item name, or None
        if the <none> Item is selected.
        Args:
        - tk: Must be a Toplevel window, either the tk() root or another
        window if needed.
        - lst: A list of Item objects, defining the visible items.
        - If has_none is True, a <none> item will be added to the beginning
          of the list.
        - If has_def is True, the 'Reset to Default' button will appear,
          which resets to the suggested item.
        - If snd_sample_sys is set, a '>' button will appear next to names
          to play the associated audio sample for the item.
          The value should be a FileSystem to look for samples in.
        - none_desc holds an optional description for the <none> Item,
          which can be used to describe what it results in.
        - none_icon allows changing the icon for the <none> Item.
        - none_name allows setting the name shown for the <none> Item.
        - title is the title of the selector window.
        - callback is a function to be called whenever the selected item
         changes.
        - callback_params is a list of additional values which will be
          passed to the callback function.
          The first argument to the callback is always the selected item ID.
        - full_context controls if the short or long names are used for the
          context menu.
        - attributes is a list of AttrDef tuples.
          Each tuple should contain an ID, display text, and default value.
          If the values are True or False a check/cross will be displayed,
          otherwise they're a string.
        - desc is descriptive text to display on the window, and in the widget
          tooltip.
        - readonly_desc will be displayed on the widget tooltip when readonly.
        - modal: If True, the window will block others while open.
        """
        self.noneItem = Item(
            name='<NONE>',
            short_name='',
            icon=none_icon,
            desc=none_desc,
            attributes=dict(none_attrs),
        )

        # The textbox on the parent window.
        self.display = None  # type: tk_tools.ReadOnlyEntry

        # Variable associated with self.display.
        self.disp_label = StringVar()

        # The '...' button to open our window.
        self.disp_btn = None  # type: ttk.Button

        # ID of the currently chosen item
        self.chosen_id = None

        # Callback function, and positional arugments to pass
        if callback is not None:
            self.callback = callback
            self.callback_params = list(callback_params)
        else:
            self.callback = None
            self.callback_params = ()

        # Item object for the currently suggested item.
        self.suggested = None

        # Should we have the 'reset to default' button?
        self.has_def = has_def
        self.description = desc
        self.readonly_description = readonly_desc

        if has_none:
            self.item_list = [self.noneItem] + lst
        else:
            self.item_list = lst
        try:
            self.selected = self.item_list[0]  # type: Item
        except IndexError:
            LOGGER.error('No items for window "{}"!', title)
            # We crash without items, forcefully add the None item in so at
            # least this works.
            self.item_list = [self.noneItem]
            self.selected = self.noneItem

        self.orig_selected = self.selected
        self.parent = tk
        self._readonly = False
        self.modal = modal

        self.win = Toplevel(tk)
        self.win.withdraw()
        self.win.title("BEE2 - " + title)
        self.win.transient(master=tk)

        # Allow resizing in X and Y.
        self.win.resizable(True, True)

        tk_tools.set_window_icon(self.win)

        # Run our quit command when the exit button is pressed, or Escape
        # on the keyboard.
        self.win.protocol("WM_DELETE_WINDOW", self.exit)
        self.win.bind("<Escape>", self.exit)

        # Allow navigating with arrow keys.
        self.win.bind("<KeyPress>", self.key_navigate)

        # A map from group name -> header widget
        self.group_widgets = {}
        # A map from folded name -> display name
        self.group_names = {}
        self.grouped_items = defaultdict(list)
        # A list of folded group names in the display order.
        self.group_order = []

        # The maximum number of items that fits per row (set in flow_items)
        self.item_width = 1

        if desc:
            self.desc_label = ttk.Label(
                self.win,
                text=desc,
                justify=LEFT,
                anchor=W,
                width=5,  # Keep a small width, so this doesn't affect the
                # initial window size.
            )
            self.desc_label.grid(row=0, column=0, sticky='EW')

        # PanedWindow allows resizing the two areas independently.
        self.pane_win = PanedWindow(
            self.win,
            orient=HORIZONTAL,
            sashpad=2,  # Padding above/below panes
            sashwidth=3,  # Width of border
            sashrelief=RAISED,  # Raise the border between panes
        )
        self.pane_win.grid(row=1, column=0, sticky="NSEW")
        self.win.columnconfigure(0, weight=1)
        self.win.rowconfigure(1, weight=1)

        shim = ttk.Frame(self.pane_win, relief="sunken")
        shim.rowconfigure(0, weight=1)
        shim.columnconfigure(0, weight=1)

        # We need to use a canvas to allow scrolling.
        self.wid_canvas = Canvas(shim, highlightthickness=0)
        self.wid_canvas.grid(row=0, column=0, sticky="NSEW")

        # Add another frame inside to place labels on.
        self.pal_frame = ttk.Frame(self.wid_canvas)
        self.wid_canvas.create_window(1, 1, window=self.pal_frame, anchor="nw")

        self.wid_scroll = tk_tools.HidingScroll(
            shim,
            orient=VERTICAL,
            command=self.wid_canvas.yview,
        )
        self.wid_scroll.grid(row=0, column=1, sticky="NS")
        self.wid_canvas['yscrollcommand'] = self.wid_scroll.set

        utils.add_mousewheel(self.wid_canvas, self.win)

        if utils.MAC:
            # Labelframe doesn't look good here on OSX
            self.sugg_lbl = ttk.Label(
                self.pal_frame,
                # Draw lines with box drawing characters
                text="\u250E\u2500" + _("Suggested") + "\u2500\u2512",
            )
        else:
            self.sugg_lbl = ttk.LabelFrame(
                self.pal_frame,
                text=_("Suggested"),
                labelanchor=N,
                height=50,
            )

        # Holds all the widgets which provide info for the current item.
        self.prop_frm = ttk.Frame(self.pane_win,
                                  borderwidth=4,
                                  relief='raised')
        self.prop_frm.columnconfigure(1, weight=1)

        # Border around the selected item icon.
        width, height = img.tuple_size(ICON_SIZE_LRG)
        self.prop_icon_frm = ttk.Frame(
            self.prop_frm,
            borderwidth=4,
            relief='raised',
            width=width,
            height=height,
        )
        self.prop_icon_frm.grid(row=0, column=0, columnspan=4)

        self.prop_icon = ttk.Label(
            self.prop_icon_frm,
            image=img.color_square(img.PETI_ITEM_BG, ICON_SIZE_LRG),
        )
        self.prop_icon.grid(row=0, column=0)

        name_frame = ttk.Frame(self.prop_frm)

        self.prop_name = ttk.Label(
            name_frame,
            text="Item",
            justify=CENTER,
            font=("Helvetica", 12, "bold"),
        )
        name_frame.grid(row=1, column=0, columnspan=4)
        name_frame.columnconfigure(0, weight=1)
        self.prop_name.grid(row=0, column=0)

        # For music items, add a '>' button to play sound samples
        if sound_sys is not None and sound.initiallised:
            self.samp_button = samp_button = ttk.Button(
                name_frame,
                text=BTN_PLAY,
                width=1,
            )
            samp_button.grid(row=0, column=1)
            add_tooltip(
                samp_button,
                _("Play a sample of this item."),
            )

            def set_samp_play():
                samp_button['text'] = BTN_PLAY

            def set_samp_stop():
                samp_button['text'] = BTN_STOP

            self.sampler = sound.SamplePlayer(
                stop_callback=set_samp_play,
                start_callback=set_samp_stop,
                system=sound_sys,
            )
            samp_button['command'] = self.sampler.play_sample
            utils.bind_leftclick(self.prop_icon, self.sampler.play_sample)
            samp_button.state(('disabled', ))
        else:
            self.sampler = None

        # If we have a sound sampler, hold the system open while the window
        # is so it doesn't snap open/closed while finding files.
        self.sampler_held_open = False

        self.prop_author = ttk.Label(self.prop_frm, text="Author")
        self.prop_author.grid(row=2, column=0, columnspan=4)

        self.prop_desc_frm = ttk.Frame(self.prop_frm, relief="sunken")
        self.prop_desc_frm.grid(row=4, column=0, columnspan=4, sticky="NSEW")
        self.prop_desc_frm.rowconfigure(0, weight=1)
        self.prop_desc_frm.columnconfigure(0, weight=1)
        self.prop_frm.rowconfigure(4, weight=1)

        self.prop_desc = tkRichText(
            self.prop_desc_frm,
            width=40,
            height=4,
            font="TkSmallCaptionFont",
        )
        self.prop_desc.grid(
            row=0,
            column=0,
            padx=(2, 0),
            pady=2,
            sticky='NSEW',
        )

        self.prop_scroll = tk_tools.HidingScroll(
            self.prop_desc_frm,
            orient=VERTICAL,
            command=self.prop_desc.yview,
        )
        self.prop_scroll.grid(
            row=0,
            column=1,
            sticky="NS",
            padx=(0, 2),
            pady=2,
        )
        self.prop_desc['yscrollcommand'] = self.prop_scroll.set

        ttk.Button(
            self.prop_frm,
            text=_("OK"),
            command=self.save,
        ).grid(
            row=6,
            column=0,
            padx=(8, 8),
        )

        if self.has_def:
            self.prop_reset = ttk.Button(
                self.prop_frm,
                text=_("Reset to Default"),
                command=self.sel_suggested,
            )
            self.prop_reset.grid(
                row=6,
                column=1,
                sticky='EW',
            )

        ttk.Button(
            self.prop_frm,
            text=_("Cancel"),
            command=self.exit,
        ).grid(
            row=6,
            column=2,
            padx=(8, 8),
        )

        self.win.option_add('*tearOff', False)
        self.context_menu = Menu(self.win)

        self.norm_font = tk_font.nametofont('TkMenuFont')

        # Make a font for showing suggested items in the context menu
        self.sugg_font = self.norm_font.copy()
        self.sugg_font['weight'] = tk_font.BOLD

        # Make a font for previewing the suggested item
        self.mouseover_font = self.norm_font.copy()
        self.mouseover_font['slant'] = tk_font.ITALIC
        self.context_var = IntVar()

        # The headers for the context menu
        self.context_menus = {}

        # Sort alphabetically, preferring a sort key if present.
        self.item_list.sort(key=lambda it: it.sort_key or it.longName)

        for ind, item in enumerate(self.item_list):
            item._selector = self

            if item == self.noneItem:
                item.button = ttk.Button(
                    self.pal_frame,
                    image=item.icon,
                )
                item.context_lbl = none_name
            else:
                item.button = ttk.Button(
                    self.pal_frame,
                    text=item.shortName,
                    image=item.icon,
                    compound='top',
                )

            group_key = item.group.casefold()
            self.grouped_items[group_key].append(item)

            if group_key not in self.group_names:
                # If the item is groupless, use 'Other' for the header.
                self.group_names[group_key] = item.group or _('Other')

            if not item.group:
                # Ungrouped items appear directly in the menu.
                menu = self.context_menus[''] = self.context_menu
            else:
                try:
                    menu = self.context_menus[group_key]
                except KeyError:
                    self.context_menus[group_key] = menu = Menu(
                        self.context_menu, )

            menu.add_radiobutton(
                label=item.context_lbl,
                command=functools.partial(self.sel_item_id, item.name),
                var=self.context_var,
                value=ind,
            )
            item._context_ind = len(self.grouped_items[group_key]) - 1

            @utils.bind_leftclick(item.button)
            def click_item(event=None, *, _item=item):
                """Handle clicking on the item.

                If it's already selected, save and close the window.
                """
                # We need to capture the item in a default, since it's
                # the same variable in different iterations
                if _item is self.selected:
                    self.save()
                else:
                    self.sel_item(_item)

        # Convert to a normal dictionary, after adding all items.
        self.grouped_items = dict(self.grouped_items)

        # Figure out the order for the groups - alphabetical.
        # Note - empty string should sort to the beginning!
        self.group_order[:] = sorted(self.grouped_items.keys())

        for index, (key, menu) in enumerate(
                sorted(self.context_menus.items(), key=itemgetter(0)),
                # We start with the ungrouped items, so increase the index
                # appropriately.
                start=len(self.grouped_items.get('', ()))):
            if key == '':
                # Don't add the ungrouped menu to itself!
                continue
            self.context_menu.add_cascade(
                menu=menu,
                label=self.group_names[key],
            )
            # Set a custom attribute to keep track of the menu's index.
            menu._context_index = index

        for group_key, text in self.group_names.items():
            self.group_widgets[group_key] = GroupHeader(
                self,
                text,
            )

        self.pane_win.add(shim)
        self.pane_win.add(self.prop_frm)

        # Force a minimum size for the two parts
        self.pane_win.paneconfigure(shim, minsize=100, stretch='always')
        self.prop_frm.update_idletasks()  # Update reqwidth()
        self.pane_win.paneconfigure(
            self.prop_frm,
            minsize=200,
            stretch='never',
        )

        if attributes:
            attr_frame = ttk.Frame(self.prop_frm)
            attr_frame.grid(
                row=5,
                column=0,
                columnspan=3,
                sticky=EW,
            )

            self.attr = {}
            # Add in all the attribute labels
            for index, attr in enumerate(attributes):
                desc_label = ttk.Label(
                    attr_frame,
                    text=attr.desc,
                )
                self.attr[attr.id] = val_label = ttk.Label(attr_frame, )
                val_label.default = attr.default
                val_label.type = attr.type
                if attr.type is AttrTypes.BOOL:
                    # It's a tick/cross label
                    val_label['image'] = (ICON_CHECK
                                          if attr.default else ICON_CROSS, )
                elif attr.type is AttrTypes.COLOR:
                    # A small colour swatch.
                    val_label.configure(relief=RAISED, )
                    # Show the color value when hovered.
                    add_tooltip(val_label)

                # Position in a 2-wide grid
                desc_label.grid(
                    row=index // 2,
                    column=(index % 2) * 2,
                    sticky=E,
                )
                val_label.grid(
                    row=index // 2,
                    column=(index % 2) * 2 + 1,
                    sticky=W,
                )
        else:
            self.attr = self.desc_label = None

        self.flow_items()
        self.wid_canvas.bind("<Configure>", self.flow_items)
Пример #29
0
    def __init__(self, parent, items=(), headers=(), add_sizegrip=False):
        """Initialise a CheckDetails pane.

        parent is the parent widget.
        items is a list of Items objects.
        headers is a list of the header strings.
        If add_sizegrip is True, add a sizegrip object between the scrollbars.
        """
        super(CheckDetails, self).__init__(parent)

        self.parent = parent
        self.headers = list(headers)
        self.items = []  # type: List[Item]
        self.sort_ind = None
        self.rev_sort = False  # Should we sort in reverse?

        self.head_check_var = tk.IntVar(value=False)
        self.wid_head_check = ttk.Checkbutton(
            self,
            variable=self.head_check_var,
            command=self.toggle_allcheck,
            takefocus=False,
            width=0,
        )
        self.wid_head_check.grid(row=0, column=0)

        add_tooltip(self.wid_head_check, _("Toggle all checkboxes."))

        def checkbox_enter(e):
            """When hovering over the 'all' checkbox, highlight the others."""
            for item in self.items:
                item.check.state(['active'])

        self.wid_head_check.bind('<Enter>', checkbox_enter)

        def checkbox_leave(e):
            for item in self.items:
                item.check.state(['!active'])

        self.wid_head_check.bind('<Leave>', checkbox_leave)

        self.wid_header = tk.PanedWindow(
            self,
            orient=tk.HORIZONTAL,
            sashrelief=tk.RAISED,
            sashpad=2,
            showhandle=False,
        )
        self.wid_header.grid(row=0, column=1, sticky='EW')
        self.wid_head_frames = [0] * len(self.headers)  # type: List[ttk.Frame]
        self.wid_head_label = [0] * len(self.headers)  # type: List[ttk.Label]
        self.wid_head_sort = [0] * len(self.headers)  # type: List[ttk.Label]
        self.make_headers()

        self.wid_canvas = tk.Canvas(self, )
        self.wid_canvas.grid(row=1, column=0, columnspan=2, sticky='NSEW')
        self.columnconfigure(1, weight=1)
        self.rowconfigure(1, weight=1)

        self.horiz_scroll = ttk.Scrollbar(
            self,
            orient=tk.HORIZONTAL,
            command=self.wid_canvas.xview,
        )
        self.vert_scroll = ttk.Scrollbar(
            self,
            orient=tk.VERTICAL,
            command=self.wid_canvas.yview,
        )
        self.wid_canvas['xscrollcommand'] = self.horiz_scroll.set
        self.wid_canvas['yscrollcommand'] = self.vert_scroll.set

        self.horiz_scroll.grid(row=2, column=0, columnspan=2, sticky='EWS')
        self.vert_scroll.grid(row=1, column=2, sticky='NSE')
        if add_sizegrip and utils.USE_SIZEGRIP:
            self.sizegrip = ttk.Sizegrip(self)
            self.sizegrip.grid(row=2, column=2)
        else:
            self.sizegrip = None

        self.wid_frame = tk.Frame(self.wid_canvas,
                                  background='white',
                                  border=0)
        self.wid_canvas.create_window(0, 0, window=self.wid_frame, anchor='nw')

        self.bind('<Configure>', self.refresh)
        self.bind('<Map>', self.refresh)  # When added to a window, refresh

        self.wid_header.bind('<ButtonRelease-1>', self.refresh)
        self.wid_header.bind('<B1-Motion>', self.refresh)
        self.wid_header.bind('<Configure>', self.refresh)

        self.add_items(*items)

        utils.add_mousewheel(
            self.wid_canvas,
            self.wid_canvas,
            self.wid_frame,
            self.wid_header,
        )
Пример #30
0
def make_tab(group, config: ConfigFile, tab_type):
    """Create all the widgets for a tab."""
    if tab_type is TabTypes.MIDCHAMBER:
        # Mid-chamber voice lines have predefined values.
        group_name = _('Mid - Chamber')
        group_id = 'MIDCHAMBER'
        group_desc = _(
            'Lines played during the actual chamber, '
            'after specific events have occurred.'
        )
    elif tab_type is TabTypes.RESPONSE:
        # Note: 'Response' tab header, and description
        group_name = _('Responses')
        group_id = None
        group_desc = _(
            'Lines played in response to certain events in Coop.'
        )
    elif tab_type is TabTypes.NORM:
        group_name = group['name', 'No Name!']
        group_id = group_name.upper()
        group_desc = group['desc', ''] + ':'
    else:
        raise ValueError('Invalid tab type!')

    # This is just to hold the canvas and scrollbar
    outer_frame = ttk.Frame(UI['tabs'])
    outer_frame.columnconfigure(0, weight=1)
    outer_frame.rowconfigure(0, weight=1)

    TABS[group_name] = outer_frame
    # We add this attribute so the refresh() method knows all the
    # tab names
    outer_frame.nb_text = group_name
    outer_frame.nb_type = tab_type

    # We need a canvas to make the list scrollable.
    canv = Canvas(
        outer_frame,
        highlightthickness=0,
        )
    scroll = tk_tools.HidingScroll(
        outer_frame,
        orient=VERTICAL,
        command=canv.yview,
        )
    canv['yscrollcommand'] = scroll.set
    canv.grid(row=0, column=0, sticky='NSEW')
    scroll.grid(row=0, column=1, sticky='NS')

    UI['tabs'].add(outer_frame)

    # This holds the actual elements
    frame = ttk.Frame(
        canv,
        )
    frame.columnconfigure(0, weight=1)
    canv.create_window(0, 0, window=frame, anchor="nw")

    ttk.Label(
        frame,
        text=group_name,
        anchor='center',
        font='tkHeadingFont',
        ).grid(
            row=0,
            column=0,
            sticky='EW',
            )

    ttk.Label(
        frame,
        text=group_desc,
        ).grid(
            row=1,
            column=0,
            sticky='EW',
            )

    ttk.Separator(frame, orient=HORIZONTAL).grid(
        row=2,
        column=0,
        sticky='EW',
    )

    if tab_type is TabTypes.RESPONSE:
        sorted_quotes = sorted(
            group,
            key=lambda prop: prop.real_name
        )
    else:
        sorted_quotes = sorted(
            group.find_all('Quote'),
            key=quote_sort_func,
            reverse=True,
        )

    for quote in sorted_quotes:  # type: Property
        if not quote.has_children():
            continue # Skip over config commands..

        if tab_type is TabTypes.RESPONSE:
            try:
                name = RESPONSE_NAMES[quote.name]
            except KeyError:
                # Convert channels of the form 'death_goo' into 'Death - Goo'.
                channel, ch_arg = quote.name.split('_', 1)
                name = channel.title() + ' - ' + ch_arg.title()
                del channel, ch_arg

            group_id = quote.name
        else:
            # note: default for quote names
            name = quote['name', _('No Name!')]

        ttk.Label(
            frame,
            text=name,
            font=QUOTE_FONT,
        ).grid(
            column=0,
            sticky=W,
        )

        if tab_type is TabTypes.RESPONSE:
            line_iter = find_resp_lines(quote)
        else:
            line_iter = find_lines(quote)

        for badges, line, line_id in line_iter:
            line_frame = ttk.Frame(
                frame,
            )
            line_frame.grid(
                column=0,
                padx=(10, 0),
                sticky=W,
            )
            for x, (img, ctx) in enumerate(badges):
                label = ttk.Label(line_frame, image=img, padding=0)
                label.grid(row=0, column=x)
                add_tooltip(label, ctx)

            line_frame.columnconfigure(len(badges), weight=1)

            check = ttk.Checkbutton(
                line_frame,
                # note: default voice line name next to checkbox.
                text=line['name', _('No Name?')],
            )

            check.quote_var = IntVar(
                value=config.get_bool(group_id, line_id, True),
            )

            check['variable'] = check.quote_var

            check['command'] = functools.partial(
                check_toggled,
                var=check.quote_var,
                config_section=config[group_id],
                quote_id=line_id,
            )
            check.transcript = list(get_trans_lines(line))
            check.grid(
                row=0,
                column=len(badges),
            )
            check.bind("<Enter>", show_trans)

    def configure_canv(e):
        """Allow resizing the windows."""
        canv['scrollregion'] = (
            4,
            0,
            canv.winfo_reqwidth(),
            frame.winfo_reqheight(),
        )
        frame['width'] = canv.winfo_reqwidth()

    canv.bind('<Configure>', configure_canv)

    return outer_frame
Пример #31
0
def init():
    """Initialise all widgets in the given window."""
    for cat, btn_text in [
            ('back_', 'Restore:'),
            ('game_', 'Backup:'),
            ]:
        UI[cat + 'frame'] = frame = ttk.Frame(
            window,
        )
        UI[cat + 'title_frame'] = title_frame = ttk.Frame(
            frame,
        )
        title_frame.grid(row=0, column=0, sticky='EW')
        UI[cat + 'title'] = ttk.Label(
            title_frame,
            font='TkHeadingFont',
        )
        UI[cat + 'title'].grid(row=0, column=0)
        title_frame.rowconfigure(0, weight=1)
        title_frame.columnconfigure(0, weight=1)

        UI[cat + 'details'] = CheckDetails(
            frame,
            headers=HEADERS,
        )
        UI[cat + 'details'].grid(row=1, column=0, sticky='NSEW')
        frame.rowconfigure(1, weight=1)
        frame.columnconfigure(0, weight=1)

        button_frame = ttk.Frame(
            frame,
        )
        button_frame.grid(column=0, row=2)
        ttk.Label(button_frame, text=btn_text).grid(row=0, column=0)
        UI[cat + 'btn_all'] = ttk.Button(
            button_frame,
            text='All',
            width=3,
        )
        UI[cat + 'btn_sel'] = ttk.Button(
            button_frame,
            text='Checked',
            width=8,
        )
        UI[cat + 'btn_all'].grid(row=0, column=1)
        UI[cat + 'btn_sel'].grid(row=0, column=2)

        UI[cat + 'btn_del'] = ttk.Button(
            button_frame,
            text='Delete Checked',
            width=14,
        )
        UI[cat + 'btn_del'].grid(row=1, column=0, columnspan=3)

        utils.add_mousewheel(
            UI[cat + 'details'].wid_canvas,
            UI[cat + 'frame'],
        )

    UI['game_refresh'] = ttk.Button(
        UI['game_title_frame'],
        image=img.png('icons/tool_sub'),
        command=ui_refresh_game,
    )
    UI['game_refresh'].grid(row=0, column=1, sticky='E')
    add_tooltip(
        UI['game_refresh'],
        "Reload the map list.",
    )

    UI['game_title']['textvariable'] = game_name
    UI['back_title']['textvariable'] = backup_name

    UI['game_btn_all']['command'] = ui_backup_all
    UI['game_btn_sel']['command'] = ui_backup_sel

    UI['back_btn_all']['command'] = ui_restore_all
    UI['back_btn_sel']['command'] = ui_restore_sel

    UI['back_frame'].grid(row=1, column=0, sticky='NSEW')
    ttk.Separator(orient=tk.VERTICAL).grid(
        row=1, column=1, sticky='NS', padx=5,
    )
    UI['game_frame'].grid(row=1, column=2, sticky='NSEW')

    window.rowconfigure(1, weight=1)
    window.columnconfigure(0, weight=1)
    window.columnconfigure(2, weight=1)
Пример #32
0
def make_pane(tool_frame):
    """Create the compiler options pane.

    """
    global window
    window = SubPane.SubPane(
        TK_ROOT,
        options=GEN_OPTS,
        title='Compile Options',
        name='compiler',
        resize_x=True,
        resize_y=False,
        tool_frame=tool_frame,
        tool_img=png.png('icons/win_compiler'),
        tool_col=4,
    )
    window.columnconfigure(0, weight=1)

    thumb_frame = ttk.LabelFrame(
        window,
        text='Thumbnail',
        labelanchor=N,
    )
    thumb_frame.grid(row=0, column=0, sticky=EW)
    thumb_frame.columnconfigure(0, weight=1)

    UI['thumb_auto'] = ttk.Radiobutton(
        thumb_frame,
        text='Auto',
        value='AUTO',
        variable=chosen_thumb,
        command=set_screen_type,
    )

    UI['thumb_peti'] = ttk.Radiobutton(
        thumb_frame,
        text='PeTI',
        value='PETI',
        variable=chosen_thumb,
        command=set_screen_type,
    )

    UI['thumb_custom'] = ttk.Radiobutton(
        thumb_frame,
        text='Custom:',
        value='CUST',
        variable=chosen_thumb,
        command=set_screen_type,
    )

    UI['thumb_label'] = ttk.Label(
        thumb_frame,
        anchor=CENTER,
        cursor=utils.CURSORS['link'],
    )
    UI['thumb_label'].bind(
        utils.EVENTS['LEFT'],
        find_screenshot,
    )

    UI['thumb_cleanup'] = ttk.Checkbutton(
        thumb_frame,
        text='Cleanup old screenshots',
        variable=cleanup_screenshot,
        command=set_screenshot_cleanup,
    )

    UI['thumb_auto'].grid(row=0, column=0, sticky='W')
    UI['thumb_peti'].grid(row=0, column=1, sticky='W')
    UI['thumb_custom'].grid(row=1, column=0, columnspan=2, sticky='NEW')
    UI['thumb_cleanup'].grid(row=3, columnspan=2, sticky='W')
    add_tooltip(
        UI['thumb_auto'],
        "Override the map image to use a screenshot automatically taken"
        "from the beginning of a chamber. Press F5 to take a new "
        "screenshot. If the map has not been previewed recently "
        "(within the last few hours), the default PeTI screenshot "
        "will be used instead."
    )
    add_tooltip(
        UI['thumb_peti'],
        "Use the normal editor view for the map preview image."
    )
    custom_tooltip = (
        "Use a custom image for the map preview image. Click the "
        "screenshot to select.\n"
        "Images will be converted to JPEGs if needed."
    )
    add_tooltip(
        UI['thumb_custom'],
        custom_tooltip,
    )

    add_tooltip(
        UI['thumb_label'],
        custom_tooltip
    )

    add_tooltip(
        UI['thumb_cleanup'],
        'Automatically delete unused Automatic screenshots. '
        'Disable if you want to keep things in "portal2/screenshots". '
    )

    if chosen_thumb.get() == 'CUST':
        # Show this if the user has set it before
        UI['thumb_label'].grid(row=2, column=0, columnspan=2, sticky='EW')
    set_screenshot()  # Load the last saved screenshot

    vrad_frame = ttk.LabelFrame(
        window,
        text='Lighting:',
        labelanchor=N,
    )
    vrad_frame.grid(row=1, column=0, sticky=EW)

    UI['light_fast'] = ttk.Radiobutton(
        vrad_frame,
        text='Fast',
        value=0,
        variable=vrad_light_type,
        command=set_vrad_type,
    )
    UI['light_fast'].grid(row=0, column=0)
    UI['light_full'] = ttk.Radiobutton(
        vrad_frame,
        text='Full',
        value=1,
        variable=vrad_light_type,
        command=set_vrad_type,
    )
    UI['light_full'].grid(row=0, column=1)

    add_tooltip(
        UI['light_fast'],
        "Compile with lower-quality, fast lighting. This speeds "
        "up compile times, but does not appear as good. Some "
        "shadows may appear wrong.\n"
        "When publishing, this is ignored."
    )
    add_tooltip(
        UI['light_full'],
        "Compile with high-quality lighting. This looks correct, "
        "but takes longer to compute. Use if you're arranging lights."
        "When publishing, this is always used."
    )

    elev_frame = ttk.LabelFrame(
        window,
        text='Spawn at:',
        labelanchor=N,
    )

    elev_frame.grid(row=2, column=0, sticky=EW)
    elev_frame.columnconfigure(0, weight=1)
    elev_frame.columnconfigure(1, weight=1)

    UI['elev_preview'] = ttk.Radiobutton(
        elev_frame,
        text='Entry Door',
        value=0,
        variable=start_in_elev,
        command=set_elev_type,
    )

    UI['elev_elevator'] = ttk.Radiobutton(
        elev_frame,
        text='Elevator',
        value=1,
        variable=start_in_elev,
        command=set_elev_type,
    )

    UI['elev_preview'].grid(row=0, column=0, sticky=W)
    UI['elev_elevator'].grid(row=0, column=1, sticky=W)

    add_tooltip(
        UI['elev_elevator'],
        "When previewing in SP, spawn inside the entry elevator. "
        "This also disables the map restarts when you reach the "
        "exit door. Use this to examine the entry and exit corridors."
    )
    add_tooltip(
        UI['elev_preview'],
        "When previewing in SP, spawn just before the entry door. "
        "When you reach the exit door, the map will restart."
    )

    corr_frame = ttk.LabelFrame(
        window,
        text='Corridor:',
        labelanchor=N,
    )
    corr_frame.grid(row=3, column=0, sticky=EW)
    corr_frame.columnconfigure(0, weight=1)
    corr_frame.columnconfigure(1, weight=1)

    UI['corr_sp_entry'] = make_corr_combo(
        corr_frame,
        'sp_entry',
        width=9,
    )

    UI['corr_sp_exit'] = make_corr_combo(
        corr_frame,
        'sp_exit',
        width=9,
    )

    UI['corr_coop'] = make_corr_combo(
        corr_frame,
        'coop',
        width=9,
    )

    UI['corr_sp_entry'].grid(row=1, column=0, sticky=EW)
    UI['corr_sp_exit'].grid(row=1, column=1, sticky=EW)
    UI['corr_coop'].grid(row=2, column=1, sticky=EW)
    ttk.Label(
        corr_frame,
        text='SP Entry:',
        anchor=CENTER,
    ).grid(row=0, column=0, sticky=EW)
    ttk.Label(
        corr_frame,
        text='SP Exit:',
        anchor=CENTER,
    ).grid(row=0, column=1, sticky=EW)
    ttk.Label(
        corr_frame,
        text='Coop:',
        anchor=CENTER,
    ).grid(row=2, column=0, sticky=EW)

    model_frame = ttk.LabelFrame(
        window,
        text='Player Model (SP):',
        labelanchor=N,
    )
    model_frame.grid(row=4, column=0, sticky=EW)
    UI['player_mdl'] = ttk.Combobox(
        model_frame,
        exportselection=0,
        textvariable=player_model_var,
        values=PLAYER_MODEL_ORDER,
        width=20,
    )
    # Users can only use the dropdown
    UI['player_mdl'].state(['readonly'])
    UI['player_mdl'].grid(row=0, column=0, sticky=EW)

    UI['player_mdl'].bind('<<ComboboxSelected>>', set_model)
    model_frame.columnconfigure(0, weight=1)

    count_frame = ttk.LabelFrame(
        window,
        text='Last Compile:',
        labelanchor=N,
    )

    count_frame.grid(row=5, column=0, sticky=EW)
    count_frame.columnconfigure(0, weight=1)
    count_frame.columnconfigure(2, weight=1)

    ttk.Label(
        count_frame,
        text='Entity',
        anchor=N,
    ).grid(row=0, column=0, columnspan=3, sticky=EW)

    UI['count_ent'] = ttk.Progressbar(
        count_frame,
        maximum=MAX_ENTS,
        variable=count_ents,
        length=120,
    )
    UI['count_ent'].grid(
        row=1,
        column=0,
        columnspan=3,
        sticky=EW,
        padx=5,
    )

    ttk.Label(
        count_frame,
        text='Overlay',
        anchor=CENTER,
    ).grid(row=2, column=0, sticky=EW)
    UI['count_over'] = ttk.Progressbar(
        count_frame,
        maximum=MAX_OVERLAY,
        variable=count_overlay,
        length=50,
    )
    UI['count_over'].grid(row=3, column=0, sticky=EW, padx=5)

    UI['refresh_counts'] = SubPane.make_tool_button(
        count_frame,
        png.png('icons/tool_sub', resize_to=16),
        refresh_counts,
    )
    UI['refresh_counts'].grid(row=3, column=1)

    ttk.Label(
        count_frame,
        text='Brush',
        anchor=CENTER,
    ).grid(row=2, column=2, sticky=EW)
    UI['count_brush'] = ttk.Progressbar(
        count_frame,
        maximum=MAX_BRUSH,
        variable=count_brush,
        length=50,
    )
    UI['count_brush'].grid(row=3, column=2, sticky=EW, padx=5)

    UI['view_logs'] = ttk.Button(
        count_frame,
        text='View Logs',
    )
    UI['view_logs'].grid(row=4, column=0, columnspan=3, sticky=EW)

    refresh_counts(reload=False)
Пример #33
0
def make_pane(parent: ttk.Frame):
    """Create all the widgets we use."""
    if not CONFIG_ORDER:
        # No configs at all...
        ttk.Label(parent, text=_('No Item Configuration!')).pack(fill='both')
        return

    CONFIG_ORDER.sort(key=lambda grp: grp.name)

    parent.columnconfigure(0, weight=1)

    # Need to use a canvas to allow scrolling
    canvas = tk.Canvas(parent, highlightthickness=0)
    canvas.grid(row=0, column=0, sticky='NSEW')
    parent.rowconfigure(0, weight=1)

    scrollbar = ttk.Scrollbar(
        parent,
        orient='vertical',
        command=canvas.yview,
    )
    scrollbar.grid(column=1, row=0, sticky="ns")
    canvas['yscrollcommand'] = scrollbar.set

    utils.add_mousewheel(canvas, canvas, parent)
    canvas_frame = ttk.Frame(canvas)
    canvas.create_window(0, 0, window=canvas_frame, anchor="nw")
    canvas_frame.rowconfigure(0, weight=1)

    for conf_row, config in enumerate(CONFIG_ORDER):
        frame = ttk.LabelFrame(canvas_frame, text=config.name)
        frame.columnconfigure(0, weight=1)
        frame.grid(row=conf_row, column=0, sticky='nsew')

        row = 0

        widget_count = len(config.widgets) + len(config.multi_widgets)

        # Now make the widgets.
        if config.widgets:
            for row, wid in enumerate(config.widgets):
                wid_frame = ttk.Frame(frame)
                wid_frame.grid(row=row, column=0, sticky='ew')
                wid_frame.columnconfigure(1, weight=1)

                label = ttk.Label(wid_frame, text=wid.name + ': ')
                label.grid(row=0, column=0)
                widget = wid.create_func(wid_frame, wid.values, wid.config)
                widget.grid(row=0, column=1, sticky='e')

                if wid.tooltip:
                    add_tooltip(widget, wid.tooltip)
                    add_tooltip(label, wid.tooltip)
                    add_tooltip(wid_frame, wid.tooltip)

        if config.widgets and config.multi_widgets:
            ttk.Separator(orient='horizontal').grid(
                row=1, column=0, sticky='ew',
            )

        # Skip if no timer widgets
        if not config.multi_widgets:
            continue

        # Continue from wherever we were.
        for row, wid in enumerate(config.multi_widgets, start=row+1):
            # If we only have 1 widget, don't add a redundant title.
            if widget_count == 1:
                wid_frame = ttk.Frame(frame)
            else:
                wid_frame = ttk.LabelFrame(frame, text=wid.name)

            wid_frame.grid(row=row, column=0, sticky='ew')
            wid.multi_func(
                wid_frame,
                wid.values,
                wid.config,
            )

            if wid.tooltip:
                add_tooltip(wid_frame, wid.tooltip)

    canvas.update_idletasks()
    canvas.config(
        scrollregion=canvas.bbox('ALL'),
        width=canvas_frame.winfo_reqwidth(),
    )

    def canvas_reflow(e):
        canvas['scrollregion'] = canvas.bbox('all')

    canvas.bind('<Configure>', canvas_reflow)
Пример #34
0
    def __init__(self, parent, items=(), headers=(), add_sizegrip=False):
        """Initialise a CheckDetails pane.

        parent is the parent widget.
        items is a list of Items objects.
        headers is a list of the header strings.
        If add_sizegrip is True, add a sizegrip object between the scrollbars.
        """
        super(CheckDetails, self).__init__(parent)

        self.parent = parent
        self.headers = list(headers)
        self.items = []
        self.sort_ind = None
        self.rev_sort = False  # Should we sort in reverse?

        self.head_check_var = tk.IntVar(value=False)
        self.wid_head_check = ttk.Checkbutton(
            self,
            variable=self.head_check_var,
            command=self.toggle_allcheck,
            takefocus=False,
            width=0,
        )
        self.wid_head_check.grid(row=0, column=0)

        add_tooltip(
            self.wid_head_check,
            "Toggle all checkboxes."
        )

        def checkbox_enter(e):
            """When hovering over the 'all' checkbox, highlight the others."""
            for item in self.items:
                item.check.state(['active'])
        self.wid_head_check.bind('<Enter>', checkbox_enter)

        def checkbox_leave(e):
            for item in self.items:
                item.check.state(['!active'])
        self.wid_head_check.bind('<Leave>', checkbox_leave)

        self.wid_header = tk.PanedWindow(
            self,
            orient=tk.HORIZONTAL,
            sashrelief=tk.RAISED,
            sashpad=2,
            showhandle=False,
        )
        self.wid_header.grid(row=0, column=1, sticky='EW')
        self.wid_head_frames = [0] * len(self.headers)
        self.wid_head_label = [0] * len(self.headers)
        self.wid_head_sort = [0] * len(self.headers)
        self.make_headers()

        self.wid_canvas = tk.Canvas(
            self,
        )
        self.wid_canvas.grid(row=1, column=0, columnspan=2, sticky='NSEW')
        self.columnconfigure(1, weight=1)
        self.rowconfigure(1, weight=1)

        self.horiz_scroll = ttk.Scrollbar(
            self,
            orient=tk.HORIZONTAL,
            command=self.wid_canvas.xview,
        )
        self.vert_scroll = ttk.Scrollbar(
            self,
            orient=tk.VERTICAL,
            command=self.wid_canvas.yview,
        )
        self.wid_canvas['xscrollcommand'] = self.horiz_scroll.set
        self.wid_canvas['yscrollcommand'] = self.vert_scroll.set

        self.horiz_scroll.grid(row=2, column=0, columnspan=2, sticky='EWS')
        self.vert_scroll.grid(row=1, column=2, sticky='NSE')
        if add_sizegrip and utils.USE_SIZEGRIP:
            self.sizegrip = ttk.Sizegrip(self)
            self.sizegrip.grid(row=2, column=2)
        else:
            self.sizegrip = None

        self.wid_frame = tk.Frame(
            self.wid_canvas,
            background='white',
            border=0
        )
        self.wid_canvas.create_window(0, 0, window=self.wid_frame, anchor='nw')

        self.bind('<Configure>', self.refresh)
        self.bind('<Map>', self.refresh)  # When added to a window, refresh

        self.wid_header.bind('<ButtonRelease-1>', self.refresh)
        self.wid_header.bind('<B1-Motion>', self.refresh)
        self.wid_header.bind('<Configure>', self.refresh)

        self.add_items(*items)

        utils.add_mousewheel(
            self.wid_canvas,

            self.wid_canvas,
            self.wid_frame,
            self.wid_header,
        )
Пример #35
0
def make_pane(parent: ttk.Frame):
    """Create all the widgets we use."""
    if not CONFIG_ORDER:
        # No configs at all...
        ttk.Label(parent, text=_('No Item Configuration!')).pack(fill='both')
        return

    CONFIG_ORDER.sort(key=lambda grp: grp.name)

    parent.columnconfigure(0, weight=1)
    parent.rowconfigure(1, weight=1)

    item_frames = []  # type: List[ttk.Frame]

    def swap_to_item(e: tk.Event = None):
        """Swap what's shown in the pane."""
        for frame in item_frames:
            frame.grid_forget()

        cur_dropdown = dropdown.current()
        if cur_dropdown == -1:
            # Not valid
            return

        # Block sound for the first few millisec to stop excess sounds from
        # playing during gridding.
        sound.block_fx()

        item_frames[cur_dropdown].grid(row=1, column=0, sticky='nsew')

    dropdown = ttk.Combobox(
        parent,
        state='readonly',
        exportselection=False,
        values=[group.name for group in CONFIG_ORDER],
    )
    dropdown.grid(row=0, column=0, columnspan=2, sticky='ew')
    dropdown.bind('<<ComboboxSelected>>', swap_to_item)

    # need to use a canvas to allow scrolling
    canvas = tk.Canvas(parent, highlightthickness=0)
    canvas.grid(row=1, column=0, sticky='NSEW')
    parent.rowconfigure(1, weight=1)

    scrollbar = ttk.Scrollbar(
        parent,
        orient='vertical',
        command=canvas.yview,
    )
    scrollbar.grid(column=1, row=1, sticky="ns")
    canvas['yscrollcommand'] = scrollbar.set

    utils.add_mousewheel(canvas, parent)
    canvas_frame = ttk.Frame(canvas)
    canvas.create_window(0, 0, window=canvas_frame, anchor="nw")
    canvas_frame.rowconfigure(0, weight=1)

    for config in CONFIG_ORDER:
        frame = ttk.Frame(canvas_frame)
        frame.columnconfigure(0, weight=1)
        item_frames.append(frame)

        # Now make the widgets.
        if config.widgets:
            non_timer_frame = ttk.LabelFrame(frame, text=_('General'))
            non_timer_frame.grid(row=0, column=0, sticky='ew')
            non_timer_frame.columnconfigure(1, weight=1)

            for row, wid in enumerate(config.widgets):
                label = ttk.Label(non_timer_frame, text=wid.name + ': ')
                label.grid(row=row, column=0)
                widget = wid.create_func(non_timer_frame, wid.values,
                                         wid.config)
                widget.grid(row=row, column=1, sticky='ew')

                if wid.tooltip:
                    add_tooltip(widget, wid.tooltip)
                    add_tooltip(label, wid.tooltip)

        if config.widgets and config.multi_widgets:
            ttk.Separator(orient='horizontal').grid(
                row=1,
                column=0,
                sticky='ew',
            )

        # Skip if no timer widgets
        if not config.multi_widgets:
            continue

        for row, wid in enumerate(config.multi_widgets):

            wid_frame = ttk.LabelFrame(frame, text=wid.name)
            wid_frame.grid(row=2 + row, column=0, sticky='ew')
            wid_frame.columnconfigure(1, weight=1)

            wid.multi_func(
                wid_frame,
                wid.values,
                wid.config,
            )

            if wid.tooltip:
                add_tooltip(wid_frame, wid.tooltip)

    # Select the first item, so we show something.
    dropdown.current(0)
    swap_to_item()

    canvas.update_idletasks()
    canvas.config(
        scrollregion=canvas.bbox('ALL'),
        width=canvas_frame.winfo_reqwidth(),
    )

    def canvas_reflow(e):
        canvas['scrollregion'] = canvas.bbox('all')

    canvas.bind('<Configure>', canvas_reflow)
Пример #36
0
def make_pane(tool_frame):
    """Create the compiler options pane.

    """
    global window
    window = SubPane(
        TK_ROOT,
        options=GEN_OPTS,
        title='Compile Opt',
        name='compiler',
        resize_x=True,
        resize_y=False,
        tool_frame=tool_frame,
        tool_img=png.png('icons/win_compiler'),
        tool_col=4,
    )
    window.columnconfigure(0, weight=1)

    thumb_frame = ttk.LabelFrame(
        window,
        text='Thumbnail',
        labelanchor=N,
    )
    thumb_frame.grid(row=0, column=0, sticky=EW)
    thumb_frame.columnconfigure(0, weight=1)

    UI['thumb_auto'] = ttk.Radiobutton(
        thumb_frame,
        text='Auto',
        value='AUTO',
        variable=chosen_thumb,
        command=set_screen_type,
    )

    UI['thumb_peti'] = ttk.Radiobutton(
        thumb_frame,
        text='PeTI',
        value='PETI',
        variable=chosen_thumb,
        command=set_screen_type,
    )

    UI['thumb_custom'] = ttk.Radiobutton(
        thumb_frame,
        text='Custom:',
        value='CUST',
        variable=chosen_thumb,
        command=set_screen_type,
    )

    UI['thumb_label'] = ttk.Label(
        thumb_frame,
        anchor=CENTER,
        cursor=utils.CURSORS['link'],
    )
    UI['thumb_label'].bind(
        utils.EVENTS['LEFT'],
        find_screenshot,
    )

    UI['thumb_cleanup'] = ttk.Checkbutton(
        thumb_frame,
        text='Cleanup old screenshots',
        variable=cleanup_screenshot,
        command=set_screenshot_cleanup,
    )

    UI['thumb_auto'].grid(row=0, column=0, sticky='W')
    UI['thumb_peti'].grid(row=0, column=1, sticky='W')
    UI['thumb_custom'].grid(row=1, column=0, columnspan=2, sticky='NEW')
    UI['thumb_cleanup'].grid(row=3, columnspan=2, sticky='W')
    add_tooltip(
        UI['thumb_auto'],
        "Override the map image to use a screenshot automatically taken"
        "from the beginning of a chamber. Press F5 to take a new "
        "screenshot. If the map has not been previewed recently "
        "(within the last few hours), the default PeTI screenshot "
        "will be used instead.")
    add_tooltip(UI['thumb_peti'],
                "Use the normal editor view for the map preview image.")
    custom_tooltip = (
        "Use a custom image for the map preview image. Click the "
        "screenshot to select.\n"
        "Images will be converted to JPEGs if needed.")
    add_tooltip(
        UI['thumb_custom'],
        custom_tooltip,
    )

    add_tooltip(UI['thumb_label'], custom_tooltip)

    add_tooltip(
        UI['thumb_cleanup'],
        'Automatically delete unused Automatic screenshots. '
        'Disable if you want to keep things in "portal2/screenshots". ')

    if chosen_thumb.get() == 'CUST':
        # Show this if the user has set it before
        UI['thumb_label'].grid(row=2, column=0, columnspan=2, sticky='EW')
    set_screenshot()  # Load the last saved screenshot

    vrad_frame = ttk.LabelFrame(
        window,
        text='Lighting:',
        labelanchor=N,
    )
    vrad_frame.grid(row=1, column=0, sticky=EW)

    UI['light_fast'] = ttk.Radiobutton(
        vrad_frame,
        text='Fast',
        value=0,
        variable=vrad_light_type,
        command=set_vrad_type,
    )
    UI['light_fast'].grid(row=0, column=0)
    UI['light_full'] = ttk.Radiobutton(
        vrad_frame,
        text='Full',
        value=1,
        variable=vrad_light_type,
        command=set_vrad_type,
    )
    UI['light_full'].grid(row=0, column=1)

    add_tooltip(
        UI['light_fast'],
        "Compile with lower-quality, fast lighting. This speeds "
        "up compile times, but does not appear as good. Some "
        "shadows may appear wrong.\n"
        "When publishing, this is ignored.")
    add_tooltip(
        UI['light_full'],
        "Compile with high-quality lighting. This looks correct, "
        "but takes longer to compute. Use if you're arranging lights."
        "When publishing, this is always used.")

    elev_frame = ttk.LabelFrame(
        window,
        text='Spawn at:',
        labelanchor=N,
    )

    elev_frame.grid(row=2, column=0, sticky=EW)
    elev_frame.columnconfigure(0, weight=1)
    elev_frame.columnconfigure(1, weight=1)

    UI['elev_preview'] = ttk.Radiobutton(
        elev_frame,
        text='Entry Door',
        value=0,
        variable=start_in_elev,
        command=set_elev_type,
    )

    UI['elev_elevator'] = ttk.Radiobutton(
        elev_frame,
        text='Elevator',
        value=1,
        variable=start_in_elev,
        command=set_elev_type,
    )

    UI['elev_preview'].grid(row=0, column=0, sticky=W)
    UI['elev_elevator'].grid(row=0, column=1, sticky=W)

    add_tooltip(
        UI['elev_preview'],
        "When previewing in SP, spawn inside the entry elevator. "
        "This also disables the map restarts when you reach the "
        "exit door. Use this to examine the entry and exit corridors.")
    add_tooltip(
        UI['elev_elevator'],
        "When previewing in SP, spawn just before the entry door. "
        "When you reach the exit door, the map will restart.")

    corr_frame = ttk.LabelFrame(
        window,
        text='Corridor:',
        labelanchor=N,
    )
    corr_frame.grid(row=3, column=0, sticky=EW)
    corr_frame.columnconfigure(0, weight=1)
    corr_frame.columnconfigure(1, weight=1)

    UI['corr_sp_entry'] = make_corr_combo(
        corr_frame,
        'sp_entry',
        width=9,
    )

    UI['corr_sp_exit'] = make_corr_combo(
        corr_frame,
        'sp_exit',
        width=9,
    )

    UI['corr_coop'] = make_corr_combo(
        corr_frame,
        'coop',
        width=9,
    )

    UI['corr_sp_entry'].grid(row=1, column=0, sticky=EW)
    UI['corr_sp_exit'].grid(row=1, column=1, sticky=EW)
    UI['corr_coop'].grid(row=2, column=1, sticky=EW)
    ttk.Label(
        corr_frame,
        text='SP Entry:',
        anchor=CENTER,
    ).grid(row=0, column=0, sticky=EW)
    ttk.Label(
        corr_frame,
        text='SP Exit:',
        anchor=CENTER,
    ).grid(row=0, column=1, sticky=EW)
    ttk.Label(
        corr_frame,
        text='Coop:',
        anchor=CENTER,
    ).grid(row=2, column=0, sticky=EW)

    model_frame = ttk.LabelFrame(
        window,
        text='Player Model (SP):',
        labelanchor=N,
    )
    model_frame.grid(row=4, column=0, sticky=EW)
    UI['player_mdl'] = ttk.Combobox(
        model_frame,
        exportselection=0,
        textvariable=player_model_var,
        values=PLAYER_MODEL_ORDER,
        width=20,
    )
    # Users can only use the dropdown
    UI['player_mdl'].state(['readonly'])
    UI['player_mdl'].grid(row=0, column=0, sticky=EW)

    UI['player_mdl'].bind('<<ComboboxSelected>>', set_model)
    model_frame.columnconfigure(0, weight=1)

    count_frame = ttk.LabelFrame(
        window,
        text='Last Compile:',
        labelanchor=N,
    )

    count_frame.grid(row=5, column=0, sticky=EW)
    count_frame.columnconfigure(0, weight=1)
    count_frame.columnconfigure(2, weight=1)

    ttk.Label(
        count_frame,
        text='Entity',
        anchor=N,
    ).grid(row=0, column=0, columnspan=3, sticky=EW)

    UI['count_ent'] = ttk.Progressbar(
        count_frame,
        maximum=MAX_ENTS,
        variable=count_ents,
        length=120,
    )
    UI['count_ent'].grid(
        row=1,
        column=0,
        columnspan=3,
        sticky=EW,
        padx=5,
    )

    ttk.Label(
        count_frame,
        text='Overlay',
        anchor=CENTER,
    ).grid(row=2, column=0, sticky=EW)
    UI['count_over'] = ttk.Progressbar(
        count_frame,
        maximum=MAX_OVERLAY,
        variable=count_overlay,
        length=50,
    )
    UI['count_over'].grid(row=3, column=0, sticky=EW, padx=5)

    ttk.Button(
        count_frame,
        image=png.png('icons/tool_sub'),
        command=refresh_counts,
    ).grid(row=3, column=1)

    ttk.Label(
        count_frame,
        text='Brush',
        anchor=CENTER,
    ).grid(row=2, column=2, sticky=EW)
    UI['count_brush'] = ttk.Progressbar(
        count_frame,
        maximum=MAX_BRUSH,
        variable=count_brush,
        length=50,
    )
    UI['count_brush'].grid(row=3, column=2, sticky=EW, padx=5)

    UI['view_logs'] = ttk.Button(
        count_frame,
        text='View Logs',
    )
    UI['view_logs'].grid(row=4, column=0, columnspan=3, sticky=EW)

    refresh_counts(reload=False)
Пример #37
0
    def __init__(
            self,
            tk,
            lst,
            has_none=True,
            has_def=True,
            has_snd_sample=False,
            none_desc=(('line', 'Do not add anything.'),),
            none_attrs: dict=utils.EmptyMapping,
            title='BEE2',
            desc='',
            readonly_desc='',
            callback: Callable[..., None]=None,
            callback_params=(),
            attributes=(),
    ):
        """Create a window object.

        Read from .selected_id to get the currently-chosen Item name, or None
        if the <none> Item is selected.
        Args:
        - tk: Must be a Toplevel window, either the tk() root or another
        window if needed.
        - lst: A list of Item objects, defining the visible items.
        - If has_none is True, a <none> item will be added to the beginning
          of the list.
        - If has_def is True, the 'Reset to Default' button will appear,
          which resets to the suggested item.
        - If has_snd_sample is True, a '>' button will appear next to names
          to play the associated audio sample for the item.
        - none_desc holds an optional description for the <none> Item,
          which can be used to describe what it results in.
        - title is the title of the selector window.
        - callback is a function to be called whenever the selected item
         changes.
        - callback_params is a list of additional values which will be
          passed to the callback function.
          The first arguement to the callback is always the selected item ID.
        - full_context controls if the short or long names are used for the
          context menu.
        - attributes is a list of AttrDef tuples.
          Each tuple should contain an ID, display text, and default value.
          If the values are True or False a check/cross will be displayed,
          otherwise they're a string.
        - desc is descriptive text to display on the window, and in the widget
          tooltip.
        - readonly_desc will be displayed on the widget tooltip when readonly.
        """
        self.noneItem = Item(
            'NONE',
            '',
            desc=none_desc,
            attributes=dict(none_attrs),
        )
        self.noneItem.icon = img.png('BEE2/none_96')

        # The textbox on the parent window.
        self.display = None  # type: tk_tools.ReadOnlyEntry

        # Variable associated with self.display.
        self.disp_label = StringVar()

        # The '...' button to open our window.
        self.disp_btn = None  # type: ttk.Button

        # ID of the currently chosen item
        self.chosen_id = None

        # Callback function, and positional arugments to pass
        if callback is not None:
            self.callback = callback
            self.callback_params = list(callback_params)
        else:
            self.callback = None
            self.callback_params = ()

        # Item object for the currently suggested item.
        self.suggested = None

        # Should we have the 'reset to default' button?
        self.has_def = has_def
        self.description = desc
        self.readonly_description = readonly_desc

        if has_none:
            self.item_list = [self.noneItem] + lst
        else:
            self.item_list = lst
        self.selected = self.item_list[0]  # type: Item
        self.orig_selected = self.selected
        self.parent = tk
        self._readonly = False

        self.win = Toplevel(tk)
        self.win.withdraw()
        self.win.title("BEE2 - " + title)
        self.win.transient(master=tk)

        # Allow resizing in X and Y.
        self.win.resizable(True, True)

        self.win.iconbitmap('../BEE2.ico')

        # Run our quit command when the exit button is pressed, or Escape
        # on the keyboard.
        self.win.protocol("WM_DELETE_WINDOW", self.exit)
        self.win.bind("<Escape>", self.exit)

        # Allow navigating with arrow keys.
        self.win.bind("<KeyPress>", self.key_navigate)

        # A map from group name -> header widget
        self.group_widgets = {}
        # A map from folded name -> display name
        self.group_names = {}
        self.grouped_items = defaultdict(list)
        # A list of folded group names in the display order.
        self.group_order = []

        # The maximum number of items that fits per row (set in flow_items)
        self.item_width = 1

        if desc:
            self.desc_label = ttk.Label(
                self.win,
                text=desc,
                justify=LEFT,
                anchor=W,
                width=5,  # Keep a small width, so this doesn't affect the
                # initial window size.
            )
            self.desc_label.grid(row=0, column=0, sticky='EW')

        # PanedWindow allows resizing the two areas independently.
        self.pane_win = PanedWindow(
            self.win,
            orient=HORIZONTAL,
            sashpad=2,  # Padding above/below panes
            sashwidth=3,  # Width of border
            sashrelief=RAISED,  # Raise the border between panes
        )
        self.pane_win.grid(row=1, column=0, sticky="NSEW")
        self.win.columnconfigure(0, weight=1)
        self.win.rowconfigure(1, weight=1)

        self.wid = {}
        shim = ttk.Frame(self.pane_win, relief="sunken")
        shim.rowconfigure(0, weight=1)
        shim.columnconfigure(0, weight=1)

        # We need to use a canvas to allow scrolling.
        self.wid_canvas = Canvas(shim, highlightthickness=0)
        self.wid_canvas.grid(row=0, column=0, sticky="NSEW")

        # Add another frame inside to place labels on.
        self.pal_frame = ttk.Frame(self.wid_canvas)
        self.wid_canvas.create_window(1, 1, window=self.pal_frame, anchor="nw")

        self.wid_scroll = tk_tools.HidingScroll(
            shim,
            orient=VERTICAL,
            command=self.wid_canvas.yview,
        )
        self.wid_scroll.grid(row=0, column=1, sticky="NS")
        self.wid_canvas['yscrollcommand'] = self.wid_scroll.set

        utils.add_mousewheel(self.wid_canvas, self.win)

        if utils.MAC:
            # Labelframe doesn't look good here on OSX
            self.sugg_lbl = ttk.Label(
                self.pal_frame,
                # Draw lines with box drawing characters
                text="\u250E\u2500Suggested\u2500\u2512"
            )
        else:
            self.sugg_lbl = ttk.LabelFrame(
                self.pal_frame,
                text="Suggested",
                labelanchor=N,
                height=50,
            )

        # Holds all the widgets which provide info for the current item.
        self.prop_frm = ttk.Frame(self.pane_win, borderwidth=4, relief='raised')
        self.prop_frm.columnconfigure(1, weight=1)

        # Border around the selected item icon.
        self.prop_icon_frm = ttk.Frame(
            self.prop_frm,
            borderwidth=4,
            relief='raised',
            width=ICON_SIZE,
            height=ICON_SIZE,
        )
        self.prop_icon_frm.grid(row=0, column=0, columnspan=4)

        self.prop_icon = ttk.Label(self.prop_icon_frm)
        self.prop_icon.img = img.png('BEE2/blank_96')
        self.prop_icon['image'] = self.prop_icon.img
        self.prop_icon.grid(row=0, column=0)

        name_frame = ttk.Frame(self.prop_frm)

        self.prop_name = ttk.Label(
            name_frame,
            text="Item",
            justify=CENTER,
            font=("Helvetica", 12, "bold"),
        )
        name_frame.grid(row=1, column=0, columnspan=4)
        name_frame.columnconfigure(0, weight=1)
        self.prop_name.grid(row=0, column=0)

        # For music items, add a '>' button to play sound samples
        if has_snd_sample and sound.initiallised:
            self.samp_button = samp_button = ttk.Button(
                name_frame,
                text=BTN_PLAY,
                width=1,
            )
            samp_button.grid(row=0, column=1)
            add_tooltip(
                samp_button,
                "Play a sample of this item.",
            )

            def set_samp_play():
                samp_button['text'] = BTN_PLAY

            def set_samp_stop():
                samp_button['text'] = BTN_STOP

            self.sampler = sound.SamplePlayer(
                stop_callback=set_samp_play,
                start_callback=set_samp_stop,
            )
            samp_button['command'] = self.sampler.play_sample
            utils.bind_leftclick(self.prop_icon, self.sampler.play_sample)
            samp_button.state(('disabled',))
        else:
            self.sampler = None

        self.prop_author = ttk.Label(self.prop_frm, text="Author")
        self.prop_author.grid(row=2, column=0, columnspan=4)

        self.prop_desc_frm = ttk.Frame(self.prop_frm, relief="sunken")
        self.prop_desc_frm.grid(row=4, column=0, columnspan=4, sticky="NSEW")
        self.prop_desc_frm.rowconfigure(0, weight=1)
        self.prop_desc_frm.columnconfigure(0, weight=1)
        self.prop_frm.rowconfigure(4, weight=1)

        self.prop_desc = tkRichText(
            self.prop_desc_frm,
            width=40,
            height=4,
            font="TkSmallCaptionFont",
        )
        self.prop_desc.grid(
            row=0,
            column=0,
            padx=(2, 0),
            pady=2,
            sticky='NSEW',
        )

        self.prop_scroll = tk_tools.HidingScroll(
            self.prop_desc_frm,
            orient=VERTICAL,
            command=self.prop_desc.yview,
        )
        self.prop_scroll.grid(
            row=0,
            column=1,
            sticky="NS",
            padx=(0, 2),
            pady=2,
        )
        self.prop_desc['yscrollcommand'] = self.prop_scroll.set

        ttk.Button(
            self.prop_frm,
            text="OK",
            command=self.save,
        ).grid(
            row=6,
            column=0,
            padx=(8, 8),
            )

        if self.has_def:
            self.prop_reset = ttk.Button(
                self.prop_frm,
                text="Reset to Default",
                command=self.sel_suggested,
            )
            self.prop_reset.grid(
                row=6,
                column=1,
                sticky='EW',
            )

        ttk.Button(
            self.prop_frm,
            text="Cancel",
            command=self.exit,
        ).grid(
            row=6,
            column=2,
            padx=(8, 8),
        )

        self.win.option_add('*tearOff', False)
        self.context_menu = Menu(self.win)

        self.norm_font = tk_font.nametofont('TkMenuFont')

        # Make a font for showing suggested items in the context menu
        self.sugg_font = self.norm_font.copy()
        self.sugg_font['weight'] = tk_font.BOLD

        # Make a font for previewing the suggested item
        self.mouseover_font = self.norm_font.copy()
        self.mouseover_font['slant'] = tk_font.ITALIC
        self.context_var = IntVar()

        # The headers for the context menu
        self.context_menus = {}

        # Sort alphabetically, prefering a sort key if present.
        self.item_list.sort(key=lambda it: it.sort_key or it.longName)

        for ind, item in enumerate(self.item_list):  # type: int, Item
            if item == self.noneItem:
                item.button = ttk.Button(
                    self.pal_frame,
                    image=item.icon,
                )
                item.context_lbl = '<None>'
            else:
                item.button = ttk.Button(
                    self.pal_frame,
                    text=item.shortName,
                    image=item.icon,
                    compound='top',
                )

            group_key = item.group.casefold()
            self.grouped_items[group_key].append(item)

            if group_key not in self.group_names:
                # If the item is groupless, use 'Other' for the header.
                self.group_names[group_key] = item.group or 'Other'

            if not item.group:
                # Ungrouped items appear directly in the menu.
                menu = self.context_menu
            else:
                try:
                    menu = self.context_menus[group_key]
                except KeyError:
                    self.context_menus[group_key] = menu = Menu(
                        self.context_menu,
                    )

            menu.add_radiobutton(
                label=item.context_lbl,
                command=functools.partial(self.sel_item_id, item.name),
                var=self.context_var,
                value=ind,
            )

            item.win = self.win
            utils.bind_leftclick(
                item.button,
                functools.partial(self.sel_item, item),
            )
            utils.bind_leftclick_double(
                item.button,
                self.save,
            )

        # Convert to a normal dictionary, after adding all items.
        self.grouped_items = dict(self.grouped_items)

        # Figure out the order for the groups - alphabetical.
        # Note - empty string should sort to the beginning!
        self.group_order[:] = sorted(self.grouped_items.keys())

        for index, (key, menu) in enumerate(
                sorted(self.context_menus.items(), key=itemgetter(0)),
                # We start with the ungrouped items, so increase the index
                # appropriately.
                start=len(self.grouped_items.get('', ()))):
            self.context_menu.add_cascade(
                menu=menu,
                label=self.group_names[key],
            )
            # Set a custom attribute to keep track of the menu's index.
            menu.index = index

        for group_key, text in self.group_names.items():
            self.group_widgets[group_key] = GroupHeader(
                self,
                text,
            )
            self.group_widgets[group_key].should_show = True

        self.flow_items(None)
        self.wid_canvas.bind("<Configure>", self.flow_items)

        self.pane_win.add(shim)
        self.pane_win.add(self.prop_frm)

        # Force a minimum size for the two parts
        self.pane_win.paneconfigure(shim, minsize=100, stretch='always')
        self.prop_frm.update_idletasks()  # Update reqwidth()
        self.pane_win.paneconfigure(
            self.prop_frm,
            minsize=200,
            stretch='never',
        )

        if attributes:
            attr_frame = ttk.Frame(self.prop_frm)
            attr_frame.grid(
                row=5,
                column=0,
                columnspan=3,
                sticky=EW,
            )

            self.attr = {}
            # Add in all the attribute labels
            for index, attr in enumerate(attributes):
                desc_label = ttk.Label(
                    attr_frame,
                    text=attr.desc,
                )
                self.attr[attr.id] = val_label = ttk.Label(
                    attr_frame,
                )
                val_label.default = attr.default
                val_label.type = attr.type
                if attr.type is AttrTypes.BOOL:
                    # It's a tick/cross label
                    val_label['image'] = (
                        ICON_CHECK
                        if attr.default else
                        ICON_CROSS,
                    )
                elif attr.type is AttrTypes.COLOR:
                    # A small colour swatch.
                    val_label.configure(
                        relief=RAISED,
                    )
                    # Show the color value when hovered.
                    add_tooltip(val_label)

                # Position in a 2-wide grid
                desc_label.grid(
                    row=index // 2,
                    column=(index % 2) * 2,
                    sticky=E,
                )
                val_label.grid(
                    row=index // 2,
                    column=(index % 2) * 2 + 1,
                    sticky=W,
                )
        else:
            self.attr = None
Пример #38
0
def init_widgets():
    """Initiallise all the window components."""
    global prop_window
    prop_window = Toplevel(TK_ROOT)
    prop_window.overrideredirect(1)
    prop_window.resizable(False, False)
    prop_window.transient(master=TK_ROOT)
    prop_window.attributes('-topmost', 1)
    prop_window.withdraw()  # starts hidden

    f = ttk.Frame(prop_window, relief="raised", borderwidth="4")
    f.grid(row=0, column=0)

    ttk.Label(
        f,
        text="Properties:",
        anchor="center",
    ).grid(
        row=0,
        column=0,
        columnspan=3,
        sticky="EW",
    )

    wid['name'] = ttk.Label(f, text="", anchor="center")
    wid['name'].grid(row=1, column=0, columnspan=3, sticky="EW")

    wid['ent_count'] = ttk.Label(
        f,
        text="",
        anchor="e",
        compound="left",
        image=png.spr('gear_ent'),
    )
    wid['ent_count'].grid(row=0, column=2, rowspan=2, sticky=E)
    tooltip.add_tooltip(
        wid['ent_count'],
        'The number of entities used for this item. The Source engine limits '
        'this to 2048 in total. This provides a guide to how many of these '
        'items can be placed in a map at once.'
    )

    wid['author'] = ttk.Label(f, text="", anchor="center", relief="sunken")
    wid['author'].grid(row=2, column=0, columnspan=3, sticky="EW")

    sub_frame = ttk.Frame(f, borderwidth=4, relief="sunken")
    sub_frame.grid(column=0, columnspan=3, row=3)
    for i in range(5):
        wid['subitem', i] = ttk.Label(
            sub_frame,
            image=png.png('BEE2/alpha_64'),
        )
        wid['subitem', i].grid(row=0, column=i)
        utils.bind_leftclick(
            wid['subitem', i],
            functools.partial(sub_sel, i),
        )
        utils.bind_rightclick(
            wid['subitem', i],
            functools.partial(sub_open, i),
        )

    wid['wip_dep'] = ttk.Label(f, text='', anchor="nw")
    wid['wip_dep'].grid(row=4, column=0, sticky="NW")

    ttk.Label(f, text="Description:", anchor="sw").grid(
        row=4,
        column=0,
        sticky="SW",
    )

    spr_frame = ttk.Frame(f, borderwidth=4, relief="sunken")
    spr_frame.grid(column=1, columnspan=2, row=4, sticky=W)
    # sprites: inputs, outputs, rotation handle, occupied/embed state,
    # desiredFacing
    for spr_id in SPR:
        wid['sprite', spr_id] = sprite = ttk.Label(
            spr_frame,
            image=png.spr('ap_grey'),
            relief="raised",
        )
        sprite.grid(row=0, column=spr_id.value)
        tooltip.add_tooltip(sprite)

    desc_frame = ttk.Frame(f, borderwidth=4, relief="sunken")
    desc_frame.grid(row=5, column=0, columnspan=3, sticky="EW")
    desc_frame.columnconfigure(0, weight=1)

    wid['desc'] = tkRichText(desc_frame, width=40, height=8)
    wid['desc'].grid(row=0, column=0, sticky="EW")

    desc_scroll = tk_tools.HidingScroll(
        desc_frame,
        orient=VERTICAL,
        command=wid['desc'].yview,
        )
    wid['desc']['yscrollcommand'] = desc_scroll.set
    desc_scroll.grid(row=0, column=1, sticky="NS")

    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)

    wid['moreinfo'] = ttk.Button(f, text="More Info>>", command=show_more_info)
    wid['moreinfo'].grid(row=6, column=2, sticky=E)
    tooltip.add_tooltip(wid['moreinfo'])

    menu_info = Menu(wid['moreinfo'])
    menu_info.add_command(label='', state='disabled')

    def show_item_props():
        snd.fx('expand')
        itemPropWin.show_window(
            selected_item.get_properties(),
            wid['changedefaults'],
            selected_sub_item.name,
        )

    wid['changedefaults'] = ttk.Button(
        f,
        text="Change Defaults...",
        command=show_item_props,
        )
    wid['changedefaults'].grid(row=6, column=1)
    tooltip.add_tooltip(
        wid['changedefaults'],
        'Change the default settings for this item when placed.'
    )

    wid['variant'] = ttk.Combobox(
        f,
        values=['VERSION'],
        exportselection=0,
        # On Mac this defaults to being way too wide!
        width=7 if utils.MAC else None,
    )
    wid['variant'].state(['readonly'])  # Prevent directly typing in values
    wid['variant'].bind('<<ComboboxSelected>>', set_item_version)
    wid['variant'].current(0)
    wid['variant'].grid(row=6, column=0, sticky=W)

    itemPropWin.init(hide_item_props)
Пример #39
0
def make_pane(parent: ttk.Frame):
    """Create all the widgets we use."""
    if not CONFIG_ORDER:
        # No configs at all...
        ttk.Label(parent, text=_('No Item Configuration!')).pack(fill='both')
        return

    CONFIG_ORDER.sort(key=lambda grp: grp.name)

    parent.columnconfigure(0, weight=1)

    # Need to use a canvas to allow scrolling
    canvas = tk.Canvas(parent, highlightthickness=0)
    canvas.grid(row=0, column=0, sticky='NSEW')
    parent.rowconfigure(0, weight=1)

    scrollbar = ttk.Scrollbar(
        parent,
        orient='vertical',
        command=canvas.yview,
    )
    scrollbar.grid(column=1, row=0, sticky="ns")
    canvas['yscrollcommand'] = scrollbar.set

    utils.add_mousewheel(canvas, canvas, parent)
    canvas_frame = ttk.Frame(canvas)
    canvas.create_window(0, 0, window=canvas_frame, anchor="nw")
    canvas_frame.rowconfigure(0, weight=1)

    for conf_row, config in enumerate(CONFIG_ORDER):
        frame = ttk.LabelFrame(canvas_frame, text=config.name)
        frame.columnconfigure(0, weight=1)
        frame.grid(row=conf_row, column=0, sticky='nsew')

        row = 0

        widget_count = len(config.widgets) + len(config.multi_widgets)

        # Now make the widgets.
        if config.widgets:
            for row, wid in enumerate(config.widgets):
                wid_frame = ttk.Frame(frame)
                wid_frame.grid(row=row, column=0, sticky='ew')
                wid_frame.columnconfigure(1, weight=1)

                label = ttk.Label(wid_frame, text=wid.name + ': ')
                label.grid(row=0, column=0)
                widget = wid.create_func(wid_frame, wid.values, wid.config)
                widget.grid(row=0, column=1, sticky='e')

                if wid.tooltip:
                    add_tooltip(widget, wid.tooltip)
                    add_tooltip(label, wid.tooltip)

        if config.widgets and config.multi_widgets:
            ttk.Separator(orient='horizontal').grid(
                row=1,
                column=0,
                sticky='ew',
            )

        # Skip if no timer widgets
        if not config.multi_widgets:
            continue

        # Continue from wherever we were.
        for row, wid in enumerate(config.multi_widgets, start=row + 1):
            # If we only have 1 widget, don't add a redundant title.
            if widget_count == 1:
                wid_frame = ttk.Frame(frame)
            else:
                wid_frame = ttk.LabelFrame(frame, text=wid.name)

            wid_frame.grid(row=row, column=0, sticky='ew')
            wid.multi_func(
                wid_frame,
                wid.values,
                wid.config,
            )

            if wid.tooltip:
                add_tooltip(wid_frame, wid.tooltip)

    canvas.update_idletasks()
    canvas.config(
        scrollregion=canvas.bbox('ALL'),
        width=canvas_frame.winfo_reqwidth(),
    )

    def canvas_reflow(e):
        canvas['scrollregion'] = canvas.bbox('all')

    canvas.bind('<Configure>', canvas_reflow)
Пример #40
0
def make_pane(tool_frame: Frame, menu_bar: Menu):
    """Create the styleVar pane.

    """
    global window
    window = SubPane(
        TK_ROOT,
        title=_('Style/Item Properties'),
        name='style',
        menu_bar=menu_bar,
        resize_y=True,
        tool_frame=tool_frame,
        tool_img=img.png('icons/win_stylevar'),
        tool_col=3,
    )

    UI['nbook'] = nbook = ttk.Notebook(window)

    nbook.grid(row=0, column=0, sticky=NSEW)
    window.rowconfigure(0, weight=1)
    window.columnconfigure(0, weight=1)
    nbook.enable_traversal()

    stylevar_frame = ttk.Frame(nbook)
    stylevar_frame.rowconfigure(0, weight=1)
    stylevar_frame.columnconfigure(0, weight=1)
    nbook.add(stylevar_frame, text=_('Styles'))

    UI['style_can'] = Canvas(stylevar_frame, highlightthickness=0)
    # need to use a canvas to allow scrolling
    UI['style_can'].grid(sticky='NSEW')
    window.rowconfigure(0, weight=1)

    UI['style_scroll'] = ttk.Scrollbar(
        stylevar_frame,
        orient=VERTICAL,
        command=UI['style_can'].yview,
    )
    UI['style_scroll'].grid(column=1, row=0, rowspan=2, sticky="NS")
    UI['style_can']['yscrollcommand'] = UI['style_scroll'].set

    utils.add_mousewheel(UI['style_can'], stylevar_frame)

    canvas_frame = ttk.Frame(UI['style_can'])

    frame_all = ttk.Labelframe(canvas_frame, text=_("All:"))
    frame_all.grid(row=0, sticky='EW')

    frm_chosen = ttk.Labelframe(canvas_frame, text=_("Selected Style:"))
    frm_chosen.grid(row=1, sticky='EW')

    ttk.Separator(
        canvas_frame,
        orient=HORIZONTAL,
    ).grid(row=2, sticky='EW', pady=(10, 5))

    frm_other = ttk.Labelframe(canvas_frame, text=_("Other Styles:"))
    frm_other.grid(row=3, sticky='EW')

    UI['stylevar_chosen_none'] = ttk.Label(
        frm_chosen,
        text=_('No Options!'),
        font='TkMenuFont',
        justify='center',
    )
    UI['stylevar_other_none'] = ttk.Label(
        frm_other,
        text=_('None!'),
        font='TkMenuFont',
        justify='center',
    )

    all_pos = 0
    for all_pos, var in enumerate(styleOptions):
        # Add the special stylevars which apply to all styles
        tk_vars[var.id] = int_var = IntVar(value=var.default)
        checkbox_all[var.id] = ttk.Checkbutton(
            frame_all,
            variable=int_var,
            text=var.name,
        )
        checkbox_all[var.id].grid(row=all_pos, column=0, sticky="W", padx=3)

        # Special case - this needs to refresh the filter when swapping,
        # so the items disappear or reappear.
        if var.id == 'UnlockDefault':

            def cmd():
                update_filter()

            checkbox_all[var.id]['command'] = cmd

        tooltip.add_tooltip(
            checkbox_all[var.id],
            make_desc(var, is_hardcoded=True),
        )

    for var in VAR_LIST:
        tk_vars[var.id] = IntVar(value=var.enabled)
        args = {
            'variable': tk_vars[var.id],
            'text': var.name,
        }
        desc = make_desc(var)
        if var.applies_to_all():
            # Available in all styles - put with the hardcoded variables.
            all_pos += 1

            checkbox_all[var.id] = check = ttk.Checkbutton(frame_all, **args)
            check.grid(row=all_pos, column=0, sticky="W", padx=3)
            tooltip.add_tooltip(check, desc)
        else:
            # Swap between checkboxes depending on style.
            checkbox_chosen[var.id] = ttk.Checkbutton(frm_chosen, **args)
            checkbox_other[var.id] = ttk.Checkbutton(frm_other, **args)
            tooltip.add_tooltip(
                checkbox_chosen[var.id],
                desc,
            )
            tooltip.add_tooltip(
                checkbox_other[var.id],
                desc,
            )

    UI['style_can'].create_window(0, 0, window=canvas_frame, anchor="nw")
    UI['style_can'].update_idletasks()
    UI['style_can'].config(
        scrollregion=UI['style_can'].bbox(ALL),
        width=canvas_frame.winfo_reqwidth(),
    )

    if utils.USE_SIZEGRIP:
        ttk.Sizegrip(
            window,
            cursor=utils.CURSORS['stretch_vert'],
        ).grid(row=1, column=0)

    UI['style_can'].bind('<Configure>', flow_stylevar)

    item_config_frame = ttk.Frame(nbook)
    nbook.add(item_config_frame, text=_('Items'))
    itemconfig.make_pane(item_config_frame)
Пример #41
0
def make_pane(tool_frame):
    """Create the styleVar pane.

    """
    global window
    window = SubPane(
        TK_ROOT,
        options=GEN_OPTS,
        title='Style Properties',
        name='style',
        resize_y=True,
        tool_frame=tool_frame,
        tool_img=png.png('icons/win_stylevar'),
        tool_col=3,
    )

    UI['style_can'] = Canvas(window, highlightthickness=0)
    # need to use a canvas to allow scrolling
    UI['style_can'].grid(sticky='NSEW')
    window.rowconfigure(0, weight=1)

    UI['style_scroll'] = ttk.Scrollbar(
        window,
        orient=VERTICAL,
        command=UI['style_can'].yview,
    )
    UI['style_scroll'].grid(column=1, row=0, rowspan=2, sticky="NS")
    UI['style_can']['yscrollcommand'] = UI['style_scroll'].set
    canvas_frame = ttk.Frame(UI['style_can'])

    frame_all = ttk.Labelframe(canvas_frame, text="All:")
    frame_all.grid(row=0, sticky='EW')

    frm_chosen = ttk.Labelframe(canvas_frame, text="Selected Style:")
    frm_chosen.grid(row=1, sticky='EW')

    ttk.Separator(
        canvas_frame,
        orient=HORIZONTAL,
    ).grid(row=2, sticky='EW', pady=(10, 5))

    frm_other = ttk.Labelframe(canvas_frame, text="Other Styles:")
    frm_other.grid(row=3, sticky='EW')

    UI['stylevar_chosen_none'] = ttk.Label(
        frm_chosen,
        text='No Options!',
        font='TkMenuFont',
        justify='center',
    )
    UI['stylevar_other_none'] = ttk.Label(
        frm_other,
        text='None!',
        font='TkMenuFont',
        justify='center',
    )

    for pos, var in enumerate(styleOptions):
        # Add the special stylevars which apply to all styles
        tk_vars[var.id] = IntVar(
            value=GEN_OPTS.get_bool('StyleVar', var.id, var.enabled))
        checkbox_special[var.id] = ttk.Checkbutton(frame_all,
                                                   variable=tk_vars[var.id],
                                                   text=var.name,
                                                   command=functools.partial(
                                                       set_stylevar, var.id))
        checkbox_special[var.id].grid(row=pos, column=0, sticky="W", padx=3)

        if var.desc:
            tooltip.add_tooltip(
                checkbox_special[var.id],
                var.desc,
            )

    for var in var_list:
        tk_vars[var.id] = IntVar(value=var.default)
        args = {
            'variable': tk_vars[var.id],
            'text': var.name,
            'command': functools.partial(set_stylevar, var.id)
        }
        checkbox_chosen[var.id] = ttk.Checkbutton(frm_chosen, **args)
        checkbox_other[var.id] = ttk.Checkbutton(frm_other, **args)
        if var.desc:
            tooltip.add_tooltip(
                checkbox_chosen[var.id],
                var.desc,
            )
            tooltip.add_tooltip(
                checkbox_other[var.id],
                var.desc,
            )

    UI['style_can'].create_window(0, 0, window=canvas_frame, anchor="nw")
    UI['style_can'].update_idletasks()
    UI['style_can'].config(
        scrollregion=UI['style_can'].bbox(ALL),
        width=canvas_frame.winfo_reqwidth(),
    )
    ttk.Sizegrip(
        window,
        cursor=utils.CURSORS['stretch_vert'],
    ).grid(row=1, column=0)

    UI['style_can'].bind('<Configure>', flow_stylevar)

    # Scroll globally even if canvas is not selected.
    if utils.WIN:
        window.bind(
            "<MouseWheel>",
            lambda e: scroll(int(-1 * (e.delta / 120))),
        )
    elif utils.MAC:
        window.bind(
            "<Button-4>",
            lambda e: scroll(1),
        )
        window.bind(
            "<Button-5>",
            lambda e: scroll(-1),
        )
Пример #42
0
def init_gen_tab(f):
    """Make widgets in the 'General' tab."""
    def load_after_export():
        """Read the 'After Export' radio set."""
        AFTER_EXPORT_ACTION.set(GEN_OPTS.get_int(
            'General',
            'after_export_action',
            AFTER_EXPORT_ACTION.get()
        ))

    def save_after_export():
        """Save the 'After Export' radio set."""
        GEN_OPTS['General']['after_export_action'] = str(AFTER_EXPORT_ACTION.get())

    after_export_frame = ttk.LabelFrame(
        f,
        text=_('After Export:'),
    )
    after_export_frame.grid(
        row=0,
        rowspan=2,
        column=0,
        sticky='NS',
        padx=(0, 10),
    )

    VARS['General', 'after_export_action'] = AFTER_EXPORT_ACTION
    AFTER_EXPORT_ACTION.load = load_after_export
    AFTER_EXPORT_ACTION.save = save_after_export
    load_after_export()

    exp_nothing = ttk.Radiobutton(
        after_export_frame,
        text=_('Do Nothing'),
        variable=AFTER_EXPORT_ACTION,
        value=AfterExport.NORMAL.value,
    )
    exp_minimise = ttk.Radiobutton(
        after_export_frame,
        text=_('Minimise BEE2'),
        variable=AFTER_EXPORT_ACTION,
        value=AfterExport.MINIMISE.value,
    )
    exp_quit = ttk.Radiobutton(
        after_export_frame,
        text=_('Quit BEE2'),
        variable=AFTER_EXPORT_ACTION,
        value=AfterExport.QUIT.value,
    )
    exp_nothing.grid(row=0, column=0, sticky='w')
    exp_minimise.grid(row=1, column=0, sticky='w')
    exp_quit.grid(row=2, column=0, sticky='w')

    add_tooltip(exp_nothing, _('After exports, do nothing and '
                               'keep the BEE2 in focus.'))
    add_tooltip(exp_minimise, _('After exports, minimise to the taskbar/dock.'))
    add_tooltip(exp_minimise, _('After exports, quit the BEE2.'))

    UI['launch_game'] = launch_game = make_checkbox(
        after_export_frame,
        section='General',
        item='launch_Game',
        var=LAUNCH_AFTER_EXPORT,
        desc=_('Launch Game'),
        tooltip=_('After exporting, launch the selected game automatically.'),
    )
    launch_game.grid(row=3, column=0, sticky='W', pady=(10, 0))

    if sound.initiallised:
        UI['mute'] = mute = make_checkbox(
            f,
            section='General',
            item='play_sounds',
            desc=_('Play Sounds'),
            var=PLAY_SOUND,
        )
    else:
        UI['mute'] = mute = ttk.Checkbutton(
            f,
            text=_('Play Sounds'),
            state='disabled',
        )
        add_tooltip(
            UI['mute'],
            _('Pyglet is either not installed or broken.\n'
              'Sound effects have been disabled.')
        )
    mute.grid(row=0, column=1, sticky='E')

    UI['reset_cache'] = reset_cache = ttk.Button(
        f,
        text=_('Reset Package Caches'),
        command=clear_caches,
    )
    reset_cache.grid(row=1, column=1, sticky='EW')
    add_tooltip(
        reset_cache,
        _('Force re-extracting all package resources. This requires a restart.'),
    )
Пример #43
0
def make_pane(tool_frame):
    """Create the styleVar pane.

    """
    global window
    window = SubPane(
        TK_ROOT,
        options=GEN_OPTS,
        title=_('Style Properties'),
        name='style',
        resize_y=True,
        tool_frame=tool_frame,
        tool_img=png.png('icons/win_stylevar'),
        tool_col=3,
    )

    UI['style_can'] = Canvas(window, highlightthickness=0)
    # need to use a canvas to allow scrolling
    UI['style_can'].grid(sticky='NSEW')
    window.rowconfigure(0, weight=1)

    UI['style_scroll'] = ttk.Scrollbar(
        window,
        orient=VERTICAL,
        command=UI['style_can'].yview,
    )
    UI['style_scroll'].grid(column=1, row=0, rowspan=2, sticky="NS")
    UI['style_can']['yscrollcommand'] = UI['style_scroll'].set

    utils.add_mousewheel(UI['style_can'], window)

    canvas_frame = ttk.Frame(UI['style_can'])

    frame_all = ttk.Labelframe(canvas_frame, text=_("All:"))
    frame_all.grid(row=0, sticky='EW')

    frm_chosen = ttk.Labelframe(canvas_frame, text=_("Selected Style:"))
    frm_chosen.grid(row=1, sticky='EW')

    ttk.Separator(
        canvas_frame,
        orient=HORIZONTAL,
    ).grid(row=2, sticky='EW', pady=(10, 5))

    frm_other = ttk.Labelframe(canvas_frame, text=_("Other Styles:"))
    frm_other.grid(row=3, sticky='EW')

    UI['stylevar_chosen_none'] = ttk.Label(
        frm_chosen,
        text=_('No Options!'),
        font='TkMenuFont',
        justify='center',
    )
    UI['stylevar_other_none'] = ttk.Label(
        frm_other,
        text=_('None!'),
        font='TkMenuFont',
        justify='center',
    )

    all_pos = 0
    for all_pos, var in enumerate(styleOptions):
        # Add the special stylevars which apply to all styles
        tk_vars[var.id] = IntVar(
            value=GEN_OPTS.get_bool('StyleVar', var.id, var.default))
        checkbox_all[var.id] = ttk.Checkbutton(frame_all,
                                               variable=tk_vars[var.id],
                                               text=var.name,
                                               command=functools.partial(
                                                   set_stylevar, var.id))
        checkbox_all[var.id].grid(row=all_pos, column=0, sticky="W", padx=3)

        tooltip.add_tooltip(
            checkbox_all[var.id],
            make_desc(var, is_hardcoded=True),
        )

    for var in VAR_LIST:
        tk_vars[var.id] = IntVar(value=var.enabled)
        args = {
            'variable': tk_vars[var.id],
            'text': var.name,
            'command': functools.partial(set_stylevar, var.id)
        }
        desc = make_desc(var)
        if var.applies_to_all():
            # Available in all styles - put with the hardcoded variables.
            all_pos += 1

            checkbox_all[var.id] = check = ttk.Checkbutton(frame_all, **args)
            check.grid(row=all_pos, column=0, sticky="W", padx=3)
            tooltip.add_tooltip(check, desc)
        else:
            # Swap between checkboxes depending on style.
            checkbox_chosen[var.id] = ttk.Checkbutton(frm_chosen, **args)
            checkbox_other[var.id] = ttk.Checkbutton(frm_other, **args)
            tooltip.add_tooltip(
                checkbox_chosen[var.id],
                desc,
            )
            tooltip.add_tooltip(
                checkbox_other[var.id],
                desc,
            )

    UI['style_can'].create_window(0, 0, window=canvas_frame, anchor="nw")
    UI['style_can'].update_idletasks()
    UI['style_can'].config(
        scrollregion=UI['style_can'].bbox(ALL),
        width=canvas_frame.winfo_reqwidth(),
    )

    if utils.USE_SIZEGRIP:
        ttk.Sizegrip(
            window,
            cursor=utils.CURSORS['stretch_vert'],
        ).grid(row=1, column=0)

    UI['style_can'].bind('<Configure>', flow_stylevar)
Пример #44
0
def init_gen_tab(f: ttk.Frame) -> None:
    """Make widgets in the 'General' tab."""
    def load_after_export():
        """Read the 'After Export' radio set."""
        AFTER_EXPORT_ACTION.set(GEN_OPTS.get_int(
            'General',
            'after_export_action',
            AFTER_EXPORT_ACTION.get()
        ))

    def save_after_export():
        """Save the 'After Export' radio set."""
        GEN_OPTS['General']['after_export_action'] = str(AFTER_EXPORT_ACTION.get())

    after_export_frame = ttk.LabelFrame(
        f,
        text=_('After Export:'),
    )
    after_export_frame.grid(
        row=0,
        rowspan=2,
        column=0,
        sticky='NS',
        padx=(0, 10),
    )

    VARS['General', 'after_export_action'] = AFTER_EXPORT_ACTION
    AFTER_EXPORT_ACTION.load = load_after_export
    AFTER_EXPORT_ACTION.save = save_after_export
    load_after_export()

    exp_nothing = ttk.Radiobutton(
        after_export_frame,
        text=_('Do Nothing'),
        variable=AFTER_EXPORT_ACTION,
        value=AfterExport.NORMAL.value,
    )
    exp_minimise = ttk.Radiobutton(
        after_export_frame,
        text=_('Minimise BEE2'),
        variable=AFTER_EXPORT_ACTION,
        value=AfterExport.MINIMISE.value,
    )
    exp_quit = ttk.Radiobutton(
        after_export_frame,
        text=_('Quit BEE2'),
        variable=AFTER_EXPORT_ACTION,
        value=AfterExport.QUIT.value,
    )
    exp_nothing.grid(row=0, column=0, sticky='w')
    exp_minimise.grid(row=1, column=0, sticky='w')
    exp_quit.grid(row=2, column=0, sticky='w')

    add_tooltip(exp_nothing, _('After exports, do nothing and '
                               'keep the BEE2 in focus.'))
    add_tooltip(exp_minimise, _('After exports, minimise to the taskbar/dock.'))
    add_tooltip(exp_minimise, _('After exports, quit the BEE2.'))

    UI['launch_game'] = launch_game = make_checkbox(
        after_export_frame,
        section='General',
        item='launch_Game',
        var=LAUNCH_AFTER_EXPORT,
        desc=_('Launch Game'),
        tooltip=_('After exporting, launch the selected game automatically.'),
    )
    launch_game.grid(row=3, column=0, sticky='W', pady=(10, 0))

    if sound.initiallised:
        UI['mute'] = mute = make_checkbox(
            f,
            section='General',
            item='play_sounds',
            desc=_('Play Sounds'),
            var=PLAY_SOUND,
        )
    else:
        UI['mute'] = mute = ttk.Checkbutton(
            f,
            text=_('Play Sounds'),
            state='disabled',
        )
        add_tooltip(
            UI['mute'],
            _('Pyglet is either not installed or broken.\n'
              'Sound effects have been disabled.')
        )
    mute.grid(row=0, column=1, sticky='E')

    UI['reset_cache'] = reset_cache = ttk.Button(
        f,
        text=_('Reset Package Caches'),
        command=clear_caches,
    )
    reset_cache.grid(row=1, column=1, sticky='EW')
    add_tooltip(
        reset_cache,
        _('Force re-extracting all package resources.'),
    )
Пример #45
0
def make_pane(tool_frame):
    """Create the styleVar pane.

    """
    global window
    window = SubPane(
        TK_ROOT,
        options=GEN_OPTS,
        title='Style Properties',
        name='style',
        resize_y=True,
        tool_frame=tool_frame,
        tool_img=png.png('icons/win_stylevar'),
        tool_col=3,
    )

    UI['style_can'] = Canvas(window, highlightthickness=0)
    # need to use a canvas to allow scrolling
    UI['style_can'].grid(sticky='NSEW')
    window.rowconfigure(0, weight=1)

    UI['style_scroll'] = ttk.Scrollbar(
        window,
        orient=VERTICAL,
        command=UI['style_can'].yview,
        )
    UI['style_scroll'].grid(column=1, row=0, rowspan=2, sticky="NS")
    UI['style_can']['yscrollcommand'] = UI['style_scroll'].set

    utils.add_mousewheel(UI['style_can'], window)

    canvas_frame = ttk.Frame(UI['style_can'])

    frame_all = ttk.Labelframe(canvas_frame, text="All:")
    frame_all.grid(row=0, sticky='EW')

    frm_chosen = ttk.Labelframe(canvas_frame, text="Selected Style:")
    frm_chosen.grid(row=1, sticky='EW')

    ttk.Separator(
        canvas_frame,
        orient=HORIZONTAL,
        ).grid(row=2, sticky='EW', pady=(10, 5))

    frm_other = ttk.Labelframe(canvas_frame, text="Other Styles:")
    frm_other.grid(row=3, sticky='EW')

    UI['stylevar_chosen_none'] = ttk.Label(
        frm_chosen,
        text='No Options!',
        font='TkMenuFont',
        justify='center',
        )
    UI['stylevar_other_none'] = ttk.Label(
        frm_other,
        text='None!',
        font='TkMenuFont',
        justify='center',
        )

    for pos, var in enumerate(styleOptions):
        # Add the special stylevars which apply to all styles
        tk_vars[var.id] = IntVar(
            value=GEN_OPTS.get_bool('StyleVar', var.id, var.default)
        )
        checkbox_special[var.id] = ttk.Checkbutton(
            frame_all,
            variable=tk_vars[var.id],
            text=var.name,
            command=functools.partial(set_stylevar, var.id)
            )
        checkbox_special[var.id].grid(row=pos, column=0, sticky="W", padx=3)

        tooltip.add_tooltip(
            checkbox_special[var.id],
            make_desc(var, is_hardcoded=True),
        )

    for var in VAR_LIST:
        tk_vars[var.id] = IntVar(value=var.enabled)
        args = {
            'variable': tk_vars[var.id],
            'text': var.name,
            'command': functools.partial(set_stylevar, var.id)
            }
        checkbox_chosen[var.id] = ttk.Checkbutton(frm_chosen, **args)
        checkbox_other[var.id] = ttk.Checkbutton(frm_other, **args)
        desc = make_desc(var)
        tooltip.add_tooltip(
            checkbox_chosen[var.id],
            desc,
        )
        tooltip.add_tooltip(
            checkbox_other[var.id],
            desc,
        )

    UI['style_can'].create_window(0, 0, window=canvas_frame, anchor="nw")
    UI['style_can'].update_idletasks()
    UI['style_can'].config(
        scrollregion=UI['style_can'].bbox(ALL),
        width=canvas_frame.winfo_reqwidth(),
    )

    if utils.USE_SIZEGRIP:
        ttk.Sizegrip(
            window,
            cursor=utils.CURSORS['stretch_vert'],
        ).grid(row=1, column=0)

    UI['style_can'].bind('<Configure>', flow_stylevar)
Пример #46
0
def init() -> None:
    """Initialise all widgets in the given window."""
    for cat, btn_text in [
        ('back_', _('Restore:')),
        ('game_', _('Backup:')),
    ]:
        UI[cat + 'frame'] = frame = ttk.Frame(window, )
        UI[cat + 'title_frame'] = title_frame = ttk.Frame(frame, )
        title_frame.grid(row=0, column=0, sticky='EW')
        UI[cat + 'title'] = ttk.Label(
            title_frame,
            font='TkHeadingFont',
        )
        UI[cat + 'title'].grid(row=0, column=0)
        title_frame.rowconfigure(0, weight=1)
        title_frame.columnconfigure(0, weight=1)

        UI[cat + 'details'] = CheckDetails(
            frame,
            headers=HEADERS,
        )
        UI[cat + 'details'].grid(row=1, column=0, sticky='NSEW')
        frame.rowconfigure(1, weight=1)
        frame.columnconfigure(0, weight=1)

        button_frame = ttk.Frame(frame, )
        button_frame.grid(column=0, row=2)
        ttk.Label(button_frame, text=btn_text).grid(row=0, column=0)
        UI[cat + 'btn_all'] = ttk.Button(
            button_frame,
            text='All',
            width=3,
        )
        UI[cat + 'btn_sel'] = ttk.Button(
            button_frame,
            text=_('Checked'),
            width=8,
        )
        UI[cat + 'btn_all'].grid(row=0, column=1)
        UI[cat + 'btn_sel'].grid(row=0, column=2)

        UI[cat + 'btn_del'] = ttk.Button(
            button_frame,
            text=_('Delete Checked'),
            width=14,
        )
        UI[cat + 'btn_del'].grid(row=1, column=0, columnspan=3)

        utils.add_mousewheel(
            UI[cat + 'details'].wid_canvas,
            UI[cat + 'frame'],
        )

    UI['game_refresh'] = ttk.Button(
        UI['game_title_frame'],
        image=img.png('icons/tool_sub'),
        command=ui_refresh_game,
    )
    UI['game_refresh'].grid(row=0, column=1, sticky='E')
    add_tooltip(
        UI['game_refresh'],
        "Reload the map list.",
    )

    UI['game_title']['textvariable'] = game_name
    UI['back_title']['textvariable'] = backup_name

    UI['game_btn_all']['command'] = ui_backup_all
    UI['game_btn_sel']['command'] = ui_backup_sel
    UI['game_btn_del']['command'] = ui_delete_game

    UI['back_btn_all']['command'] = ui_restore_all
    UI['back_btn_sel']['command'] = ui_restore_sel
    UI['back_btn_del']['command'] = ui_delete_backup

    UI['back_frame'].grid(row=1, column=0, sticky='NSEW')
    ttk.Separator(orient=tk.VERTICAL).grid(
        row=1,
        column=1,
        sticky='NS',
        padx=5,
    )
    UI['game_frame'].grid(row=1, column=2, sticky='NSEW')

    window.rowconfigure(1, weight=1)
    window.columnconfigure(0, weight=1)
    window.columnconfigure(2, weight=1)
Пример #47
0
def make_tab(group, config: ConfigFile, tab_type):
    """Create all the widgets for a tab."""
    if tab_type is TabTypes.MIDCHAMBER:
        # Mid-chamber voice lines have predefined values.
        group_name = _('Mid - Chamber')
        group_id = 'MIDCHAMBER'
        group_desc = _('Lines played during the actual chamber, '
                       'after specific events have occurred.')
    elif tab_type is TabTypes.RESPONSE:
        # Note: 'Response' tab header, and description
        group_name = _('Responses')
        group_id = None
        group_desc = _('Lines played in response to certain events in Coop.')
    elif tab_type is TabTypes.NORM:
        group_name = group['name', 'No Name!']
        group_id = group_name.upper()
        group_desc = group['desc', ''] + ':'
    else:
        raise ValueError('Invalid tab type!')

    # This is just to hold the canvas and scrollbar
    outer_frame = ttk.Frame(UI['tabs'])
    outer_frame.columnconfigure(0, weight=1)
    outer_frame.rowconfigure(0, weight=1)

    TABS[group_name] = outer_frame
    # We add this attribute so the refresh() method knows all the
    # tab names
    outer_frame.nb_text = group_name
    outer_frame.nb_type = tab_type

    # We need a canvas to make the list scrollable.
    canv = Canvas(
        outer_frame,
        highlightthickness=0,
    )
    scroll = tk_tools.HidingScroll(
        outer_frame,
        orient=VERTICAL,
        command=canv.yview,
    )
    canv['yscrollcommand'] = scroll.set
    canv.grid(row=0, column=0, sticky='NSEW')
    scroll.grid(row=0, column=1, sticky='NS')

    UI['tabs'].add(outer_frame)

    # This holds the actual elements
    frame = ttk.Frame(canv, )
    frame.columnconfigure(0, weight=1)
    canv.create_window(0, 0, window=frame, anchor="nw")

    ttk.Label(
        frame,
        text=group_name,
        anchor='center',
        font='tkHeadingFont',
    ).grid(
        row=0,
        column=0,
        sticky='EW',
    )

    ttk.Label(
        frame,
        text=group_desc,
    ).grid(
        row=1,
        column=0,
        sticky='EW',
    )

    ttk.Separator(frame, orient=HORIZONTAL).grid(
        row=2,
        column=0,
        sticky='EW',
    )

    if tab_type is TabTypes.RESPONSE:
        sorted_quotes = sorted(group, key=lambda prop: prop.real_name)
    else:
        sorted_quotes = sorted(
            group.find_all('Quote'),
            key=quote_sort_func,
            reverse=True,
        )

    for quote in sorted_quotes:  # type: Property
        if not quote.has_children():
            continue  # Skip over config commands..

        if tab_type is TabTypes.RESPONSE:
            try:
                name = RESPONSE_NAMES[quote.name]
            except KeyError:
                # Convert channels of the form 'death_goo' into 'Death - Goo'.
                channel, ch_arg = quote.name.split('_', 1)
                name = channel.title() + ' - ' + ch_arg.title()
                del channel, ch_arg

            group_id = quote.name
        else:
            # note: default for quote names
            name = quote['name', _('No Name!')]

        ttk.Label(
            frame,
            text=name,
            font=QUOTE_FONT,
        ).grid(
            column=0,
            sticky=W,
        )

        if tab_type is TabTypes.RESPONSE:
            line_iter = find_resp_lines(quote)
        else:
            line_iter = find_lines(quote)

        for badges, line, line_id in line_iter:
            line_frame = ttk.Frame(frame, )
            line_frame.grid(
                column=0,
                padx=(10, 0),
                sticky=W,
            )
            for x, (img, ctx) in enumerate(badges):
                label = ttk.Label(line_frame, image=img, padding=0)
                label.grid(row=0, column=x)
                add_tooltip(label, ctx)

            line_frame.columnconfigure(len(badges), weight=1)

            check = ttk.Checkbutton(
                line_frame,
                # note: default voice line name next to checkbox.
                text=line['name', _('No Name?')],
            )

            check.quote_var = IntVar(value=config.get_bool(
                group_id, line_id, True), )

            check['variable'] = check.quote_var

            check['command'] = functools.partial(
                check_toggled,
                var=check.quote_var,
                config_section=config[group_id],
                quote_id=line_id,
            )
            check.transcript = list(get_trans_lines(line))
            check.grid(
                row=0,
                column=len(badges),
            )
            check.bind("<Enter>", show_trans)

    def configure_canv(e):
        """Allow resizing the windows."""
        canv['scrollregion'] = (
            4,
            0,
            canv.winfo_reqwidth(),
            frame.winfo_reqheight(),
        )
        frame['width'] = canv.winfo_reqwidth()

    canv.bind('<Configure>', configure_canv)

    return outer_frame