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))
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)
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)
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.' ), )
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
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)
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)
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)
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)
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))
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)
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
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
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
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 )
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)
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)
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)
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)
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.' )
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)
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)
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)
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))
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)
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, 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, )
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
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)
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)
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)
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, )
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)
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)
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
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)
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)
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)
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), )
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.'), )
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)
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.'), )
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)
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)
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