Container inspired by Overlay to position our tooltip. bottom_w should be a BoxWidget. The top window currently has to be a listbox to support shrinkwrapping. This passes keyboard events to the bottom instead of the top window. It also positions the top window relative to the curs
| 444 | |
| 445 | |
| 446 | class Tooltip(urwid.BoxWidget): |
| 447 | """Container inspired by Overlay to position our tooltip. |
| 448 | |
| 449 | bottom_w should be a BoxWidget. |
| 450 | The top window currently has to be a listbox to support shrinkwrapping. |
| 451 | |
| 452 | This passes keyboard events to the bottom instead of the top window. |
| 453 | |
| 454 | It also positions the top window relative to the cursor position |
| 455 | from the bottom window and hides it if there is no cursor. |
| 456 | """ |
| 457 | |
| 458 | def __init__(self, bottom_w, listbox): |
| 459 | super().__init__() |
| 460 | |
| 461 | self.bottom_w = bottom_w |
| 462 | self.listbox = listbox |
| 463 | # TODO: this linebox should use the 'main' color. |
| 464 | self.top_w = urwid.LineBox(listbox) |
| 465 | self.tooltip_focus = False |
| 466 | |
| 467 | def selectable(self): |
| 468 | return self.bottom_w.selectable() |
| 469 | |
| 470 | def keypress(self, size, key): |
| 471 | return self.bottom_w.keypress(size, key) |
| 472 | |
| 473 | def mouse_event(self, size, event, button, col, row, focus): |
| 474 | # TODO: pass to top widget if visible and inside it. |
| 475 | if not hasattr(self.bottom_w, "mouse_event"): |
| 476 | return False |
| 477 | |
| 478 | return self.bottom_w.mouse_event(size, event, button, col, row, focus) |
| 479 | |
| 480 | def get_cursor_coords(self, size): |
| 481 | return self.bottom_w.get_cursor_coords(size) |
| 482 | |
| 483 | def render(self, size, focus=False): |
| 484 | maxcol, maxrow = size |
| 485 | bottom_c = self.bottom_w.render(size, focus) |
| 486 | cursor = bottom_c.cursor |
| 487 | if not cursor: |
| 488 | # Hide the tooltip if there is no cursor. |
| 489 | return bottom_c |
| 490 | |
| 491 | cursor_x, cursor_y = cursor |
| 492 | if cursor_y * 2 < maxrow: |
| 493 | # Cursor is in the top half. Tooltip goes below it: |
| 494 | y = cursor_y + 1 |
| 495 | rows = maxrow - y |
| 496 | else: |
| 497 | # Cursor is in the bottom half. Tooltip fills the area above: |
| 498 | y = 0 |
| 499 | rows = cursor_y |
| 500 | |
| 501 | # HACK: shrink-wrap the tooltip. This is ugly in multiple ways: |
| 502 | # - It only works on a listbox. |
| 503 | # - It assumes the wrapping LineBox eats one char on each edge. |