Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added indicator box to TUI that follows focused pane #303

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 58 additions & 15 deletions toot/tui/timeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
from .entities import Status
from .scroll import Scrollable, ScrollBar
from .utils import highlight_hashtags, parse_datetime, highlight_keys
from .widgets import SelectableText, SelectableColumns
from .widgets import SelectableText, SelectableColumns, StatusList
from toot.utils import format_content
from toot.utils.language import language_name
from toot.tui.utils import time_ago
from urwid.util import is_mouse_press

logger = logging.getLogger("toot")

Expand Down Expand Up @@ -67,18 +68,19 @@ def __init__(self,
focused_status = None

self.status_details = StatusDetails(self, focused_status)
status_widget = self.wrap_status_details(self.status_details)
status_widget = self.wrap_status_details(self.status_details, False)
status_list_widget = self.wrap_status_list(self.status_list, True)

super().__init__([
("weight", 40, self.status_list),
("weight", 0, urwid.AttrWrap(urwid.SolidFill(""), "blue_selected")),
("weight", 40, status_list_widget),
("weight", 0, urwid.AttrWrap(urwid.SolidFill(" "), "blue_selected")),
("weight", 60, status_widget),
])

def wrap_status_details(self, status_details: "StatusDetails") -> urwid.Widget:
def wrap_status_details(self, status_details: "StatusDetails", focus=False) -> urwid.Widget:
"""Wrap StatusDetails widget with a scrollbar and footer."""
self.status_detail_scrollable = Scrollable(urwid.Padding(status_details, right=1))
return urwid.Padding(
wrapped_sd = urwid.Padding(
urwid.Frame(
body=ScrollBar(
self.status_detail_scrollable,
Expand All @@ -87,15 +89,29 @@ def wrap_status_details(self, status_details: "StatusDetails") -> urwid.Widget:
),
footer=self.get_option_text(status_details.status),
),
left=1
)
left=1)
if (focus):
return urwid.LineBox(wrapped_sd)
else:
return urwid.LineBox(wrapped_sd,
tline=" ", bline=" ", rline=" ",
lline=" ", tlcorner=" ", trcorner=" ",
blcorner=" ", brcorner=" ")

def wrap_status_list(self, status_list: urwid.ListBox, focus=True) -> urwid.Widget:
"""Wrap StatusList widget with a box"""
if (focus):
return urwid.LineBox(status_list)
else:
return urwid.LineBox(status_list, tline=" ", bline=" ", rline=" ",
lline=" ", tlcorner=" ", trcorner=" ", blcorner=" ", brcorner=" ")

def build_status_list(self, statuses, focus):
items = [self.build_list_item(status) for status in statuses]
walker = urwid.SimpleFocusListWalker(items)
walker.set_focus(focus)
urwid.connect_signal(walker, "modified", self.modified)
return urwid.ListBox(walker)
return StatusList(walker, self)

def build_list_item(self, status):
item = StatusListItem(status)
Expand Down Expand Up @@ -158,25 +174,46 @@ def get_focused_status_with_counts(self):
def modified(self):
"""Called when the list focus switches to a new status"""
status, index, count = self.get_focused_status_with_counts()
self.draw_status_details(status)
self.draw_status_details(status, focus=False)
self._emit("focus")

def refresh_status_details(self):
def refresh_same_status_details(self, focus=None):
"""Redraws the details of the focused status."""
pos = self.status_detail_scrollable.get_scrollpos()
widget = self.wrap_status_details(self.status_details, focus)
self.status_detail_scrollable.set_scrollpos(pos)
self.contents[2] = widget, ("weight", 60, False)

def refresh_status_details(self, focus=None):
"""Redraws the details of the focused status."""
status = self.get_focused_status()
pos = self.status_detail_scrollable.get_scrollpos()
self.draw_status_details(status)
self.status_detail_scrollable.set_scrollpos(pos)

def draw_status_details(self, status):
def draw_status_details(self, status, focus=None):
self.status_details = StatusDetails(self, status)
widget = self.wrap_status_details(self.status_details)
widget = self.wrap_status_details(self.status_details, focus)
self.contents[2] = widget, ("weight", 60, False)

def draw_status_list(self, focus=None):
widget = self.wrap_status_list(self.status_list, focus)
self.contents[0] = widget, ("weight", 40, False)

def keypress(self, size, key):
status = self.get_focused_status()
command = self._command_map[key]

if command in [urwid.CURSOR_RIGHT, urwid.CURSOR_MAX_RIGHT]:
if self.focus_position == 0:
self.draw_status_list(focus=False)
self.refresh_same_status_details(focus=True)

if command in [urwid.CURSOR_LEFT, urwid.CURSOR_MAX_LEFT]:
if self.focus_position != 0:
self.draw_status_list(focus=True)
self.refresh_same_status_details(focus=False)

if not status:
return super().keypress(size, key)

Expand Down Expand Up @@ -314,7 +351,7 @@ def update_status(self, status):

# Redraw status details if status is focused
if index == self.status_list.body.focus:
self.draw_status_details(status)
self.draw_status_details(status, focus=False)

def remove_status(self, status):
index = self.get_status_index(status.id)
Expand All @@ -330,7 +367,7 @@ def __init__(self, timeline: Timeline, status: Optional[Status]):
self.status = status
self.followed_tags = timeline.followed_tags
self.followed_accounts = timeline.followed_accounts

self.timeline = timeline
reblogged_by = status.author if status and status.reblog else None
widget_list = list(self.content_generator(status.original, reblogged_by)
if status else ())
Expand Down Expand Up @@ -454,6 +491,12 @@ def poll_generator(self, poll):

yield urwid.Text(("gray", status))

def mouse_event(self, size, event, button, col, row, focus):
if is_mouse_press(event) and button == 1:
self.timeline.draw_status_list(focus=False)
self.timeline.refresh_same_status_details(focus=True)
return super().mouse_event(size, event, button, col, row, focus)


class StatusListItem(SelectableColumns):
def __init__(self, status):
Expand Down
13 changes: 13 additions & 0 deletions toot/tui/widgets.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import urwid
from urwid.util import is_mouse_press


class Clickable:
Expand Down Expand Up @@ -48,6 +49,18 @@ def set_label(self, *args, **kwargs):
self.original_widget.width = len(args[0]) + 4


class StatusList(urwid.ListBox):
def __init__(self, *args, **kwargs):
self.timeline = args[1]
return super().__init__(args[0])

def mouse_event(self, size, event, button, col, row, focus):
if is_mouse_press(event) and button == 1:
self.timeline.draw_status_list(focus=True)
self.timeline.refresh_same_status_details(focus=False)
return super().mouse_event(size, event, button, col, row, focus)


class CheckBox(urwid.AttrWrap):
"""Styled checkbox."""
def __init__(self, *args, **kwargs):
Expand Down