Martin Siebel | 9 Feb 11:55 2012
Picon

ListBox loses focus

Hello,

I am trying to build a GridBox widget, which is similiar to the GridFlow widget, but can be scrolled.

In doing so, I encountered a problem using urwid's ListBox when setting a focus explicitely.
The following code generates a display with 3x5 checkboxes. The focus is explicitely set on the second entry in the third row.
When running this code in a terminal which is large enough to hold the focus without scrolling the list, the focus is set to the first entry in the third row instead of the second.
When the terminal is small enough not to hold the focus without scrolling, the focus is set properly.

I could trace the problem back to the render method of the ListBox, which explicitely alters the focus of the contained Columns object.
(See the second code snippet and the corresponding output).
Is this a bug in the ListBox or am I doing something wrong when setting the focus?

Any help would be appreciated!
Best regards.

Snippet 1:
######################################################################################
#! /usr/bin/python                                                                                                                                                              &nb sp;                   
import urwid
import random

palette = [('header', 'white', 'dark red', "", "#afd", "#f0f"),
           ('footer', 'black', 'light blue', "", "#6f0", "#d00"),
           ('reveal focus', 'dark green', 'yellow', "", "#fd0", "#808"),
           ('body', 'yellow', 'dark green', 'standout', "#808", "#fd0"),
           ('edit', 'black', 'light gray', "", "#f0f", "#afd")]

buttons = [urwid.AttrMap(urwid.CheckBox(k), None, 'reveal focus')
           for k in ["%d %s" % (i, j)
                     for i, j in
                     enumerate(sorted(["".join([chr(random.randint(97, 122))
                                                for x in range(
                                                       random.randint(4, 16))])
                                       for j in range(15)]))]]
body = urwid.ListBox(urwid.SimpleListWalker([urwid.Columns(buttons[3*i:3*i+3])
                                             for i in range(len(buttons)/3)]))
body.set_focus(2)
body.get_focus()[0].set_focus(1)
loop = urwid.MainLoop(body, palette)
loop.screen.set_terminal_properties(colors=256)
loop.run()

Snippet 2:
########################################################################
#! /usr/bin/python                                                                                                                                                              &nb sp;                   
import urwid
import random
import sys
from math import log10
palette = [('header', 'white', 'dark red', "", "#afd", "#f0f"),
           ('footer', 'black', 'light blue', "", "#6f0", "#d00"),
           ('reveal focus', 'dark green', 'yellow', "", "#fd0", "#808"),
           ('body', 'yellow', 'dark green', 'standout', "#808", "#fd0"),
           ('edit', 'black', 'light gray', "", "#f0f", "#afd")]

def log(txt):
    import time
    f = open("/tmp/gridbox.log", "a")
    f.write("%s: %s\n" % (time.strftime("%H:%M:%S"), txt))
    f.close()

class MyListBox(urwid.ListBox):
    def __init__(self, *args, **kwargs):
        urwid.ListBox.__init__(self, *args, **kwargs)
    def render(self, *args, **kwargs):
        log("BEFORE RENDER:")
        for i in self.body:
            l = [j.original_widget for j in i.widget_list]
            log("row %d: [%s], focus is on %d" % (id(i),
                                                  ", ".join([str(id(j)) for j in l]),
                                                  i.get_focus_column()))

        retval = super(MyListBox, self).render(*args, **kwargs)
        log("AFTER RENDER:")
        for i in self.body:
            l = [j.base_widget for j in i.widget_list]
            log("row %d: [%s], focus is on %d" % (id(i),
                                                  ", ".join([str(id(j)) for j in l]),
                                                  i.get_focus_column()))

        return retval

buttons = [urwid.AttrMap(urwid.CheckBox(k), None, 'reveal focus')
           for k in ["%d %s" % (i, j)
                     for i, j in
                     enumerate(sorted(["".join([chr(random.randint(97, 122))
                                                for x in range(random.randint(4, 16))])
                                       for j in range(15)]))]]
body = MyListBox(urwid.SimpleListWalker([urwid.Columns(buttons[3*i:3*i+3])
                                         for i in range(len(buttons)/3)]))
body.set_focus(2)
body.get_focus()[0].set_focus(1)
loop = urwid.MainLoop(body, palette)
loop.screen.set_terminal_properties(colors=256)
loop.run()

Output of snippet 2:
11:51:44: BEFORE RENDER:
11:51:44: row 35364944: [35360976, 35361296, 35361552], focus is on 0
11:51:44: row 35365008: [35361808, 35362064, 35362320], focus is on 0
11:51:44: row 35365072: [35362576, 35362832, 35363088], focus is on 1
11:51:44: row 35365136: [35363344, 35363600, 35363856], focus is on 0
11:51:44: row 35365200: [35364112, 35364368, 35364624], focus is on 0
11:51:44: AFTER RENDER:
11:51:44: row 35364944: [35360976, 35361296, 35361552], focus is on 0
11:51:44: row 35365008: [35361808, 35362064, 35362320], focus is on 0
11:51:44: row 35365072: [35362576, 35362832, 35363088], focus is on 0
11:51:44: row 35365136: [35363344, 35363600, 35363856], focus is on 0
11:51:44: row 35365200: [35364112, 35364368, 35364624], focus is on 0



_______________________________________________
Urwid mailing list
Urwid <at> lists.excess.org
http://lists.excess.org/mailman/listinfo/urwid
Ian Ward | 13 Feb 16:48 2012

Re: ListBox loses focus

Good find.


So, the reason for this is that ListBox is trying very hard to maintain the screen column from its initial selected item (the first Columns) and the one you switched focus to.  This is because commonly the focus changes as a result of the user pressing up/down.

This screen column isn't set until the ListBox knows its own size (such as when render() is called) and when it does it doesn't know that it is clobbering a setting that you wanted to take precedence.  All this code is in ListBox._set_focus_complete() if you want to take a look.

ListBox.set_focus() should probably set a flag that indicates not to try and maintain the screen column when _set_focus_complete is eventually called.

Ian

On Thu, Feb 9, 2012 at 6:55 PM, Martin Siebel <lonequestor <at> yahoo.de> wrote:
Hello,

I am trying to build a GridBox widget, which is similiar to the GridFlow widget, but can be scrolled.

In doing so, I encountered a problem using urwid's ListBox when setting a focus explicitely.
The following code generates a display with 3x5 checkboxes. The focus is explicitely set on the second entry in the third row.
When running this code in a terminal which is large enough to hold the focus without scrolling the list, the focus is set to the first entry in the third row instead of the second.
When the terminal is small enough not to hold the focus without scrolling, the focus is set properly.

I could trace the problem back to the render method of the ListBox, which explicitely alters the focus of the contained Columns object.
(See the second code snippet and the corresponding output).
Is this a bug in the ListBox or am I doing something wrong when setting the focus?

Any help would be appreciated!
Best regards.

Snippet 1:
######################################################################################
#! /usr/bin/python                                                                                                                                                              &nb sp;                   
import urwid
import random

palette = [('header', 'white', 'dark red', "", "#afd", "#f0f"),
           ('footer', 'black', 'light blue', "", "#6f0", "#d00"),
           ('reveal focus', 'dark green', 'yellow', "", "#fd0", "#808"),
           ('body', 'yellow', 'dark green', 'standout', "#808", "#fd0"),
           ('edit', 'black', 'light gray', "", "#f0f", "#afd")]

buttons = [urwid.AttrMap(urwid.CheckBox(k), None, 'reveal focus')
           for k in ["%d %s" % (i, j)
                     for i, j in
                     enumerate(sorted(["".join([chr(random.randint(97, 122))
                                                for x in range(
                                                       random.randint(4, 16))])
                                       for j in range(15)]))]]
body = urwid.ListBox(urwid.SimpleListWalker([urwid.Columns(buttons[3*i:3*i+3])
                                             for i in range(len(buttons)/3)]))
body.set_focus(2)
body.get_focus()[0].set_focus(1)
loop = urwid.MainLoop(body, palette)
loop.screen.set_terminal_properties(colors=256)
loop.run()

Snippet 2:
########################################################################
#! /usr/bin/python                                                                                                                                                              &nb sp;                   
import urwid
import random
import sys
from math import log10
palette = [('header', 'white', 'dark red', "", "#afd", "#f0f"),
           ('footer', 'black', 'light blue', "", "#6f0", "#d00"),
           ('reveal focus', 'dark green', 'yellow', "", "#fd0", "#808"),
           ('body', 'yellow', 'dark green', 'standout', "#808", "#fd0"),
           ('edit', 'black', 'light gray', "", "#f0f", "#afd")]

def log(txt):
    import time
    f = open("/tmp/gridbox.log", "a")
    f.write("%s: %s\n" % (time.strftime("%H:%M:%S"), txt))
    f.close()

class MyListBox(urwid.ListBox):
    def __init__(self, *args, **kwargs):
        urwid.ListBox.__init__(self, *args, **kwargs)
    def render(self, *args, **kwargs):
        log("BEFORE RENDER:")
        for i in self.body:
            l = [j.original_widget for j in i.widget_list]
            log("row %d: [%s], focus is on %d" % (id(i),
                                                  ", ".join([str(id(j)) for j in l]),
                                                  i.get_focus_column()))

        retval = super(MyListBox, self).render(*args, **kwargs)
        log("AFTER RENDER:")
        for i in self.body:
            l = [j.base_widget for j in i.widget_list]
            log("row %d: [%s], focus is on %d" % (id(i),
                                                  ", ".join([str(id(j)) for j in l]),
                                                  i.get_focus_column()))

        return retval

buttons = [urwid.AttrMap(urwid.CheckBox(k), None, 'reveal focus')
           for k in ["%d %s" % (i, j)
                     for i, j in
                     enumerate(sorted(["".join([chr(random.randint(97, 122))
                                                for x in range(random.randint(4, 16))])
                                       for j in range(15)]))]]
body = MyListBox(urwid.SimpleListWalker([urwid.Columns(buttons[3*i:3*i+3])
                                         for i in range(len(buttons)/3)]))
body.set_focus(2)
body.get_focus()[0].set_focus(1)
loop = urwid.MainLoop(body, palette)
loop.screen.set_terminal_properties(colors=256)
loop.run()

Output of snippet 2:
11:51:44: BEFORE RENDER:
11:51:44: row 35364944: [35360976, 35361296, 35361552], focus is on 0
11:51:44: row 35365008: [35361808, 35362064, 35362320], focus is on 0
11:51:44: row 35365072: [35362576, 35362832, 35363088], focus is on 1
11:51:44: row 35365136: [35363344, 35363600, 35363856], focus is on 0
11:51:44: row 35365200: [35364112, 35364368, 35364624], focus is on 0
11:51:44: AFTER RENDER:
11:51:44: row 35364944: [35360976, 35361296, 35361552], focus is on 0
11:51:44: row 35365008: [35361808, 35362064, 35362320], focus is on 0
11:51:44: row 35365072: [35362576, 35362832, 35363088], focus is on 0
11:51:44: row 35365136: [35363344, 35363600, 35363856], focus is on 0
11:51:44: row 35365200: [35364112, 35364368, 35364624], focus is on 0




_______________________________________________
Urwid mailing list
Urwid <at> lists.excess.org
http://lists.excess.org/mailman/listinfo/urwid


_______________________________________________
Urwid mailing list
Urwid <at> lists.excess.org
http://lists.excess.org/mailman/listinfo/urwid
Martin Siebel | 14 Feb 11:03 2012
Picon

Re: ListBox loses focus

Hello Ian,

thanks for the fast help. I looked already into the _set_focus_complete code once, but could not really see what path is executed under which conditions (pending focusses etc.).

I was not aware that the change in focus occurs only before the size of the ListBox is known. Knowing this I, can just make a call to ListBox.render() in my widgetWrapper.render() before setting the focus and returning the actual ListBox.render() result.
I just tried it, it seems to work just fine.

Thank you!
Martin

Von: Ian Ward <ian <at> excess.org>
An: Martin Siebel <lonequestor <at> yahoo.de>; Urwid General Discussion <urwid <at> lists.excess.org>
Gesendet: 16:48 Montag, 13.Februar 2012
Betreff: Re: [Urwid] ListBox loses focus

Good find.

So, the reason for this is that ListBox is trying very hard to maintain the screen column from its initial selected item (the first Columns) and the one you switched focus to.  This is because commonly the focus changes as a result of the user pressing up/down.

This screen column isn't set until the ListBox knows its own size (such as when render() is called) and when it does it doesn't know that it is clobbering a setting that you wanted to take precedence.  All this code is in ListBox._set_focus_complete() if you want to take a look.

ListBox.set_focus() should probably set a flag that indicates not to try and maintain the screen column when _set_focus_complete is eventually called.

Ian

On Thu, Feb 9, 2012 at 6:55 PM, Martin Siebel <lonequestor <at> yahoo.de> wrote:
Hello,

I am trying to build a GridBox widget, which is similiar to the GridFlow widget, but can be scrolled.

In doing so, I encountered a problem using urwid's ListBox when setting a focus explicitely.
The following code generates a display with 3x5 checkboxes. The focus is explicitely set on the second entry in the third row.
When running this code in a terminal which is large enough to hold the focus without scrolling the list, the focus is set to the first entry in the third row instead of the second.
When the terminal is small enough not to hold the focus without scrolling, the focus is set properly.

I could trace the problem back to the render method of the ListBox, which explicitely alters the focus of the contained Columns object.
(See the second code snippet and the corresponding output).
Is this a bug in the ListBox or am I doing something wrong when setting the focus?

Any help would be appreciated!
Best regards.

Snippet 1:
######################################################################################
#! /usr/bin/python                                                                                                                                                              &am p;nb sp;                   
import urwid
import random

palette = [('header', 'white', 'dark red', "", "#afd", "#f0f"),
           ('footer', 'black', 'light blue', "", "#6f0", "#d00"),
           ('reveal focus', 'dark green', 'yellow', "", "#fd0", "#808"),
           ('body', 'yellow', 'dark green', 'standout', "#808", "#fd0"),
           ('edit', 'black', 'light gray', "", "#f0f", "#afd")]

buttons = [urwid.AttrMap(urwid.CheckBox(k), None, 'reveal focus')
           for k in ["%d %s" % (i, j)
                     for i, j in
                     enumerate(sorted(["".join([chr(random.randint(97, 122))
                                                for x in range(
                                                       random.randint(4, 16))])
                                       for j in range(15)]))]]
body = urwid.ListBox(urwid.SimpleListWalker([urwid.Columns(buttons[3*i:3*i+3])
                                             for i in range(len(buttons)/3)]))
body.set_focus(2)
body.get_focus()[0].set_focus(1)
loop = urwid.MainLoop(body, palette)
loop.screen.set_terminal_properties(colors=256)
loop.run()

Snippet 2:
########################################################################
#! /usr/bin/python                                                                                                                                                              &am p;nb sp;                   
import urwid
import random
import sys
from math import log10
palette = [('header', 'white', 'dark red', "", "#afd", "#f0f"),
           ('footer', 'black', 'light blue', "", "#6f0", "#d00"),
           ('reveal focus', 'dark green', 'yellow', "", "#fd0", "#808"),
           ('body', 'yellow', 'dark green', 'standout', "#808", "#fd0"),
           ('edit', 'black', 'light gray', "", "#f0f", "#afd")]

def log(txt):
    import time
    f = open("/tmp/gridbox.log", "a")
    f.write("%s: %s\n" % (time.strftime("%H:%M:%S"), txt))
    f.close()

class MyListBox(urwid.ListBox):
    def __init__(self, *args, **kwargs):
        urwid.ListBox.__init__(self, *args, **kwargs)
    def render(self, *args, **kwargs):
        log("BEFORE RENDER:")
        for i in self.body:
            l = [j.original_widget for j in i.widget_list]
            log("row %d: [%s], focus is on %d" % (id(i),
                                                  ", ".join([str(id(j)) for j in l]),
                                                  i.get_focus_column()))

        retval = super(MyListBox, self).render(*args, **kwargs)
        log("AFTER RENDER:")
        for i in self.body:
            l = [j.base_widget for j in i.widget_list]
            log("row %d: [%s], focus is on %d" % (id(i),
                                                  ", ".join([str(id(j)) for j in l]),
                                                  i.get_focus_column()))

        return retval

buttons = [urwid.AttrMap(urwid.CheckBox(k), None, 'reveal focus')
           for k in ["%d %s" % (i, j)
                     for i, j in
                     enumerate(sorted(["".join([chr(random.randint(97, 122))
                                                for x in range(random.randint(4, 16))])
                                       for j in range(15)]))]]
body = MyListBox(urwid.SimpleListWalker([urwid.Columns(buttons[3*i:3*i+3])
                                         for i in range(len(buttons)/3)]))
body.set_focus(2)
body.get_focus()[0].set_focus(1)
loop = urwid.MainLoop(body, palette)
loop.screen.set_terminal_properties(colors=256)
loop.run()

Output of snippet 2:
11:51:44: BEFORE RENDER:
11:51:44: row 35364944: [35360976, 35361296, 35361552], focus is on 0
11:51:44: row 35365008: [35361808, 35362064, 35362320], focus is on 0
11:51:44: row 35365072: [35362576, 35362832, 35363088], focus is on 1
11:51:44: row 35365136: [35363344, 35363600, 35363856], focus is on 0
11:51:44: row 35365200: [35364112, 35364368, 35364624], focus is on 0
11:51:44: AFTER RENDER:
11:51:44: row 35364944: [35360976, 35361296, 35361552], focus is on 0
11:51:44: row 35365008: [35361808, 35362064, 35362320], focus is on 0
11:51:44: row 35365072: [35362576, 35362832, 35363088], focus is on 0
11:51:44: row 35365136: [35363344, 35363600, 35363856], focus is on 0
11:51:44: row 35365200: [35364112, 35364368, 35364624], focus is on 0




_______________________________________________
Urwid mailing list
Urwid <at> lists.excess.org
http://lists.excess.org/mailman/listinfo/urwid




_______________________________________________
Urwid mailing list
Urwid <at> lists.excess.org
http://lists.excess.org/mailman/listinfo/urwid
Andrew Wu | 15 Feb 09:24 2012
Picon

MainLoop.remove_watch_pipe doesn't work?

Hello,

I tried to call MainLoop.remove_watch_pipe, but it doesn't work:

####

import urwid

txt = urwid.Text(u"Hello World")
fill = urwid.Filler(txt, 'top')
loop = urwid.MainLoop(fill)

def callback(data):
    pass

fd = loop.watch_pipe(callback)
loop.remove_watch_pipe(fd)

loop.run()

####

I got error message:

Traceback (most recent call last):
  File "t.py", line 11, in <module>
    loop.remove_watch_pipe(fd)
  File "/home/Andrew Wu/urwid/main_loop.py", line 205, in remove_watch_pipe
    watch_handle, pipe_rd = self._watch_pipes.remove(write_fd)
AttributeError: 'dict' object has no attribute 'remove'


_______________________________________________
Urwid mailing list
Urwid <at> lists.excess.org
http://lists.excess.org/mailman/listinfo/urwid

Gmane