@@ -187,17 +187,21 @@ class Tooltip(urwid.BoxWidget):
187187
188188 """Container inspired by Overlay to position our tooltip.
189189
190+ bottom_w should be a BoxWidget.
191+ The top window currently has to be a listbox to support shrinkwrapping.
192+
190193 This passes keyboard events to the bottom instead of the top window.
191194
192195 It also positions the top window relative to the cursor position
193196 from the bottom window and hides it if there is no cursor.
194197 """
195198
196- def __init__ (self , bottom_w , top_w ):
199+ def __init__ (self , bottom_w , listbox ):
197200 self .__super .__init__ ()
198201
199202 self .bottom_w = bottom_w
200- self .top_w = top_w
203+ self .listbox = listbox
204+ self .top_w = urwid .LineBox (listbox )
201205
202206 def selectable (self ):
203207 return self .bottom_w .selectable ()
@@ -224,7 +228,6 @@ def render(self, size, focus=False):
224228 # Hide the tooltip if there is no cursor.
225229 return bottom_c
226230
227- # TODO: deal with the tooltip not needing all the space we have.
228231 cursor_x , cursor_y = cursor
229232 if cursor_y * 2 < maxrow :
230233 # Cursor is in the top half. Tooltip goes below it:
@@ -234,6 +237,20 @@ def render(self, size, focus=False):
234237 # Cursor is in the bottom half. Tooltip fills the area above:
235238 y = 0
236239 rows = cursor_y
240+
241+ # HACK: shrink-wrap the tooltip. This is ugly in multiple ways:
242+ # - It only works on a listbox.
243+ # - It assumes the wrapping LineBox eats one char on each edge.
244+ # - It is a loop.
245+ # (ideally it would check how much free space there is,
246+ # instead of repeatedly trying smaller sizes)
247+ while 'bottom' in self .listbox .ends_visible ((maxcol - 2 , rows - 3 )):
248+ rows -= 1
249+
250+ # If we're displaying above the cursor move the top edge down:
251+ if not y :
252+ y = cursor_y - rows
253+
237254 # The top window never gets focus.
238255 top_c = self .top_w .render ((maxcol , rows ))
239256
@@ -469,7 +486,7 @@ def main(args=None, locals_=None, banner=None):
469486 tooltip = urwid .ListBox (urwid .SimpleListWalker ([
470487 urwid .Text ('' ), urwid .Text ('' ), urwid .Text ('' )]))
471488 # TODO: this linebox should use the 'main' color.
472- overlay = Tooltip (listbox , urwid . LineBox ( tooltip ) )
489+ overlay = Tooltip (listbox , tooltip )
473490
474491 frame = urwid .Frame (overlay , footer = statusbar .widget )
475492
0 commit comments