I have had the design of a general way of doing pop-ups with Urwid
rolling around in my head for years, and while I wrote the supporting
canvas handling code I never presented a working pop-up implementation.
Andrew Psaltis reminded me of this on IRC, and so I decided to finally
put an example together. This example works with 0.9.8 and later
versions of Urwid.
The pop-up is implemented in two parts: the PopUpTarget is a box widget
that, in this example, covers the whole screen. This is the area that
pop-ups may appear in. The second part is a custom widget that displays
a pop-up when a button is pressed (press space or enter, I haven't
enabled the mouse in this example yet)
When the pop-up is displayed, try resizing the screen to see how it
behaves. Notice that it seems attached to the originating widget, but
if you shrink the screen enough it will move to try to keep its size intact.
I haven't included this code in Urwid yet because I'm not yet sure I
like the interface. Suggestions are welcome.
Ian
#!/usr/bin/python
import urwid
import urwid.raw_display
class PopUpTarget(urwid.WidgetWrap):
def __init__(self, original_widget):
self.__super.__init__(original_widget)
self._pop_up = None
self._current_widget = self._w
def render(self, size, focus=False):
canv = self._current_widget.render(size, focus=focus)
if 'pop_up' in canv.coords:
x, y, (w, h, widget, set_close) = canv.coords['pop_up']
if not self._pop_up:
self._open_pop_up(x, y, w, h, widget)
set_close(self.close_pop_up)
else:
self._update_pop_up(x, y, w, h)
canv = self._current_widget.render(size, focus=focus)
return canv
def _open_pop_up(self, x, y, w, h, widget):
assert not self._pop_up
self._pop_up = widget
self._update_pop_up(x, y, w, h)
def _update_pop_up(self, x, y, w, h):
self._current_widget = urwid.Overlay(self._pop_up, self._w,
('fixed left', x), w, ('fixed top', y), h)
def close_pop_up(self):
if self._pop_up:
self._pop_up = None
self._current_widget = self._w
self._invalidate()
# use our current widget's methods
selectable = property(lambda self:self._current_widget.selectable)
get_cursor_coords = property(lambda self:self._current_widget.get_cursor_coords)
get_pref_col = property(lambda self:self._current_widget.get_pref_col)
keypress = property(lambda self:self._current_widget.keypress)
move_cursor_to_coords = property(lambda self:self._current_widget.move_cursor_to_coords)
mouse_event = property(lambda self:self._current_widget.mouse_event)
sizing = property(lambda self:self._current_widget.sizing)
class PopUpConfirm(urwid.WidgetWrap):
def __init__(self):
def on_click(button):
self._open_pop_up = True
self._invalidate()
self.__super.__init__(urwid.Button("click-me", on_click))
self._open_pop_up = False
self._pop_up_window = self._create_pop_up()
def _create_pop_up(self):
def on_click(button):
button.do_close()
self._open_pop_up = False
close_button = urwid.Button("confirm", on_click)
def set_close(fn):
close_button.do_close = fn
pile = urwid.Pile([urwid.Text("this is a pop-up"), close_button])
fill = urwid.Filler(pile)
amap = urwid.AttrWrap(fill, 'popbg')
return (30, 4, amap, set_close)
def render(self, size, focus=False):
canv = self.__super.render(size, focus)
if self._open_pop_up:
canv = urwid.CompositeCanvas(canv)
# same left column, one line below ourselves
canv.coords['pop_up'] = (0, 1, self._pop_up_window)
return canv
ui = urwid.raw_display.Screen()
ui.register_palette([('popbg', 'white', 'dark blue')])
def run():
size = ui.get_cols_rows()
fill = urwid.Filler(urwid.Padding(PopUpConfirm(), 'center', 15))
target = PopUpTarget(fill)
while True:
canvas = target.render(size, True)
ui.draw_screen(size, canvas)
keys = ui.get_input()
for k in keys:
target.keypress(size, k)
if "window resize" in keys:
size = ui.get_cols_rows()
ui.run_wrapper(run)
_______________________________________________
Urwid mailing list
[email protected]
http://lists.excess.org/mailman/listinfo/urwid