Mini Shell

Direktori : /proc/self/root/opt/sharedrads/python/
Upload File :
Current File : //proc/self/root/opt/sharedrads/python/picker.py

#!/opt/imh-python/bin/python3

# hi, this routine isn't licensed. but credit would be nice somewhere.
# See http://pp19dd.com/2013/11/simple-python-list-picker-using-curses/

# usage:
# opts = Picker(
#    title = 'Delete all files',
#    options = ["Yes", "No"]
# ).get_selected()

# returns a simple list
# cancel returns False

import curses


class Picker:
    """Allows you to select from a list with curses"""

    stdscr = None
    win = None
    title = ""
    arrow = ""
    footer = ""
    more = ""
    c_selected = ""
    c_empty = ""

    cursor = 0
    offset = 0
    selected = 0
    selcount = 0
    aborted = False

    window_height = 15
    window_width = 60
    all_options = []
    length = 0

    def curses_start(self):
        self.stdscr = curses.initscr()
        curses.noecho()
        curses.cbreak()
        self.win = curses.newwin(
            5 + self.window_height, self.window_width, 2, 4
        )

    def curses_stop(self):
        curses.nocbreak()
        self.stdscr.keypad(0)
        curses.echo()
        curses.endwin()

    def get_selected(self):
        if self.aborted:
            return False

        ret_s = [x for x in self.all_options if x["selected"]]
        ret = [x["label"] for x in ret_s]
        return ret

    def redraw(self):
        self.win.clear()
        self.win.border(
            self.border[0],
            self.border[1],
            self.border[2],
            self.border[3],
            self.border[4],
            self.border[5],
            self.border[6],
            self.border[7],
        )
        self.win.addstr(self.window_height + 4, 5, " " + self.footer + " ")

        position = 0
        option_range = self.all_options[
            self.offset : self.offset + self.window_height + 1
        ]
        for option in option_range:
            if option["selected"]:
                line_label = self.c_selected + " "
            else:
                line_label = self.c_empty + " "

            self.win.addstr(position + 2, 5, line_label + option["label"])
            position = position + 1

        # hint for more content above
        if self.offset > 0:
            self.win.addstr(1, 5, self.more)

        # hint for more content below
        if self.offset + self.window_height <= self.length - 2:
            self.win.addstr(self.window_height + 3, 5, self.more)

        self.win.addstr(0, 5, " " + self.title + " ")
        self.win.addstr(
            0,
            self.window_width - 8,
            " " + str(self.selcount) + "/" + str(self.length) + " ",
        )
        self.win.addstr(self.cursor + 2, 1, self.arrow)
        self.win.refresh()

    def check_cursor_up(self):
        if self.cursor < 0:
            self.cursor = 0
            if self.offset > 0:
                self.offset = self.offset - 1

    def check_cursor_down(self):
        if self.cursor >= self.length:
            self.cursor = self.cursor - 1

        if self.cursor > self.window_height:
            self.cursor = self.window_height
            self.offset = self.offset + 1

            if self.offset + self.cursor >= self.length:
                self.offset = self.offset - 1

    def curses_loop(self, stdscr):
        while 1:
            self.redraw()
            char = stdscr.getch()

            if char == ord('q') or char == ord('Q'):
                self.aborted = True
                break
            if char == curses.KEY_UP:
                self.cursor = self.cursor - 1
            elif char == curses.KEY_DOWN:
                self.cursor = self.cursor + 1
            # elif c == curses.KEY_PPAGE:
            # elif c == curses.KEY_NPAGE:
            elif char == ord(' '):
                self.all_options[self.selected][
                    "selected"
                ] = not self.all_options[self.selected]["selected"]
            elif char == 10:
                break

            # deal with interaction limits
            self.check_cursor_up()
            self.check_cursor_down()

            # compute selected position only after dealing with limits
            self.selected = self.cursor + self.offset

            temp = self.get_selected()
            self.selcount = len(temp)

    def __init__(
        self,
        options,
        title='Select',
        arrow="-->",
        footer="Space = toggle, Enter = accept, q = cancel",
        more="...",
        border="||--++++",
        c_selected="[X]",
        c_empty="[ ]",
    ):
        self.title = title
        self.arrow = arrow
        self.footer = footer
        self.more = more
        self.border = border
        self.c_selected = c_selected
        self.c_empty = c_empty

        self.all_options = []

        for option in options:
            self.all_options.append({"label": option, "selected": False})
            self.length = len(self.all_options)

        self.curses_start()
        curses.wrapper(self.curses_loop)
        self.curses_stop()

Zerion Mini Shell 1.0