def __init__(self, master, style_def): super().__init__(master, style_def) self.set_def(style_def) self.config(width=150, height=110) self.n = ToggleButton(self, text="N", width=20, height=20) self.n.grid(row=0, column=0, columnspan=3, sticky='ns') self.w = ToggleButton(self, text='W', width=20, height=20) self.w.grid(row=1, column=0, sticky='ew') self.pad = Frame(self, width=60, height=60, **self.style.dark, **self.style.dark_highlight_active) self.pad.grid(row=1, column=1, padx=1, pady=1) self.pad.grid_propagate(0) self.pad.grid_columnconfigure(0, minsize=60) self.pad.grid_rowconfigure(0, minsize=60) self.floating = Frame(self.pad, **self.style.dark_on_hover, width=20, height=20) self.floating.grid(row=0, column=0, pady=1, padx=1) self.e = ToggleButton(self, text="E", width=20, height=20) self.e.grid(row=1, column=2, sticky='ew') self.s = ToggleButton(self, text='S', width=20, height=20) self.s.grid(row=2, column=0, columnspan=3, sticky='ns') self.anchors = {"n": self.n, "w": self.w, "e": self.e, "s": self.s} self._order = ("n", "s", "e", "w") self._selected = [] self._exclusive_pairs = ({"n", "s"}, {"e", "w"}) self._is_multiple = re.compile(r'(.*[ns].*[ns])|(.*[ew].*[ew])') for anchor in self.anchors: self.anchors[anchor].on_change(self._change, anchor)
def __init__(self, master, debugger): super(ElementPane, self).__init__(master) Label(self._header, **self.style.text_accent, text=self.name).pack(side="left") ElementTreeView.Node.debugger = debugger self._tree = ElementTreeView(self) self._tree.pack(side="top", fill="both", expand=True, pady=4) self._tree.allow_multi_select(True) self._tree.on_select(self.on_select) self._search_btn = Button( self._header, **self.style.button, image=get_icon_image("search", 15, 15), width=25, height=25, ) self._search_btn.pack(side="right", padx=2) self._search_btn.on_click(self.start_search) self._reload_btn = Button( self._header, **self.style.button, image=get_icon_image("rotate_clockwise", 15, 15), width=25, height=25, ) self._reload_btn.pack(side="right", padx=2) self._reload_btn.tooltip("reload tree") self._toggle_btn = Button(self._header, image=get_icon_image("chevron_down", 15, 15), **self.style.button, width=25, height=25) self._toggle_btn.pack(side="right", padx=2) self._select_btn = ToggleButton( self._header, **self.style.button, image=get_icon_image("cursor", 15, 15), width=25, height=25, ) self._select_btn.pack(side="right", padx=2) self._select_btn.tooltip("select element to inspect") self.debugger = debugger self._tree.add_as_node( widget=debugger.root).update_preload_status(False) self.debugger.bind("<<WidgetCreated>>", self.on_widget_created) self.debugger.bind("<<WidgetDeleted>>", self.on_widget_deleted) self.debugger.bind("<<WidgetModified>>", self.on_widget_modified) tkinter.Misc.bind_all(self.debugger.root, "<Motion>", self.on_motion) tkinter.Misc.bind_all(self.debugger.root, "<Button-1>", self.on_widget_tap) tkinter.Misc.bind_all(self.debugger.root, "<Button-3>", self.on_widget_tap) tkinter.Misc.bind_all(self.debugger.root, "<Map>", self.on_widget_map) tkinter.Misc.bind_all(self.debugger.root, "<Unmap>", self.on_widget_unmap) self.highlighted = None
class Anchor(Editor): def __init__(self, master, style_def): super().__init__(master, style_def) self.set_def(style_def) self.config(width=150, height=110) self.n = ToggleButton(self, text="N", width=20, height=20) self.n.grid(row=0, column=0, columnspan=3, sticky='ns') self.w = ToggleButton(self, text='W', width=20, height=20) self.w.grid(row=1, column=0, sticky='ew') self.pad = Frame(self, width=60, height=60, **self.style.dark, **self.style.dark_highlight_active) self.pad.grid(row=1, column=1, padx=1, pady=1) self.pad.grid_propagate(0) self.pad.grid_columnconfigure(0, minsize=60) self.pad.grid_rowconfigure(0, minsize=60) self.floating = Frame(self.pad, **self.style.dark_on_hover, width=20, height=20) self.floating.grid(row=0, column=0, pady=1, padx=1) self.e = ToggleButton(self, text="E", width=20, height=20) self.e.grid(row=1, column=2, sticky='ew') self.s = ToggleButton(self, text='S', width=20, height=20) self.s.grid(row=2, column=0, columnspan=3, sticky='ns') self.anchors = {"n": self.n, "w": self.w, "e": self.e, "s": self.s} self._order = ("n", "s", "e", "w") self._selected = [] self._exclusive_pairs = ({"n", "s"}, {"e", "w"}) self._is_multiple = re.compile(r'(.*[ns].*[ns])|(.*[ew].*[ew])') for anchor in self.anchors: self.anchors[anchor].on_change(self._change, anchor) def _is_exclusive_of(self, anchor1, anchor2): return {anchor1, anchor2} in self._exclusive_pairs def _change(self, _, anchor): if not self.multiple: self._sanitize(anchor) self._adjust() if self._on_change: self._on_change(self.get()) def _sanitize(self, anchor): ex_anchor = [i for i in self.get() if self._is_exclusive_of(i, anchor)] if len(ex_anchor): self.anchors.get(ex_anchor[0]).set(False) def _adjust(self): sticky = '' if self.get() == 'center' else self.get() self.floating.grid(row=0, column=0, pady=1, padx=1, sticky=sticky) def get(self): anchor = ''.join([i for i in self._order if self.anchors[i].get()]) # No anchor means center but only when we are acting as an anchor editor # if self.multiple is True then we are a stickiness editor and an empty string will suffice if anchor == '': if not self.multiple: return 'center' return anchor def set(self, value): # bypass the special value 'center' before subjecting to validity check value = '' if value == 'center' else str(value) # Ignore invalid values if self._is_multiple.match(str(value)) and not self.multiple: return # Assume no anchor means center for anchor in self.anchors: self.anchors.get(anchor).set(anchor in value) self._adjust() def set_def(self, definition): # This flag determines whether multiple anchors are allowed at a time # set to True to obtain a sticky property editor self.multiple = definition.get("multiple", True) super().set_def(definition)
class ElementPane(Pane): name = "Widget tree" MAX_STARTING_DEPTH = 4 def __init__(self, master, debugger): super(ElementPane, self).__init__(master) Label(self._header, **self.style.text_accent, text=self.name).pack(side="left") ElementTreeView.Node.debugger = debugger self._tree = ElementTreeView(self) self._tree.pack(side="top", fill="both", expand=True, pady=4) self._tree.allow_multi_select(True) self._tree.on_select(self.on_select) self._search_btn = Button( self._header, **self.style.button, image=get_icon_image("search", 15, 15), width=25, height=25, ) self._search_btn.pack(side="right", padx=2) self._search_btn.on_click(self.start_search) self._reload_btn = Button( self._header, **self.style.button, image=get_icon_image("rotate_clockwise", 15, 15), width=25, height=25, ) self._reload_btn.pack(side="right", padx=2) self._reload_btn.tooltip("reload tree") self._toggle_btn = Button(self._header, image=get_icon_image("chevron_down", 15, 15), **self.style.button, width=25, height=25) self._toggle_btn.pack(side="right", padx=2) self._select_btn = ToggleButton( self._header, **self.style.button, image=get_icon_image("cursor", 15, 15), width=25, height=25, ) self._select_btn.pack(side="right", padx=2) self._select_btn.tooltip("select element to inspect") self.debugger = debugger self._tree.add_as_node( widget=debugger.root).update_preload_status(False) self.debugger.bind("<<WidgetCreated>>", self.on_widget_created) self.debugger.bind("<<WidgetDeleted>>", self.on_widget_deleted) self.debugger.bind("<<WidgetModified>>", self.on_widget_modified) tkinter.Misc.bind_all(self.debugger.root, "<Motion>", self.on_motion) tkinter.Misc.bind_all(self.debugger.root, "<Button-1>", self.on_widget_tap) tkinter.Misc.bind_all(self.debugger.root, "<Button-3>", self.on_widget_tap) tkinter.Misc.bind_all(self.debugger.root, "<Map>", self.on_widget_map) tkinter.Misc.bind_all(self.debugger.root, "<Unmap>", self.on_widget_unmap) self.highlighted = None @property def selected(self): return self._tree.get() def on_select(self): self.debugger.update_selection(self._tree.get()) def on_widget_tap(self, event): if self._select_btn.get(): try: # widget = self.debugger.root.winfo_containing(event.x_root, event.y_root) widget = event.widget # print(widget) if widget.winfo_toplevel() == self.debugger or getattr( widget, "_dbg_ignore", False): widget = None except (KeyError, AttributeError): widget = None if widget: node = self._tree.expand_to(widget) if node: node.select(event) def on_motion(self, event): if self._select_btn.get(): try: # widget = self.debugger.root.winfo_containing(event.x_root, event.y_root) widget = event.widget if widget.winfo_toplevel() == self.debugger or getattr( widget, "_dbg_ignore", False): widget = None # print(f"motion : {widget} <> {event.widget}") except (KeyError, AttributeError): widget = None self.debugger.highlight_widget(widget) self.highlighted = widget def on_widget_created(self, _): widget = self.debugger.active_widget parent_node = getattr(widget.master, "_dbg_node", None) if parent_node: if parent_node.loaded: parent_node.add_as_node(widget=widget) self.debugger.hook_widget(widget) else: parent_node.update_preload_status(True) def on_widget_deleted(self, _): widget = self.debugger.active_widget parent_node = getattr(widget.master, "_dbg_node", None) if parent_node: if parent_node.loaded: node = widget._dbg_node if node in self.selected: self._tree.toggle_from_selection(node) parent_node.remove(widget._dbg_node) else: parent_node.update_preload_status(False) def on_widget_modified(self, _): if self.debugger.active_widget not in self.selected: return def on_widget_map(self, _): pass def on_widget_unmap(self, _): pass