Change button label on screen redraw urwid

572 views Asked by At

In urwid, is there a way for child widgets to change their attributes based on screen redraw actions?

Specifically, if I have a button widget with some very long string:

mybutton = urwid.Button(<some very long string>)

Is there a way for the button to display only part of the string when the terminal is re-sized to a column width less than the length of the string? Equivalent to:

mybutton = urwid.Button(<some very long...>)

As it is now, urwid attempts to wrap the button label, which looks ugly in the context of my interface.

1

There are 1 answers

0
Elias Dorneles On

I think the easiest way to achieve this is to implement this behavior as a custom widget, which wraps the vanilla urwid.Button but forcing it to render always in only one row -- here is a fully working example:

from __future__ import print_function, absolute_import, division
import urwid    

class MyButton(urwid.WidgetWrap):
    def __init__(self, *args, **kw):
        self.button = urwid.Button(*args, **kw)
        super(MyButton, self).__init__(self.button)

    def rows(self, *args, **kw):
        return 1

    def render(self, size, *args, **kw):
        cols = size[0]
        maxsize = cols - 4  # buttons use 4 chars to draw < > borders
        if len(self.button.label) > maxsize:
            new_label = self.button.label[:maxsize - 3] + '...'
            self.button.set_label(new_label)
        return super(MyButton, self).render(size, *args, **kw)


def show_or_exit(key):
    if key in ('q', 'Q', 'esc'):
        raise urwid.ExitMainLoop()    


if __name__ == '__main__':
    # demo:
    widget = urwid.Pile([
        urwid.Text('Some buttons using urwid vanilla urwid.Button widget:\n'),
        urwid.Button('Here is a little button with really a really long string for label, such that it can be used to try out a problem described in Stackoverflow question'),
        urwid.Button('And here is another button, also with a really really long string for label, for the same reason as the previous one'),
        urwid.Button('And a short one'),
        urwid.Text('\n\n\nSame buttons, with a custom button widget:\n'),
        MyButton('Here is a little button with really a really long string for label, such that it can be used to try out a problem described in Stackoverflow question'),
        MyButton('And here is another button, also with a really really long string for label, for the same reason as the previous one'),
        MyButton('And a short one'),
        urwid.Columns([
            MyButton('Here is a little button with really a really long string for label, such that it can be used to try out a problem described in Stackoverflow question'),
            MyButton('And here is another button, also with a really really long string for label, for the same reason as the previous one'),
        ]),
    ])
    widget = urwid.Filler(widget, 'top')
    loop = urwid.MainLoop(widget, unhandled_input=show_or_exit)
    loop.run()

Learn more