From ba22f41cf86a5cc1e85cf9b727507b20413208c2 Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Wed, 12 May 2021 14:02:44 +0200 Subject: [PATCH] Focus handling --- nomadnet/NomadNetworkApp.py | 2 +- nomadnet/ui/TextUI.py | 1 + nomadnet/ui/textui/Conversations.py | 97 ++++++++++++++++++----------- nomadnet/ui/textui/Main.py | 65 ++++++++++++++++--- 4 files changed, 120 insertions(+), 45 deletions(-) diff --git a/nomadnet/NomadNetworkApp.py b/nomadnet/NomadNetworkApp.py index 49bdd84..e38ce26 100644 --- a/nomadnet/NomadNetworkApp.py +++ b/nomadnet/NomadNetworkApp.py @@ -106,7 +106,7 @@ class NomadNetworkApp: self.lxmf_destination = self.message_router.register_delivery_identity(self.identity) RNS.log("LXMF Router ready to receive on: "+RNS.prettyhexrep(self.lxmf_destination.hash)) - self.ui = nomadnet.ui.spawn(self.uimode) + nomadnet.ui.spawn(self.uimode) def lxmf_delivery(self, message): diff --git a/nomadnet/ui/TextUI.py b/nomadnet/ui/TextUI.py index a14b657..246d9bd 100644 --- a/nomadnet/ui/TextUI.py +++ b/nomadnet/ui/TextUI.py @@ -33,6 +33,7 @@ class TextUI: def __init__(self): self.app = NomadNetworkApp.get_shared_instance() + self.app.ui = self self.loop = None if importlib.util.find_spec("urwid") != None: diff --git a/nomadnet/ui/textui/Conversations.py b/nomadnet/ui/textui/Conversations.py index 921d840..993b398 100644 --- a/nomadnet/ui/textui/Conversations.py +++ b/nomadnet/ui/textui/Conversations.py @@ -2,19 +2,50 @@ import RNS import time import nomadnet -class ConversationsDisplayShortcuts(): +import urwid + +class ListEntry(urwid.Text): + _selectable = True + + signals = ["click"] + + def keypress(self, size, key): + """ + Send 'click' signal on 'activate' command. + """ + if self._command_map[key] != urwid.ACTIVATE: + return key + + self._emit('click') + + def mouse_event(self, size, event, button, x, y, focus): + """ + Send 'click' signal on button 1 press. + """ + if button != 1 or not urwid.util.is_mouse_press(event): + return False + + self._emit('click') + return True + + +class ConversationListDisplayShortcuts(): def __init__(self, app): - import urwid self.app = app - self.widget = urwid.AttrMap(urwid.Text("Conversations Display Shortcuts"), "shortcutbar") + self.widget = urwid.AttrMap(urwid.Text("Conversation List Display Shortcuts"), "shortcutbar") + +class ConversationDisplayShortcuts(): + def __init__(self, app): + self.app = app + + self.widget = urwid.AttrMap(urwid.Text("[C-s] Send"), "shortcutbar") class ConversationsDisplay(): list_width = 0.33 cached_conversation_widgets = {} def __init__(self, app): - import urwid from nomadnet.vendor.additional_urwid_widgets import IndicativeListBox self.app = app @@ -23,12 +54,21 @@ class ConversationsDisplay(): for conversation in app.conversations(): conversation_list_widgets.append(self.conversation_list_widget(conversation)) + def disp_list_shortcuts(sender, arg1, arg2): + self.shortcuts_display = self.list_shortcuts + self.app.ui.main_display.update_active_shortcuts() + RNS.log("Modified") + walker = urwid.SimpleFocusListWalker(conversation_list_widgets) - listbox = urwid.LineBox(urwid.Filler(IndicativeListBox(conversation_list_widgets), height=("relative", 100))) + ilb = IndicativeListBox(conversation_list_widgets) + listbox = urwid.LineBox(urwid.Filler(ilb, height=("relative", 100))) columns_widget = urwid.Columns([("weight", ConversationsDisplay.list_width, listbox), ("weight", 1-ConversationsDisplay.list_width, self.make_conversation_widget(None))], dividechars=0, focus_column=0, box_columns=[0]) - self.shortcuts_display = ConversationsDisplayShortcuts(self.app) + self.list_shortcuts = ConversationListDisplayShortcuts(self.app) + self.editor_shortcuts = ConversationDisplayShortcuts(self.app) + + self.shortcuts_display = self.list_shortcuts self.widget = columns_widget def display_conversation(self, sender=None, source_hash=None): @@ -38,7 +78,6 @@ class ConversationsDisplay(): def make_conversation_widget(self, source_hash): time_format = self.app.time_format - import urwid class LXMessageWidget(urwid.WidgetWrap): def __init__(self, message): title_string = time.strftime(time_format) @@ -76,44 +115,26 @@ class ConversationsDisplay(): from nomadnet.vendor.additional_urwid_widgets import IndicativeListBox messagelist = IndicativeListBox(message_widgets) + msg_editor = urwid.Edit(caption="\u270E", edit_text="", multiline=True) + widget = urwid.LineBox( urwid.Frame( messagelist, - footer=urwid.AttrMap(urwid.Edit(caption="\u270E", edit_text=""), "msg_editor") + footer=urwid.AttrMap(msg_editor, "msg_editor") ) ) + def disp_editor_shortcuts(sender, arg1, arg2): + self.shortcuts_display = self.editor_shortcuts + self.app.ui.main_display.update_active_shortcuts() + + urwid.connect_signal(msg_editor, "change", disp_editor_shortcuts, "modified event") + ConversationsDisplay.cached_conversation_widgets[source_hash] = widget return widget def conversation_list_widget(self, conversation): - import urwid - - class ListEntry(urwid.Text): - _selectable = True - - signals = ["click"] - - def keypress(self, size, key): - """ - Send 'click' signal on 'activate' command. - """ - if self._command_map[key] != urwid.ACTIVATE: - return key - - self._emit('click') - - def mouse_event(self, size, event, button, x, y, focus): - """ - Send 'click' signal on button 1 press. - """ - if button != 1 or not urwid.util.is_mouse_press(event): - return False - - self._emit('click') - return True - #widget = urwid.SelectableIcon(str(conversation), cursor_position=-1) widget = ListEntry(str(conversation)) urwid.connect_signal(widget, "click", self.display_conversation, conversation) @@ -121,4 +142,10 @@ class ConversationsDisplay(): def shortcuts(self): - return self.shortcuts_display \ No newline at end of file + focus_path = self.widget.get_focus_path() + if focus_path[0] == 0: + return self.list_shortcuts + elif focus_path[0] == 1: + return self.editor_shortcuts + else: + return self.list_shortcuts \ No newline at end of file diff --git a/nomadnet/ui/textui/Main.py b/nomadnet/ui/textui/Main.py index 34d99ae..e641877 100644 --- a/nomadnet/ui/textui/Main.py +++ b/nomadnet/ui/textui/Main.py @@ -1,13 +1,14 @@ import RNS +import time from .Network import * from .Conversations import * from .Directory import * from .Map import * +import urwid class SubDisplays(): def __init__(self, app): - import urwid self.app = app self.network_display = NetworkDisplay(self.app) self.conversations_display = ConversationsDisplay(self.app) @@ -19,17 +20,65 @@ class SubDisplays(): def active(self): return self.active_display +class MenuButton(urwid.Button): + button_left = urwid.Text('[') + button_right = urwid.Text(']') + +class MainFrame(urwid.Frame): + FOCUS_CHECK_TIMEOUT = 0.25 + + def __init__(self, body, header=None, footer=None, delegate=None): + self.delegate = delegate + self.current_focus = None + super().__init__(body, header, footer) + + def keypress_focus_check(self, deferred=False): + current_focus = self.delegate.widget.get_focus_widgets()[-1] + + if deferred: + if current_focus != self.current_focus: + self.focus_changed() + else: + def deferred_focus_check(loop, user_data): + self.keypress_focus_check(deferred=True) + self.delegate.app.ui.loop.set_alarm_in(MainFrame.FOCUS_CHECK_TIMEOUT, deferred_focus_check) + + self.current_focus = current_focus + + def focus_changed(self): + current_focus = self.delegate.widget.get_focus_widgets()[-1] + current_focus_path = self.delegate.widget.get_focus_path() + RNS.log("Focus changed to: "+str(current_focus_path)) + + if len(current_focus_path) > 1: + if current_focus_path[0] == "body": + self.delegate.update_active_shortcuts() + + def mouse_event(self, size, event, button, col, row, focus): + current_focus = self.delegate.widget.get_focus_widgets()[-1] + if current_focus != self.current_focus: + self.focus_changed() + + self.current_focus = current_focus + return super(MainFrame, self).mouse_event(size, event, button, col, row, focus) + + def keypress(self, size, key): + self.keypress_focus_check() + + if key == "ctrl q": + raise urwid.ExitMainLoop + + return super(MainFrame, self).keypress(size, key) class MainDisplay(): def __init__(self, ui, app): - import urwid self.ui = ui self.app = app self.menu_display = MenuDisplay(self.app, self) self.sub_displays = SubDisplays(self.app) - self.frame = urwid.Frame(self.sub_displays.active().widget, header=self.menu_display.widget, footer=self.sub_displays.active().shortcuts().widget) + self.frame = MainFrame(self.sub_displays.active().widget, header=self.menu_display.widget, footer=self.sub_displays.active().shortcuts().widget, delegate=self) self.widget = self.frame def show_network(self, user_data): @@ -50,17 +99,15 @@ class MainDisplay(): def update_active_sub_display(self): self.frame.contents["body"] = (self.sub_displays.active().widget, None) + self.update_active_shortcuts() + + def update_active_shortcuts(self): self.frame.contents["footer"] = (self.sub_displays.active().shortcuts().widget, None) + class MenuDisplay(): def __init__(self, app, handler): - import urwid - - class MenuButton(urwid.Button): - button_left = urwid.Text('[') - button_right = urwid.Text(']') - self.app = app menu_text = ("pack", urwid.Text(" \U00002638"))