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)
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=2, ) 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)
def sel_item(self, item: Item, event=None): self.prop_name['text'] = item.longName if len(item.authors) == 0: self.prop_author['text'] = '' else: self.prop_author['text'] = ngettext( 'Author: {}', 'Authors: {}', len(item.authors), ).format(', '.join(item.authors)) if item.large_icon is not None: # We have a large icon, use it. self.prop_icon['image'] = item.large_icon width, height = img.tuple_size(ICON_SIZE_LRG) else: # Small icon, shrink the preview. self.prop_icon['image'] = item.icon width, height = img.tuple_size(ICON_SIZE) self.prop_icon_frm.configure(width=width, height=height) self.prop_desc.set_text(item.desc) self.selected.button.state(('!alternate', )) self.selected = item item.button.state(('alternate', )) self.scroll_to(item) if self.sampler: is_playing = self.sampler.is_playing self.sampler.stop() self.sampler.cur_file = item.snd_sample if self.sampler.cur_file: self.samp_button.state(('!disabled', )) if is_playing: # Start the sampler again, so it plays the current item! self.sampler.play_sample() else: self.samp_button.state(('disabled', )) if self.has_def: if self.suggested is None or self.selected == self.suggested: self.prop_reset.state(('disabled', )) else: self.prop_reset.state(('!disabled', )) if self.attr: # Set the attribute items. for attr_id, label in self.attr.items(): val = item.attrs.get(attr_id, label.default) if label.type is AttrTypes.BOOL: label['image'] = (ICON_CHECK if val else ICON_CROSS) elif label.type is AttrTypes.COLOR: label['image'] = img.color_square(val, size=16) # Display the full color when hovering.. # i18n: Tooltip for colour swatch. set_tooltip( label, _('Color: R={r}, G={g}, B={b}').format( r=int(val.x), g=int(val.y), b=int(val.z), )) elif label.type is AttrTypes.LIST: # Join the values (in alphabetical order) label['text'] = ', '.join(sorted(val)) elif label.type is AttrTypes.STRING: # Just a string. label['text'] = str(val) else: raise ValueError('Invalid attribute type: "{}"'.format( label.type))
def sel_item(self, item: Item, event=None): self.prop_name['text'] = item.longName if len(item.authors) == 0: self.prop_author['text'] = '' else: self.prop_author['text'] = ngettext( 'Author: {}', 'Authors: {}', len(item.authors), ).format( ', '.join(item.authors) ) if item.large_icon is not None: # We have a large icon, use it. self.prop_icon['image'] = item.large_icon width, height = img.tuple_size(ICON_SIZE_LRG) else: # Small icon, shrink the preview. self.prop_icon['image'] = item.icon width, height = img.tuple_size(ICON_SIZE) self.prop_icon_frm.configure(width=width, height=height) self.prop_desc.set_text(item.desc) self.selected.button.state(('!alternate',)) self.selected = item item.button.state(('alternate',)) self.scroll_to(item) if self.sampler: is_playing = self.sampler.is_playing self.sampler.stop() self.sampler.cur_file = item.snd_sample if self.sampler.cur_file: self.samp_button.state(('!disabled',)) if is_playing: # Start the sampler again, so it plays the current item! self.sampler.play_sample() else: self.samp_button.state(('disabled',)) if self.has_def: if self.suggested is None or self.selected == self.suggested: self.prop_reset.state(('disabled',)) else: self.prop_reset.state(('!disabled',)) if self.attr: # Set the attribute items. for attr_id, label in self.attr.items(): val = item.attrs.get(attr_id, label.default) if label.type is AttrTypes.BOOL: label['image'] = ( ICON_CHECK if val else ICON_CROSS ) elif label.type is AttrTypes.COLOR: label['image'] = img.color_square(val, size=16) # Display the full color when hovering.. # i18n: Tooltip for colour swatch. set_tooltip(label, _('Color: R={r}, G={g}, B={b}').format( r=int(val.x), g=int(val.y), b=int(val.z), )) elif label.type is AttrTypes.LIST: # Join the values (in alphabetical order) label['text'] = ', '.join(sorted(val)) elif label.type is AttrTypes.STRING: # Just a string. label['text'] = str(val) else: raise ValueError( 'Invalid attribute type: "{}"'.format(label.type) )