pfalcon / picotui

Lightweight, pure-Python Text User Interface (TUI) widget toolkit with minimal dependencies. Dedicated to the Pycopy project.
https://github.com/pfalcon/pycopy
MIT License
811 stars 70 forks source link

Suggestion - add a "disabled" state to all FocusableWidget instances #53

Open qippur opened 3 years ago

qippur commented 3 years ago

Hi, I'd like to share a feature I implemented and hope that it could help someone. I needed a way to disable any interactive widget (e. g. disable a drop down until a checkbox is selected) - this feature seems to be only available for buttons. So, this is what I did.

This is my new FocusableWidget class (added disabled status, disable and enable methods):

class FocusableWidget(Widget):
    # If set to non-False, pressing Enter on this widget finishes
    # dialog, with Dialog.loop() return value being this value.
    finish_dialog = False

    def __init__(self, disabled=False):
        super().__init__()
        self.disabled = disabled

    def enable(self):
        self.disabled = False

    def disable(self):
        self.disabled = True

These are my new find_focusable* methods for Dialog class (added check for disabled status):

    def find_focusable_by_idx(self, from_idx, direction):
        sz = len(self.childs)
        while 0 <= from_idx < sz:
            child = self.childs[from_idx]
            if isinstance(child, FocusableWidget) and not child.disabled:
                return from_idx, child
            from_idx = (from_idx + direction) % sz
        return None, None

    def find_focusable_by_xy(self, x, y):
        i = 0
        for w in self.childs:
            if isinstance(w, FocusableWidget) and w.inside(
                    x, y) and not w.disabled:
                return i, w
            i += 1
        return None, None

And, last, my new change_focus (just added a check for disabled status on top)

    def change_focus(self, widget):
        if widget.disabled:
            return
        if widget is self.focus_w:
            return
        if self.focus_w:
            self.focus_w.focus = False
            self.focus_w.redraw()
        self.focus_w = widget
        widget.focus = True
        widget.redraw()
        widget.set_cursor()
pfalcon commented 3 years ago

Ack. Would be nice to implement those. The changes actually would be more pervasive, as disabled widgets would need to render themselves accordingly. No plans when that would be looked into, there's a queue of other issues so far.