153 lines
4.0 KiB
Python
153 lines
4.0 KiB
Python
from abc import ABC, abstractmethod
|
||
from typing import Any
|
||
|
||
from textual.containers import ScrollableContainer
|
||
|
||
|
||
class BaseScreenFocusService(ABC):
|
||
"""
|
||
TUI 屏幕焦点服务基类。
|
||
|
||
该基类统一处理焦点顺序中的左右移动和滚动目标回退逻辑,具体页面
|
||
只需声明自身的焦点顺序和默认滚动容器。
|
||
"""
|
||
|
||
@abstractmethod
|
||
def get_focus_order(self, screen: Any) -> list[Any]:
|
||
"""
|
||
返回当前页面的焦点顺序。
|
||
|
||
:param screen: 当前屏幕对象
|
||
:return: 焦点组件列表
|
||
"""
|
||
|
||
@abstractmethod
|
||
def get_default_scroll_target(self, screen: Any) -> ScrollableContainer:
|
||
"""
|
||
返回当前页面的默认滚动容器。
|
||
|
||
:param screen: 当前屏幕对象
|
||
:return: 默认滚动容器
|
||
"""
|
||
|
||
def move_focus(self, screen: Any, step: int) -> None:
|
||
"""
|
||
按给定方向移动当前焦点。
|
||
|
||
:param screen: 当前屏幕对象
|
||
:param step: 焦点移动步长
|
||
:return: None
|
||
"""
|
||
order = self.get_focus_order(screen)
|
||
focused = screen.app.focused
|
||
if focused not in order:
|
||
order[0].focus()
|
||
return
|
||
target_index = max(0, min(order.index(focused) + step, len(order) - 1))
|
||
order[target_index].focus()
|
||
|
||
def get_scroll_target(self, screen: Any) -> Any:
|
||
"""
|
||
获取当前应响应滚动动作的焦点区域。
|
||
|
||
:param screen: 当前屏幕对象
|
||
:return: 当前焦点组件或默认滚动容器
|
||
"""
|
||
focused = screen.app.focused
|
||
order = self.get_focus_order(screen)
|
||
if focused in order:
|
||
return focused
|
||
return self.get_default_scroll_target(screen)
|
||
|
||
|
||
class ScreenFocusActionsMixin:
|
||
"""
|
||
TUI 屏幕焦点动作混入。
|
||
|
||
该混入负责将焦点服务暴露为屏幕上的左右移动与滚动 action,避免
|
||
各个 Screen 类重复编写同形转发方法。
|
||
"""
|
||
|
||
focus_service: BaseScreenFocusService
|
||
|
||
def _move_focus(self, step: int) -> None:
|
||
"""
|
||
按给定方向移动当前焦点。
|
||
|
||
:param step: 焦点移动步长
|
||
:return: None
|
||
"""
|
||
self.focus_service.move_focus(self, step)
|
||
|
||
def _get_scroll_target(self) -> Any:
|
||
"""
|
||
获取当前应响应滚动动作的焦点区域。
|
||
|
||
:return: 当前焦点组件或主工作区
|
||
"""
|
||
return self.focus_service.get_scroll_target(self)
|
||
|
||
def action_scroll_focus_down(self) -> None:
|
||
"""
|
||
向下滚动当前焦点区域。
|
||
|
||
:return: None
|
||
"""
|
||
self._get_scroll_target().scroll_down(animate=False)
|
||
|
||
def action_scroll_focus_up(self) -> None:
|
||
"""
|
||
向上滚动当前焦点区域。
|
||
|
||
:return: None
|
||
"""
|
||
self._get_scroll_target().scroll_up(animate=False)
|
||
|
||
def action_scroll_focus_page_down(self) -> None:
|
||
"""
|
||
向下翻动当前焦点区域。
|
||
|
||
:return: None
|
||
"""
|
||
self._get_scroll_target().scroll_page_down(animate=False)
|
||
|
||
def action_scroll_focus_page_up(self) -> None:
|
||
"""
|
||
向上翻动当前焦点区域。
|
||
|
||
:return: None
|
||
"""
|
||
self._get_scroll_target().scroll_page_up(animate=False)
|
||
|
||
def action_scroll_focus_home(self) -> None:
|
||
"""
|
||
将当前焦点区域滚动到起始位置。
|
||
|
||
:return: None
|
||
"""
|
||
self._get_scroll_target().scroll_home(animate=False)
|
||
|
||
def action_scroll_focus_end(self) -> None:
|
||
"""
|
||
将当前焦点区域滚动到末尾位置。
|
||
|
||
:return: None
|
||
"""
|
||
self._get_scroll_target().scroll_end(animate=False)
|
||
|
||
def action_focus_left(self) -> None:
|
||
"""
|
||
将焦点向左移动一列。
|
||
|
||
:return: None
|
||
"""
|
||
self._move_focus(-1)
|
||
|
||
def action_focus_right(self) -> None:
|
||
"""
|
||
将焦点向右移动一列。
|
||
|
||
:return: None
|
||
"""
|
||
self._move_focus(1)
|