예제 #1
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)
예제 #2
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)
예제 #3
0
def init_widgets():
    """Make all the window components."""
    win.columnconfigure(0, weight=1)
    win.transient(master=TK_ROOT)
    tk_tools.set_window_icon(win)
    win.protocol("WM_DELETE_WINDOW", win.withdraw)
    win.bind("<Escape>", lambda event: win.withdraw())

    pane = PanedWindow(
        win,
        orient=VERTICAL,
        sashpad=2,  # Padding above/below panes
        sashwidth=3,  # Width of border
        sashrelief=RAISED,  # Raise the border between panes
    )
    UI['pane'] = pane
    pane.grid(row=1, column=0, sticky='NSEW')
    win.rowconfigure(1, weight=1)

    UI['tabs'] = ttk.Notebook(pane)
    UI['tabs'].enable_traversal()  # Add keyboard shortcuts
    pane.add(UI['tabs'])
    pane.paneconfigure(UI['tabs'], minsize=50)

    trans_frame = ttk.Frame(pane)
    trans_frame.rowconfigure(1, weight=1)
    trans_frame.columnconfigure(0, weight=1)

    ttk.Label(
        trans_frame,
        text=_('Transcript:'),
    ).grid(
        row=0,
        column=0,
        sticky=W,
    )

    trans_inner_frame = ttk.Frame(trans_frame, borderwidth=2, relief='sunken')
    trans_inner_frame.grid(row=1, column=0, sticky='NSEW')
    trans_inner_frame.rowconfigure(0, weight=1)
    trans_inner_frame.columnconfigure(0, weight=1)

    default_bold_font = font.nametofont('TkDefaultFont').copy()
    default_bold_font['weight'] = 'bold'

    UI['trans'] = Text(
        trans_inner_frame,
        width=10,
        height=4,
        wrap='word',
        relief='flat',
        state='disabled',
        font='TkDefaultFont',
    )
    UI['trans_scroll'] = tk_tools.HidingScroll(
        trans_inner_frame,
        orient=VERTICAL,
        command=UI['trans'].yview,
    )
    UI['trans'].tag_config(
        'bold',
        font=default_bold_font,
    )
    UI['trans']['yscrollcommand'] = UI['trans_scroll'].set
    UI['trans_scroll'].grid(row=0, column=1, sticky='NS')
    UI['trans'].grid(row=0, column=0, sticky='NSEW')

    ttk.Button(
        win,
        text=_('Save'),
        command=save,
    ).grid(row=2, column=0)

    # Don't allow resizing the transcript box to be smaller than the
    # original size.
    trans_frame.update_idletasks()
    pane.paneconfigure(trans_frame, minsize=trans_frame.winfo_reqheight())
예제 #4
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")

    # We do this so we can adjust the scrollregion later in
    # <Configure>.
    canv.frame = frame

    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 badge, line, line_id in line_iter:
            if line_id is None:
                line_id = line['id', line['name']]
            check = ttk.Checkbutton(
                frame,
                # note: default voice line name next to checkbox.
                text=line['name', _('No Name?')],
                compound=LEFT,
                image=badge,
            )

            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(
                column=0,
                padx=(10, 0),
                sticky=W,
            )
            check.bind("<Enter>", show_trans)
    canv.bind('<Configure>', configure_canv)

    return outer_frame
def init_widgets():
    pane = PanedWindow(
        win,
        orient=VERTICAL,
        sashpad=2,  # Padding above/below panes
        sashwidth=3,  # Width of border
        sashrelief=RAISED,  # Raise the border between panes
    )
    UI['pane'] = pane
    pane.grid(row=1, column=0, sticky='NSEW')
    win.rowconfigure(1, weight=1)

    UI['tabs'] = ttk.Notebook(pane)
    UI['tabs'].enable_traversal()  # Add keyboard shortcuts
    pane.add(UI['tabs'])
    pane.paneconfigure(UI['tabs'], minsize=50)

    trans_frame = ttk.Frame(pane)
    trans_frame.rowconfigure(1, weight=1)
    trans_frame.columnconfigure(0, weight=1)

    ttk.Label(
        trans_frame,
        text=_('Transcript:'),
    ).grid(
        row=0,
        column=0,
        sticky=W,
    )

    trans_inner_frame = ttk.Frame(trans_frame, borderwidth=2, relief='sunken')
    trans_inner_frame.grid(row=1, column=0, sticky='NSEW')
    trans_inner_frame.rowconfigure(0, weight=1)
    trans_inner_frame.columnconfigure(0, weight=1)

    UI['trans'] = Text(
        trans_inner_frame,
        width=10,
        height=4,
        wrap='word',
        relief='flat',
        state='disabled',
        font=('Helvectia', 10),
    )
    UI['trans_scroll'] = tk_tools.HidingScroll(
        trans_inner_frame,
        orient=VERTICAL,
        command=UI['trans'].yview,
    )
    UI['trans'].tag_config(
        'bold',
        font=('Helvectia', 10, 'bold'),
    )
    UI['trans']['yscrollcommand'] = UI['trans_scroll'].set
    UI['trans_scroll'].grid(row=0, column=1, sticky='NS')
    UI['trans'].grid(row=0, column=0, sticky='NSEW')

    ttk.Button(
        win,
        text='Save',
        command=save,
    ).grid(row=2, column=0)

    # Don't allow resizing the transcript box to be smaller than the
    # original size.
    trans_frame.update_idletasks()
    pane.paneconfigure(trans_frame, minsize=trans_frame.winfo_reqheight())
예제 #6
0
def init(start_open, log_level='info'):
    """Initialise the window."""
    global window, log_handler, text_box, level_selector

    window = tk.Toplevel(TK_ROOT, name='console_win')
    window.withdraw()
    window.columnconfigure(0, weight=1)
    window.rowconfigure(0, weight=1)
    window.title(_('Logs - {}').format(utils.BEE_VERSION))
    window.protocol('WM_DELETE_WINDOW', lambda: set_visible(False))

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

    log_level = logging.getLevelName(log_level.upper())

    log_handler = TextHandler(text_box)

    try:
        log_handler.setLevel(log_level)
    except ValueError:
        log_level = logging.INFO
    log_handler.setFormatter(utils.short_log_format)

    logging.getLogger('BEE2').addHandler(log_handler)

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

    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='Clear',
        command=btn_clear,
    ).grid(row=0, column=0)

    ttk.Button(
        button_frame,
        name='copy_btn',
        text=_('Copy'),
        command=btn_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=_('Show:'),
        anchor='e',
        justify='right',
    ).grid(row=0, column=0, sticky='E')

    level_selector = ttk.Combobox(
        sel_frame,
        name='level_selector',
        values=[LVL_TEXT[level] for level in BOX_LEVELS],
        exportselection=0,
        # On Mac this defaults to being way too wide!
        width=15 if utils.MAC else None,
    )
    level_selector.state(['readonly'])  # Prevent directly typing in values
    level_selector.bind('<<ComboboxSelected>>', set_level)
    level_selector.current(BOX_LEVELS.index(log_level))

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

    utils.add_mousewheel(text_box, window, sel_frame, button_frame)

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

    if start_open:
        window.deiconify()
        window.lift()
        # Force an update, we're busy with package extraction...
        window.update()
    else:
        window.withdraw()
def init(frm):
    """Initialise the UI objects."""

    frm.bind('<Enter>', expand)
    frm.bind('<Leave>', contract)

    wid['tag_mode_any'] = widget = ttk.Radiobutton(
        frm,
        text='Any',
        variable=TAG_MODE,
        value='ANY',
        command=filter_items,
    )
    widget.grid(row=0, column=0, sticky='W')

    wid['tag_mode_all'] = widget = ttk.Radiobutton(
        frm,
        text='All',
        variable=TAG_MODE,
        value='ALL',
        command=filter_items,
    )
    widget.grid(row=1, column=0, sticky='W')

    wid['cur_tags'] = cur_tags = tk.Text(
        frm,
        font='TkDefaultFont',
        width=10,
        height=2,
        cursor=utils.CURSORS['regular'],
    )
    cur_tags.grid(row=0, rowspan=2, column=1, sticky='EW')

    wid['expand_frame'] = exp = ttk.Frame(frm, )

    # Resize to fit the expansion frame
    frm.columnconfigure(1, weight=1)
    frm.rowconfigure(2, weight=1)

    ttk.Label(
        exp,
        text='Available Tags (click):',
    ).grid(row=0, column=0, columnspan=2)

    # Make the tag section the dynamically-resizing portion
    exp.columnconfigure(0, weight=1)
    exp.rowconfigure(0, weight=1)

    wid['tag_list'] = tag_list = tk.Text(
        exp,
        font='TkDefaultFont',
        width=10,
        height=8,
        cursor=utils.CURSORS['regular'],
    )
    tag_list.grid(row=1, column=0, sticky='NSEW')

    wid['tag_scroll'] = tag_scroll = tk_tools.HidingScroll(
        exp,
        orient=tk.VERTICAL,
        command=tag_list.yview,
    )
    tag_scroll.grid(row=1, column=1, sticky='NS')
    tag_list['yscrollcommand'] = tag_scroll.set
    tag_list['state'] = "disabled"  # Prevent users from editing the text

    def event_hover_tag(text: tk.Text, e):
        """When hovering over a tag, change the cursor."""
        text['cursor'] = utils.CURSORS['link']

    def event_unhover_tag(text: tk.Text, e):
        text['cursor'] = utils.CURSORS['regular']

    for text in (tag_list, cur_tags):
        text.tag_config(
            'highlight',
            underline=1,
        )
        # We can't change the cursor property for individual tags, so
        # change it globally when the cursor enters and leaves.
        text.tag_bind('highlight', '<Enter>', partial(event_hover_tag, text))
        text.tag_bind('highlight', '<Leave>', partial(event_unhover_tag, text))
    tag_list.tag_config(
        'header',
        font=BOLD_FONT,
    )

    refresh_tags()