[elbe-devel] [PATCH 01/14] Debianize - TUI

Bastian Germann bage at linutronix.de
Thu Aug 1 14:44:04 CEST 2019


> From: Olivier Dion <dion at linutronix.de>
> 
> The TUI uses the Urwid package, see <http://urwid.org/>.
> 
> The code is copy-paste from one of my previous collaborate project
> with a friend at <https://github.com/abelfodil/inf1900-grader> and is
> under GPL-3.

In the file headers you say GPL-3.0-or-later which should be the license
for elbe but there is nothing in your project that states the GPL
version. You should ask the other authors if we can use it with the GPL
"or later" clause to identify the GPL version. Otherwise (if it is not
"or later") we cannot use the code in Elbe.

> 
> I've also made some modifications to fits the debianizer needs.

fit

> 
> * TUI
> 
>   The TUI is a singleton object that control the terminal.  It divides

controls

>   it in 3 sections.  The header, the body and the footer.  Is also
>   install signal handler to ensure proper restoration of the terminal

It also installs a signal handler...

>   settings.
> 
> ** Header
> 
>    The header is a Text widget.  It's manipulated through the
>    TUI.print and TUI.clear method.
> 
> *** TUI.print
> 
>     Print a formatted text to the header.  The previous text is
>     overwritten.
> 
> *** TUI.clear
> 
>     Clear the header.
> 
> ** Footer
> 
>    The footer is a Text widget.  It's not intend to be manipulated.
>    It only show usefull keybinding to the user.

It only shows useful ...

> 
> ** Body
> 
>    The body can be anything.  It's the main view of the application.
> 
> Signed-off-by: Olivier Dion <dion at linutronix.de>
> ---
>  elbepack/debianize/base/tui.py | 181 +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 181 insertions(+)
>  create mode 100644 elbepack/debianize/base/tui.py
> 
> diff --git a/elbepack/debianize/base/tui.py b/elbepack/debianize/base/tui.py
> new file mode 100644
> index 00000000..1b4cdeec
> --- /dev/null
> +++ b/elbepack/debianize/base/tui.py
> @@ -0,0 +1,181 @@
> +# ELBE - Debian Based Embedded Rootfilesystem Builder
> +# Copyright (c) 2019 Olivier Dion <dion at linutronix.de>
> +#
> +# SPDX-License-Identifier: GPL-3.0-or-later
> +
> +
> +import os
> +import signal
> +
> +from urwid import (
> +    ExitMainLoop,
> +    Frame,
> +    MainLoop,
> +    Text
> +)
> +
> +
> +# +=====================================================+
> +# |+-: root (box) -------------------------------------+|
> +# ||+-: header (flow) --------------------------------+||
> +# |||                                                 |||
> +# ||+-------------------------------------------------+||
> +# ||+-: body (box) -----------------------------------+||
> +# |||                                                 |||
> +# |||                                                 |||
> +# |||                                                 |||
> +# |||                                                 |||
> +# |||                                                 |||
> +# |||                                                 |||
> +# |||                                                 |||
> +# |||                                                 |||
> +# |||                                                 |||
> +# |||                                                 |||
> +# ||+-------------------------------------------------+||
> +# ||+-: helper (flow) --------------------------------+||
> +# |||                                                 | |
> +# ||+-------------------------------------------------+||
> +# |+---------------------------------------------------+|
> +# +=====================================================+
> +
> +
> +def generate_helper_text(hints):
> +    markup = []
> +    for key, text, text_palette in hints:
> +        markup.extend((("helper_key", key), " ", (text_palette, text), " "))
> +    return markup
> +
> +
> +class TUIException(Exception):
> +    pass
> +
> +
> +class TUI(object):
> +
> +    palette = [
> +        ("blue_head", "dark blue", ""),
> +        ("red_head", "dark red", ""),
> +        ("header", "bold, underline, default", ""),
> +        ("error", "bold, light red", ""),
> +        ("normal_box", "default", "default"),
> +        ("selected_box", "black", "light gray"),
> +        ("confirm_button", "default", "dark green"),
> +        ("abort_button", "light red", "dark red"),
> +        ("progress_low", "default", "yellow"),
> +        ("progress_hight", "default", "dark green"),
> +        ("helper_key", "bold", "default"),
> +        ("helper_text_brown", "black", "brown"),
> +        ("helper_text_red", "black", "dark red"),
> +        ("helper_text_green", "black", "dark green"),
> +        ("helper_text_light", "white", "dark blue"),
> +    ]
> +
> +    main_helper_text = generate_helper_text([
> +        ("C-f", "Forward", "helper_text_brown"),
> +        ("C-b", "Backward", "helper_text_brown"),
> +        ("C-p", "Previous", "helper_text_brown"),
> +        ("C-n", "Next", "helper_text_brown"),
> +        ("TAB", "Next", "helper_text_brown"),
> +        ("backtab", "Previous", "helper_text_brown"),
> +        ("C-\\", "Quit", "helper_text_red"),
> +    ])
> +
> +    keybind = {}
> +
> +    def __init__(self, body):
> +
> +        TUI.root = Frame(body.root,
> +                         Text(("header", ""), "center"),
> +                         Text(TUI.main_helper_text, "center"))
> +
> +        TUI.loop = MainLoop(TUI.root, TUI.palette,
> +                            unhandled_input=TUI.unhandled_input)
> +
> +        TUI.install_signals_handler()
> +
> +    def __call__(self):
> +        TUI.loop.run()
> +
> +    @classmethod
> +    def focus_header(cls):
> +        cls.root.focus_position = "header"
> +
> +    @classmethod
> +    def focus_body(cls):
> +        cls.root.focus_position = "body"
> +
> +    @classmethod
> +    def focus_footer(cls):
> +        cls.root.focus_position = "footer"
> +
> +    @classmethod
> +    def header(cls, flow_widget=None):
> +        if flow_widget is not None:
> +            if "flow" not in flow_widget.sizing():
> +                raise TUIException("Header must be of sizing flow")
> +            cls.root.contents["header"] = flow_widget
> +        return cls.root.contents["header"]
> +
> +    @classmethod
> +    def body(cls, box_widget=None):
> +        if box_widget is not None:
> +            if "box" not in box_widget.sizing():
> +                raise TUIException("Body must be of sizing box")
> +            cls.root.contents["body"] = (box_widget, TUI.root.options())
> +        return cls.root.contents["body"]
> +
> +    @classmethod
> +    def footer(cls, flow_widget=None):
> +        if flow_widget is not None:
> +            if "flow" not in flow_widget.sizing():
> +                raise TUIException("Header must be of sizing flow")
> +            cls.root.contents["footer"] = flow_widget
> +        return cls.root.contents["footer"]
> +
> +    @classmethod
> +    def unhandled_input(cls, key):
> +        if key in cls.keybind:
> +            cls.keybind[key]()
> +            return None
> +
> +    @classmethod
> +    def bind_global(cls, key, callback):
> +        cls.keybind[key] = callback
> +
> +    @classmethod
> +    def printf(cls, fmt, *args):
> +        cls.header()[0].set_text(("header", fmt.format(*args)))
> +
> +    @classmethod
> +    def clear(cls):
> +        cls.printf("")
> +
> +    @staticmethod
> +    def quit(*kargs):
> +        raise ExitMainLoop()
> +
> +    @staticmethod
> +    def pause(*kargs):
> +        TUI.loop.stop()
> +        os.kill(os.getpid(), signal.SIGSTOP)
> +        TUI.loop.start()
> +        TUI.loop.draw_screen()
> +
> +    @staticmethod
> +    def interrupt(*kargs):
> +        pass
> +
> +    @staticmethod
> +    def install_signals_handler():
> +
> +        if os.sys.platform != "win32":
> +            signal.signal(signal.SIGQUIT, TUI.quit)
> +            signal.signal(signal.SIGTSTP, TUI.pause)
> +
> +        # TODO - Windows
> +        #
> +        # sys.platform == win32 Should test for
> +        # signal.CTRL_BREAK_EVENT and signal.CTRL_C_EVENT and hook to
> +        # appropriate callback

As windows support is not yet a thing in Elbe, please remove this TODO
section.

> +
> +        signal.signal(signal.SIGINT, TUI.interrupt)
> 

With the changes and after the other authors have agreed on the licensing
Reviewed-by: Bastian Germann <bage at linutronix.de>



More information about the elbe-devel mailing list