Files
StreamLens/analyzer/tui/navigation.py

77 lines
3.1 KiB
Python

"""
Navigation and input handling for the TUI
"""
import curses
from typing import List
from ..models import FlowStats
class NavigationHandler:
"""Handles navigation and input for the TUI"""
def __init__(self):
self.current_view = 'main' # main, dissection
self.selected_flow = 0
self.scroll_offset = 0
self.show_timeline = True # Toggle for bottom timeline plot
def handle_input(self, key: int, flows_list: List[FlowStats]) -> str:
"""
Handle keyboard input and return action
Returns:
Action string: 'quit', 'view_change', 'selection_change', 'none'
"""
if key == ord('q'):
return 'quit'
elif key == ord('d'):
self.current_view = 'dissection'
return 'view_change'
elif key == ord('m') or key == 27: # 'm' or ESC to return to main
self.current_view = 'main'
return 'view_change'
elif key == curses.KEY_UP and self.current_view == 'main':
self.selected_flow = max(0, self.selected_flow - 1)
return 'selection_change'
elif key == curses.KEY_DOWN and self.current_view == 'main':
max_items = self._get_total_display_items(flows_list)
self.selected_flow = min(max_items - 1, self.selected_flow + 1)
return 'selection_change'
elif key == ord('t'): # Toggle timeline plot
self.show_timeline = not self.show_timeline
return 'view_change'
elif key == curses.KEY_PPAGE and self.current_view == 'main': # Page Up
self.selected_flow = max(0, self.selected_flow - 10)
return 'selection_change'
elif key == curses.KEY_NPAGE and self.current_view == 'main': # Page Down
max_items = self._get_total_display_items(flows_list)
self.selected_flow = min(max_items - 1, self.selected_flow + 10)
return 'selection_change'
elif key == curses.KEY_HOME and self.current_view == 'main': # Home
self.selected_flow = 0
return 'selection_change'
elif key == curses.KEY_END and self.current_view == 'main': # End
max_items = self._get_total_display_items(flows_list)
self.selected_flow = max_items - 1
return 'selection_change'
return 'none'
def _get_total_display_items(self, flows_list: List[FlowStats]) -> int:
"""Calculate total number of selectable items (flows + frame types)"""
total = 0
for flow in flows_list:
total += 1 # Flow itself
total += len(flow.frame_types) # Frame types under this flow
return total
def get_status_bar_text(self) -> str:
"""Get status bar text based on current view"""
if self.current_view == 'main':
timeline_status = "ON" if self.show_timeline else "OFF"
return f"[↑↓]navigate [PgUp/PgDn]scroll [t]imeline:{timeline_status} [d]issection [q]uit"
elif self.current_view == 'dissection':
return "[m]ain view [q]uit"
else:
return "[m]ain [d]issection [q]uit"