def render(self): self.config(height=40) seq_frame = Frame(self, **self.style.highlight) seq_frame.grid(row=0, column=0, sticky="nsew") seq_frame.pack_propagate(False) self.sequence = Entry(seq_frame, **self.style.input) self.sequence.place(x=0, y=0, relwidth=1, relheight=1, width=-40) self.sequence.set(self.value.sequence) self.sequence.configure(**self.style.no_highlight) self.sequence.focus_set() self.handler = Entry(self, **self.style.input) self.handler.grid(row=0, column=1, sticky="ew") self.handler.set(self.value.handler) self.handler.config(**self.style.highlight) self.add_arg = Checkbutton(self, **self.style.checkbutton) self.add_arg.grid(row=0, column=2, sticky="ew") self.add_arg.set(self.value.add) del_btn = Label(self, **self.style.button, image=get_icon_image("delete", 14, 14)) del_btn.grid(row=0, column=3, sticky='nswe') del_btn.bind("<Button-1>", self._delete_entry) # set the first two columns to expand evenly for column in range(2): self.grid_columnconfigure(column, weight=1, uniform=1) for widget in (self.sequence, self.handler): widget.on_change(self._on_value_change) self.add_arg._var.trace("w", lambda *_: self._on_value_change())
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)