def init_toolbar(self): for action in self.actions: if len(action) == 1: Frame(self._toolbar, width=1, bg=self.style.colors.get("primarydarkaccent")).pack( side='left', fill='y', pady=3, padx=5) continue btn = Button(self._toolbar, image=action[1], **self.style.button, width=25, height=25) btn.pack(side="left", padx=3) btn.tooltip(action[3]) ActionNotifier.bind_event("<Button-1>", btn, action[2], text=action[3])
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
class EventPane(BaseFeature): name = "Event pane" icon = "blank" _defaults = { **BaseFeature._defaults, "side": "right", } NO_SELECTION_MSG = "You have not selected any widget selected" NO_EVENT_MSG = "You have not added any bindings" NO_MATCH_MSG = "No items match your search" def __init__(self, master, studio, **cnf): super().__init__(master, studio, **cnf) self.header = Frame(self, **self.style.surface) self.header.pack(side="top", fill="x") for i, title in enumerate(("Sequence", "Handler", "Add", " " * 3)): Label( self.header, **self.style.text_passive, text=title, anchor="w", ).grid(row=0, column=i, sticky='ew') # set the first two columns to expand evenly for column in range(2): self.header.grid_columnconfigure(column, weight=1, uniform=1) self.bindings = BindingsTable(self) self.bindings.on_value_change(self.modify_item) self.bindings.on_item_delete(self.delete_item) self.bindings.pack(fill="both", expand=True) self._add = Button(self._header, **self.style.button, width=25, height=25, image=get_icon_image("add", 15, 15)) self._add.pack(side="right") self._add.tooltip("Add event binding") self._add.on_click(self.add_new) 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") self._search_btn.on_click(self.start_search) self._empty_frame = Label(self.bindings, **self.style.text_passive) self._show_empty(self.NO_SELECTION_MSG) def _show_empty(self, message): self._empty_frame.place(x=0, y=0, relwidth=1, relheight=1) self._empty_frame["text"] = message def _remove_empty(self): self._empty_frame.place_forget() def add_new(self, *_): if self.studio.selected is None: return self._remove_empty() new_binding = make_event("<>", "", False) widget = self.studio.selected if not hasattr(widget, "_event_map_"): setattr(widget, "_event_map_", {}) widget._event_map_[new_binding.id] = new_binding self.bindings.add(new_binding) def delete_item(self, item): widget = self.studio.selected if widget is None: return widget._event_map_.pop(item.id) self.bindings.remove(item.id) def modify_item(self, value: EventBinding): widget = self.studio.selected widget._event_map_[value.id] = value def on_select(self, widget): if widget is None: self._show_empty(self.NO_SELECTION_MSG) return self._remove_empty() bindings = getattr(widget, "_event_map_", {}) values = bindings.values() self.bindings.clear() self.bindings.add(*values) if not values: self._show_empty(self.NO_EVENT_MSG) def start_search(self, *_): if self.studio.selected: super().start_search() def on_search_query(self, query: str): showing = 0 self._remove_empty() self.bindings.hide_all() for item in self.bindings.items: if query in item.value.sequence or query in item.value.handler: item.show() showing += 1 if not showing: self._show_empty(self.NO_MATCH_MSG) def on_search_clear(self): self._remove_empty() self.bindings.hide_all() for item in self.bindings.items: item.show() super().on_search_clear()