def add_tabs(): """Add the tabs to the notebook.""" notebook = UI['tabs'] # Save the current tab index so we can restore it after. try: current_tab = notebook.index(notebook.select()) except TclError: # .index() will fail if the voice is empty, current_tab = None # in that case abandon remembering the tab. # Add or remove tabs so only the correct mode is visible. for name, tab in sorted(TABS.items()): notebook.add(tab) # For the special tabs, we use a special image to make # sure they are well-distinguished from the other groups if tab.nb_type is TabTypes.MID: notebook.tab( tab, compound='image', image=img.png('icons/mid_quote'), ) if tab.nb_type is TabTypes.RESPONSE: notebook.tab( tab, compound=RIGHT, image=img.png('icons/resp_quote'), #Note: 'response' tab name, should be short. text=_('Resp')) else: notebook.tab(tab, text=tab.nb_text) if current_tab is not None: notebook.select(current_tab)
def __init__( self, name: str, icon: str, group: str = None, group_icon: str = None, ) -> None: self.name = name self.dnd_icon = img.png('items/clean/{}.png'.format(icon)) self.dnd_group = group if group_icon: self.dnd_group_icon = img.png( 'items/clean/{}.png'.format(group_icon))
def set_corridors(config: Dict[Tuple[str, int], CorrDesc]): """Set the corridor data based on the passed in config.""" CORRIDOR_DATA.clear() CORRIDOR_DATA.update(config) default_icon = img.icon('clean/portal_door') corridor_conf = COMPILE_CFG['CorridorNames'] for group, length in CORRIDOR_COUNTS.items(): selector = CORRIDOR[group] for item in selector.item_list: if item.name == '<NONE>': continue # No customisation for this. ind = int(item.name) data = config[group, ind] corridor_conf['{}_{}_name'.format(group, ind)] = data.name corridor_conf['{}_{}_desc'.format(group, ind)] = data.desc corridor_conf['{}_{}_icon'.format(group, ind)] = data.icon # Note: default corridor description desc = data.name or _('Corridor') item.longName = item.shortName = item.context_lbl = item.name + ': ' + desc if data.icon: item.large_icon = img.png( 'corr/' + data.icon, resize_to=selector_win.ICON_SIZE_LRG, error=default_icon, ) item.icon = img.png( 'corr/' + data.icon, resize_to=selector_win.ICON_SIZE, error=default_icon, ) else: item.icon = item.large_icon = default_icon if data.desc: item.desc = tkMarkdown.convert(data.desc) else: item.desc = CORRIDOR_DESC selector.set_disp() COMPILE_CFG.save_check()
def style_changed(new_style: Style) -> None: """Update the icons for the selected signage.""" for sign in Signage.all(): for potential_style in new_style.bases: try: icon = sign.styles[potential_style.id.upper()].icon break except KeyError: pass else: LOGGER.warning( 'No valid <{}> style for "{}" signage!', new_style.id, sign.id, ) try: icon = sign.styles['BEE2_CLEAN'].icon except KeyError: sign.dnd_icon = img.img_error continue if icon: sign.dnd_icon = img.png(icon, resize_to=(64, 64)) else: LOGGER.warning( 'No icon for "{}" signage in <{}> style!', sign.id, new_style.id, ) sign.dnd_icon = img.img_error drag_man.refresh_icons()
def make_help_menu(parent: tk.Menu): """Create the application 'Help' menu.""" # Using this name displays this correctly in OS X help = tk.Menu(parent, name='help') parent.add_cascade(menu=help, label=_('Help')) invis_icon = img.invis_square(16) icons = { icon: img.png('icons/' + icon.value, resize_to=16, error=invis_icon) for icon in ResIcon if icon is not ResIcon.NONE } icons[ResIcon.NONE] = invis_icon credits = Dialog( title=_('BEE2 Credits'), text=CREDITS_TEXT, ) for res in WEB_RESOURCES: if res is SEPERATOR: help.add_separator() else: help.add_command( label=res.name, command=functools.partial(webbrowser.open, res.url), compound='left', image=icons[res.icon], ) help.add_separator() help.add_command( label=_('Credits...'), command=credits.show, )
def __init__( self, man: Manager, parent: tkinter.Misc, is_source: bool, label: str, ) -> None: """Internal only, use Manager.slot().""" self.man = man self.is_source = is_source self._contents = None self._pos_type = None self._lbl = tkinter.Label( parent, image=man._img_blank, ) utils.bind_leftclick(self._lbl, self._evt_start) self._lbl.bind(utils.EVENTS['LEFT_SHIFT'], self._evt_fastdrag) self._lbl.bind('<Enter>', self._evt_hover_enter) self._lbl.bind('<Leave>', self._evt_hover_exit) config_event = self._evt_configure utils.bind_rightclick(self._lbl, config_event) if label: self._text_lbl = tkinter.Label( self._lbl, text=label, font=('Helvetica', -12), relief='ridge', bg=img.PETI_ITEM_BG_HEX, ) else: self._text_lbl = None if man.config_icon: self._info_btn = tkinter.Label( self._lbl, image=img.png('icons/gear'), relief='ridge', ) @utils.bind_leftclick(self._info_btn) def info_button_click(e): """Trigger the callback whenever the gear button was pressed.""" config_event(e) # Cancel the event sequence, so it doesn't travel up to the main # window and hide the window again. return 'break' # Rightclick does the same as the main icon. utils.bind_rightclick(self._info_btn, config_event) else: self._info_btn = None
def make_pane(tool_frame: Frame, menu_bar: Menu) -> None: """Initialise when part of the BEE2.""" global window window = SubPane.SubPane( TK_ROOT, title=_('Compile Options'), name='compiler', menu_bar=menu_bar, resize_x=True, resize_y=False, tool_frame=tool_frame, tool_img=img.png('icons/win_compiler'), tool_col=4, ) window.columnconfigure(0, weight=1) window.rowconfigure(0, weight=1) make_widgets()
def set_text(self, text_data: Union[str, tkMarkdown.MarkdownData]) -> None: """Write the rich-text into the textbox. text_data should either be a string, or the data returned from tkMarkdown.convert(). """ # Remove all previous link commands for cmd_tag, cmd_id in self._link_commands.values(): self.tag_unbind(cmd_tag, '<Button-1>', funcid=cmd_id) self._link_commands.clear() self['state'] = "normal" self.delete(1.0, END) # Basic mode, insert just blocks of text. if isinstance(text_data, str): super().insert("end", text_data) return segment: tkMarkdown.TextSegment for block in text_data.blocks: if isinstance(block, tkMarkdown.TextSegment): if block.url: try: cmd_tag, _ = self._link_commands[block.url] except KeyError: cmd_tag = f'link_cb_{len(self._link_commands)}' cmd_id = self.tag_bind( cmd_tag, '<Button-1>', self.make_link_callback(block.url), ) self._link_commands[block.url] = cmd_tag, cmd_id tags = block.tags + (cmd_tag, 'link') else: tags = block.tags super().insert('end', block.text, tags) elif isinstance(block, tkMarkdown.Image): super().insert('end', '\n') self.image_create('end', image=img.png(block.src)) super().insert('end', '\n') else: raise ValueError('Unknown block {!r}?'.format(block)) self['state'] = "disabled"
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_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, ) 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, ) UI['light_fast'].grid(row=0, column=0) UI['light_full'] = ttk.Radiobutton( vrad_frame, text=_('Full'), value=1, variable=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.\n" "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)
QUOTE_FONT = font.nametofont('TkHeadingFont').copy() QUOTE_FONT['weight'] = 'bold' IMG_TEXT = { 'sp': _('Singleplayer'), 'coop': _('Cooperative'), 'atlas': _('ATLAS (SP/Coop)'), 'pbody': _('P-Body (SP/Coop)'), 'bendy': _('Bendy'), 'chell': _('Chell'), 'human': _('Human characters (Bendy and Chell)'), 'robot': _('AI characters (ATLAS, P-Body, or Coop)'), } IMG = { spr: (img.png('icons/quote_' + spr), ctx) for spr, ctx in IMG_TEXT.items() } # type: Dict[str, Tuple[PhotoImage, str]] # Friendly names given to certain response channels. RESPONSE_NAMES = { 'death_goo': _('Death - Toxic Goo'), 'death_turret': _('Death - Turrets'), 'death_crush': _('Death - Crusher'), 'death_laserfield': _('Death - LaserField'), } config = config_mid = config_resp = None # type: ConfigFile class TabTypes(Enum):
def __init__(self, *args): super().__init__(*args) self.is_compact = True all_fonts = set(tk.font.families()) for font_family in all_fonts: # DIN is the font used by Portal 2's logo, # so try and use that. if 'DIN' in font_family: break else: # Otherwise, use system UI fonts from a list. for font_family in SPLASH_FONTS: if font_family in all_fonts: break else: font_family = 'Times' # Generic special case font = Font( family=font_family, size=-18, # negative = in pixels weight='bold', ) progress_font = Font( family=font_family, size=-12, # negative = in pixels ) logo_img = img.png('BEE2/splash_logo') self.lrg_canvas = tk.Canvas(self.win) self.sml_canvas = tk.Canvas( self.win, background='#009678', # 0, 150, 120 ) sml_width = int(min(self.win.winfo_screenwidth() * 0.5, 400)) sml_height = int(min(self.win.winfo_screenheight() * 0.5, 175)) self.lrg_canvas.create_image( 10, 10, anchor='nw', image=logo_img, ) self.sml_canvas.create_text( sml_width / 2, 30, anchor='n', text=self.title_text, fill='white', font=font, ) self.sml_canvas.create_text( sml_width / 2, 50, anchor='n', text=TRANSLATION['version'], fill='white', font=font, ) text1 = self.lrg_canvas.create_text( 10, 125, anchor='nw', text=self.title_text, fill='white', font=font, ) text2 = self.lrg_canvas.create_text( 10, 145, anchor='nw', text=TRANSLATION['version'], fill='white', font=font, ) # Now add shadows behind the text, and draw to the canvas. splash, lrg_width, lrg_height = img.make_splash_screen( max(self.win.winfo_screenwidth() * 0.6, 500), max(self.win.winfo_screenheight() * 0.6, 500), base_height=len(self.stages) * 20, text1_bbox=self.lrg_canvas.bbox(text1), text2_bbox=self.lrg_canvas.bbox(text2), ) self.splash_img = splash # Keep this alive self.lrg_canvas.tag_lower( self.lrg_canvas.create_image( 0, 0, anchor='nw', image=splash, )) self.canvas = [ (self.lrg_canvas, lrg_width, lrg_height), (self.sml_canvas, sml_width, sml_height), ] for canvas, width, height in self.canvas: canvas.create_rectangle( width - 40, 0, width - 20, 20, fill='#00785A', width=0, tags='resize_button', ) # 150, 120, 64 # Diagonal part of arrow. canvas.create_line( width - 20 - 4, 4, width - 20 - 16, 16, fill='black', width=2, tags='resize_button', ) canvas.tag_bind( 'resize_button', '<Button-1>', self.compact_button( canvas is self.lrg_canvas, width, lrg_width if width == sml_width else sml_width, ), ) self.sml_canvas.create_line( sml_width - 20 - 4, 4, sml_width - 20 - 16, 4, fill='black', width=2, tags='resize_button', ) self.sml_canvas.create_line( sml_width - 20 - 4, 4, sml_width - 20 - 4, 16, fill='black', width=2, tags='resize_button', ) self.lrg_canvas.create_line( lrg_width - 20 - 16, 16, lrg_width - 20 - 4, 16, fill='black', width=2, tags='resize_button', ) self.lrg_canvas.create_line( lrg_width - 20 - 16, 16, lrg_width - 20 - 16, 4, fill='black', width=2, tags='resize_button', ) for canvas, width, height in self.canvas: canvas['width'] = width canvas['height'] = height canvas.bind(utils.EVENTS['LEFT_DOUBLE'], self.toggle_compact) canvas.create_rectangle( width - 20, 0, width, 20, fill='#00785A', width=0, tags='quit_button', ) canvas.create_rectangle( width - 20, 0, width, 20, fill='#00785A', width=0, tags='quit_button', ) # 150, 120, 64 canvas.create_line( width - 16, 4, width - 4, 16, fill='black', width=2, tags='quit_button', ) canvas.create_line( width - 4, 4, width - 16, 16, fill='black', width=2, tags='quit_button', ) canvas.tag_bind('quit_button', '<Button-1>', self.cancel) for ind, (st_id, stage_name) in enumerate(reversed(self.stages), start=1): canvas.create_rectangle( 20, height - (ind + 0.5) * 20, 20, height - (ind - 0.5) * 20, fill='#00785A', # 0, 120, 90 width=0, tags='bar_' + st_id, ) # Border canvas.create_rectangle( 20, height - (ind + 0.5) * 20, width - 20, height - (ind - 0.5) * 20, outline='#00785A', width=2, ) canvas.create_text( 25, height - ind * 20, anchor='w', text=stage_name + ': (0/???)', fill='white', tags='text_' + st_id, font=progress_font, )
def make_pane(tool_frame: Frame, menu_bar: Menu, update_item_vis: Callable[[], None]): """Create the styleVar pane. update_item_vis is the callback fired whenever change defaults changes. """ global window, _load_cback _load_cback = update_item_vis window = SubPane( TK_ROOT, title=_('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')) canvas = Canvas(stylevar_frame, highlightthickness=0) # need to use a canvas to allow scrolling canvas.grid(sticky='NSEW') window.rowconfigure(0, weight=1) UI['style_scroll'] = ttk.Scrollbar( stylevar_frame, orient=VERTICAL, command=canvas.yview, ) UI['style_scroll'].grid(column=1, row=0, rowspan=2, sticky="NS") canvas['yscrollcommand'] = UI['style_scroll'].set utils.add_mousewheel(canvas, stylevar_frame) canvas_frame = ttk.Frame(canvas) 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': checkbox_all[var.id]['command'] = lambda: update_item_vis() 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, ) canvas.create_window(0, 0, window=canvas_frame, anchor="nw") canvas.update_idletasks() canvas.config( scrollregion=canvas.bbox(ALL), width=canvas_frame.winfo_reqwidth(), ) if utils.USE_SIZEGRIP: ttk.Sizegrip( window, cursor=utils.CURSORS['stretch_vert'], ).grid(row=1, column=0) canvas.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox(ALL))) item_config_frame = ttk.Frame(nbook) nbook.add(item_config_frame, text=_('Items')) itemconfig.make_pane(item_config_frame)