Exemplo n.º 1
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=True)
                wid.bind('<Leave>', self.hover_stop, add=True)
                tk_tools.bind_leftclick(wid, self.row_click, add=True)
                wid.bind(tk_tools.EVENTS['LEFT_RELEASE'],
                         self.row_unclick,
                         add=True)

            self.val_widgets.append(wid)

        tk_tools.add_mousewheel(self.master.wid_canvas, self.check,
                                *self.val_widgets)
Exemplo n.º 2
0
def make_pane(parent: ttk.Frame):
    """Create all the widgets we use."""
    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

    tk_tools.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)

    sign_button = signage_ui.init_widgets(canvas_frame)
    if sign_button is not None:
        sign_button.grid(row=0, column=0, sticky='ew')

    for conf_row, config in enumerate(CONFIG_ORDER, start=1):
        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)

                try:
                    widget = wid.create_func(wid_frame, wid.values, wid.config)
                except Exception:
                    LOGGER.exception('Could not construct widget {}.{}',
                                     config.id, wid.id)
                    continue

                label = ttk.Label(wid_frame, text=wid.name + ': ')
                label.grid(row=0, column=0)
                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)
Exemplo n.º 3
0
def init_widgets(master: ttk.Frame) -> Optional[tk.Widget]:
    """Construct the widgets, returning the configuration button.

    If no signages are defined, this returns None.
    """

    if not any(Signage.all()):
        return ttk.Label(master)

    window.resizable(True, True)
    window.title(gettext('Configure Signage'))

    frame_selected = ttk.Labelframe(
        window,
        text=gettext('Selected'),
        relief='raised',
        labelanchor='n',
    )

    canv_all = tk.Canvas(window)

    scroll = tk_tools.HidingScroll(window, orient='vertical', command=canv_all.yview)
    canv_all['yscrollcommand'] = scroll.set

    name_label = ttk.Label(window, text='', justify='center')
    frame_preview = ttk.Frame(window, relief='raised', borderwidth=4)

    frame_selected.grid(row=0, column=0, sticky='nsew')
    ttk.Separator(orient='horizontal').grid(row=1, column=0, sticky='ew')
    name_label.grid(row=2, column=0)
    frame_preview.grid(row=3, column=0, pady=4)
    canv_all.grid(row=0, column=1, rowspan=4, sticky='nsew')
    scroll.grid(row=0, column=2, rowspan=4, sticky='ns')
    window.columnconfigure(1, weight=1)
    window.rowconfigure(3, weight=1)

    tk_tools.add_mousewheel(canv_all, canv_all, window)

    preview_left = ttk.Label(frame_preview, anchor='e')
    preview_right = ttk.Label(frame_preview, anchor='w')
    img.apply(preview_left, IMG_BLANK)
    img.apply(preview_right, IMG_BLANK)
    preview_left.grid(row=0, column=0)
    preview_right.grid(row=0, column=1)

    try:
        sign_arrow = Signage.by_id('SIGN_ARROW')
    except KeyError:
        LOGGER.warning('No arrow signage defined!')
        sign_arrow = None

    hover_arrow = False
    hover_toggle_id = None
    hover_sign: Optional[Signage] = None

    def hover_toggle() -> None:
        """Toggle between arrows and dual icons."""
        nonlocal hover_arrow, hover_toggle_id
        hover_arrow = not hover_arrow
        if hover_sign is None:
            return
        if hover_arrow and sign_arrow:
            left = hover_sign.dnd_icon
            right = sign_arrow.dnd_icon
        else:
            try:
                left = Signage.by_id(hover_sign.prim_id or '').dnd_icon
            except KeyError:
                left = hover_sign.dnd_icon
            try:
                right = Signage.by_id(hover_sign.sec_id or '').dnd_icon
            except KeyError:
                right = IMG_BLANK
        img.apply(preview_left, left)
        img.apply(preview_right, right)
        hover_toggle_id = TK_ROOT.after(1000, hover_toggle)

    def on_hover(slot: dragdrop.Slot[Signage]) -> None:
        """Show the signage when hovered."""
        nonlocal hover_arrow, hover_sign
        if slot.contents is not None:
            name_label['text'] = gettext('Signage: {}').format(slot.contents.name)
            hover_sign = slot.contents
            hover_arrow = True
            hover_toggle()
        else:
            on_leave(slot)

    def on_leave(slot: dragdrop.Slot[Signage]) -> None:
        """Reset the visible sign when left."""
        nonlocal hover_toggle_id, hover_sign
        name_label['text'] = ''
        hover_sign = None
        if hover_toggle_id is not None:
            TK_ROOT.after_cancel(hover_toggle_id)
            hover_toggle_id = None
        img.apply(preview_left, IMG_BLANK)
        img.apply(preview_right, IMG_BLANK)

    drag_man.reg_callback(dragdrop.Event.HOVER_ENTER, on_hover)
    drag_man.reg_callback(dragdrop.Event.HOVER_EXIT, on_leave)

    for i in range(3, 31):
        SLOTS_SELECTED[i] = slot = drag_man.slot(
            frame_selected,
            source=False,
            label=f'00:{i:02g}'
        )
        row, col = divmod(i-3, 4)
        slot.grid(row=row, column=col, padx=1, pady=1)

        prev_id = DEFAULT_IDS.get(i, '')
        if prev_id:
            try:
                slot.contents = Signage.by_id(prev_id)
            except KeyError:
                LOGGER.warning('Missing sign id: {}', prev_id)

    for sign in sorted(Signage.all(), key=lambda s: s.name):
        if not sign.hidden:
            slot = drag_man.slot(canv_all, source=True)
            slot.contents = sign

    drag_man.flow_slots(canv_all, drag_man.sources())

    canv_all.bind(
        '<Configure>',
        lambda e: drag_man.flow_slots(canv_all, drag_man.sources()),
    )

    def hide_window() -> None:
        """Hide the window."""
        window.withdraw()
        drag_man.unload_icons()
        img.apply(preview_left, IMG_BLANK)
        img.apply(preview_right, IMG_BLANK)

    def show_window() -> None:
        """Show the window."""
        drag_man.load_icons()
        window.deiconify()
        utils.center_win(window, TK_ROOT)

    window.protocol("WM_DELETE_WINDOW", hide_window)
    return ttk.Button(
        master,
        text=gettext('Configure Signage'),
        command=show_window,
    )
Exemplo n.º 4
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, gettext("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 tk_tools.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)

        tk_tools.add_mousewheel(
            self.wid_canvas,
            self.wid_canvas,
            self.wid_frame,
            self.wid_header,
        )
Exemplo n.º 5
0
        self.refresh()

    def checked(self) -> Iterator[Item]:
        """Yields enabled check items."""
        return (item for item in self.items if item.state_var.get())

    def unchecked(self) -> Iterator[Item]:
        """Yields disabled check items."""
        return (item for item in self.items if not item.state_var.get())


if __name__ == '__main__':
    from app import TK_ROOT
    test_inst = CheckDetails(parent=TK_ROOT,
                             headers=['Name', 'Author', 'Description'],
                             items=[
                                 Item('Item1', 'Auth1', 'Blah blah blah'),
                                 Item('Item5', 'Auth3', 'Lorem Ipsum'),
                                 Item('Item3', 'Auth2', '.........'),
                                 Item('Item4', 'Auth2', '.........'),
                                 Item('Item6', 'Sir VeryLongName', '.....'),
                                 Item('Item2', 'Auth1', '...'),
                             ])
    test_inst.grid(sticky='NSEW')
    tk_tools.add_mousewheel(test_inst.wid_canvas, TK_ROOT)

    TK_ROOT.columnconfigure(0, weight=1)
    TK_ROOT.rowconfigure(0, weight=1)
    TK_ROOT.deiconify()
    TK_ROOT.mainloop()
Exemplo n.º 6
0
def init() -> None:
    """Initialise all widgets in the given window."""
    for cat, btn_text in [
            ('back_', gettext('Restore:')),
            ('game_', gettext('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=gettext('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=gettext('Delete Checked'),
            width=14,
        )
        UI[cat + 'btn_del'].grid(row=1, column=0, columnspan=3)

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

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

    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)
Exemplo n.º 7
0
def make_pane(tool_frame: Frame, menu_bar: Menu,
              update_item_vis: Callable[[], None]) -> None:
    """Create the styleVar pane.

    update_item_vis is the callback fired whenever change defaults changes.
    """
    global window, _load_cback
    _load_cback = update_item_vis

    window = SubPane(
        TK_ROOT,
        title=gettext('Style/Item Properties'),
        name='style',
        menu_bar=menu_bar,
        resize_y=True,
        tool_frame=tool_frame,
        tool_img='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=gettext('Styles'))

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

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

    tk_tools.add_mousewheel(canvas, stylevar_frame)

    canvas_frame = ttk.Frame(canvas)

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

    frm_chosen = ttk.Labelframe(canvas_frame, text=gettext("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=gettext("Other Styles:"))
    frm_other.grid(row=3, sticky='EW')

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

    VAR_LIST[:] = sorted(StyleVar.all(), key=operator.attrgetter('id'))

    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':
            checkbox_all[var.id]['command'] = lambda: update_item_vis()

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

    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)

    canvas.create_window(0, 0, window=canvas_frame, anchor="nw")
    canvas.update_idletasks()
    canvas.config(
        scrollregion=canvas.bbox(ALL),
        width=canvas_frame.winfo_reqwidth(),
    )

    if tk_tools.USE_SIZEGRIP:
        ttk.Sizegrip(
            window,
            cursor=tk_tools.Cursors.STRETCH_VERT,
        ).grid(row=1, column=0)

    canvas.bind('<Configure>',
                lambda e: canvas.configure(scrollregion=canvas.bbox(ALL)))

    item_config_frame = ttk.Frame(nbook)
    nbook.add(item_config_frame, text=gettext('Items'))
    itemconfig.make_pane(item_config_frame)
Exemplo n.º 8
0
    def __init__(self, translations: dict,
                 pipe: multiprocessing.connection.Connection) -> None:
        """Initialise the window."""
        self.win = window = tk.Toplevel(TK_ROOT)
        self.pipe = pipe
        window.columnconfigure(0, weight=1)
        window.rowconfigure(0, weight=1)
        window.title(translations['log_title'])
        window.protocol('WM_DELETE_WINDOW', self.evt_close)
        window.withdraw()

        self.has_text = False
        self.text = tk.Text(
            window,
            name='text_box',
            width=50,
            height=15,
        )
        self.text.grid(row=0, column=0, sticky='NSEW')

        scroll = tk_tools.HidingScroll(
            window,
            name='scroll',
            orient=tk.VERTICAL,
            command=self.text.yview,
        )
        scroll.grid(row=0, column=1, sticky='NS')
        self.text['yscrollcommand'] = scroll.set

        # Assign colours for each logging level
        for level, colour in LVL_COLOURS.items():
            self.text.tag_config(
                logging.getLevelName(level),
                foreground=colour,
                # For multi-line messages, indent this much.
                lmargin2=30,
            )
        self.text.tag_config(
            logging.getLevelName(logging.CRITICAL),
            background='red',
        )
        # If multi-line messages contain carriage returns, lmargin2 doesn't
        # work. Add an additional tag for that.
        self.text.tag_config(
            'INDENT',
            lmargin1=30,
            lmargin2=30,
        )

        button_frame = ttk.Frame(window, name='button_frame')
        button_frame.grid(row=1, column=0, columnspan=2, sticky='EW')

        ttk.Button(
            button_frame,
            name='clear_btn',
            text=translations['clear'],
            command=self.evt_clear,
        ).grid(row=0, column=0)

        ttk.Button(
            button_frame,
            name='copy_btn',
            text=translations['copy'],
            command=self.evt_copy,
        ).grid(row=0, column=1)

        sel_frame = ttk.Frame(button_frame)
        sel_frame.grid(row=0, column=2, sticky='EW')
        button_frame.columnconfigure(2, weight=1)

        ttk.Label(
            sel_frame,
            text=translations['log_show'],
            anchor='e',
            justify='right',
        ).grid(row=0, column=0, sticky='E')

        self.level_selector = ttk.Combobox(
            sel_frame,
            name='level_selector',
            values=translations['level_text'],
            exportselection=False,
            # On Mac this defaults to being way too wide!
            width=15 if utils.MAC else None,
        )
        self.level_selector.state(['readonly'
                                   ])  # Prevent directly typing in values
        self.level_selector.bind('<<ComboboxSelected>>', self.evt_set_level)
        self.level_selector.current(1)

        self.level_selector.grid(row=0, column=1, sticky='E')
        sel_frame.columnconfigure(1, weight=1)

        tk_tools.add_mousewheel(self.text, window, sel_frame, button_frame)

        if tk_tools.USE_SIZEGRIP:
            ttk.Sizegrip(button_frame).grid(row=0, column=3)