@@ -0,0 +1,128 @@
|
||||
"""
|
||||
Table of Contents overlay sub-application.
|
||||
|
||||
Simple TOC overlay (deprecated in favor of NavigationOverlay).
|
||||
Kept for backward compatibility.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, List, Tuple
|
||||
from PIL import Image
|
||||
|
||||
from .base import OverlaySubApplication
|
||||
from ..gesture import GestureResponse, ActionType
|
||||
from ..state import OverlayState
|
||||
from ..html_generator import generate_toc_overlay
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..application import EbookReader
|
||||
|
||||
|
||||
class TOCOverlay(OverlaySubApplication):
|
||||
"""
|
||||
Simple Table of Contents overlay.
|
||||
|
||||
NOTE: This is deprecated in favor of NavigationOverlay which provides
|
||||
a unified interface for both TOC and bookmarks. Kept for backward compatibility.
|
||||
|
||||
Features:
|
||||
- List of chapters with clickable links
|
||||
- Chapter navigation
|
||||
"""
|
||||
|
||||
def __init__(self, reader: 'EbookReader'):
|
||||
"""Initialize TOC overlay."""
|
||||
super().__init__(reader)
|
||||
self._cached_chapters: List[Tuple[str, int]] = []
|
||||
|
||||
def get_overlay_type(self) -> OverlayState:
|
||||
"""Return TOC overlay type."""
|
||||
return OverlayState.TOC
|
||||
|
||||
def open(self, base_page: Image.Image, **kwargs) -> Image.Image:
|
||||
"""
|
||||
Open the TOC overlay.
|
||||
|
||||
Args:
|
||||
base_page: Current reading page to show underneath
|
||||
chapters: List of (chapter_title, chapter_index) tuples
|
||||
|
||||
Returns:
|
||||
Composited image with TOC overlay
|
||||
"""
|
||||
chapters = kwargs.get('chapters', [])
|
||||
|
||||
# Store for later use
|
||||
self._cached_chapters = chapters
|
||||
|
||||
# Calculate panel size (60% width, 70% height)
|
||||
panel_size = self._calculate_panel_size(0.6, 0.7)
|
||||
|
||||
# Convert chapters to format expected by HTML generator
|
||||
chapter_data = [
|
||||
{"index": idx, "title": title}
|
||||
for title, idx in chapters
|
||||
]
|
||||
|
||||
# Generate TOC HTML with clickable links
|
||||
html = generate_toc_overlay(chapter_data, page_size=panel_size)
|
||||
|
||||
# Render HTML to image
|
||||
overlay_panel = self.render_html_to_image(html, panel_size)
|
||||
|
||||
# Cache for later use
|
||||
self._cached_base_page = base_page.copy()
|
||||
self._cached_overlay_image = overlay_panel
|
||||
|
||||
# Composite and return
|
||||
return self.composite_overlay(base_page, overlay_panel)
|
||||
|
||||
def handle_tap(self, x: int, y: int) -> GestureResponse:
|
||||
"""
|
||||
Handle tap within TOC overlay.
|
||||
|
||||
Detects:
|
||||
- Chapter selection (chapter:N)
|
||||
- Tap outside overlay (closes)
|
||||
|
||||
Args:
|
||||
x, y: Screen coordinates of tap
|
||||
|
||||
Returns:
|
||||
GestureResponse with appropriate action
|
||||
"""
|
||||
# Query the overlay to see what was tapped
|
||||
query_result = self.query_overlay_pixel(x, y)
|
||||
|
||||
# If query failed (tap outside overlay), close it
|
||||
if not query_result:
|
||||
return GestureResponse(ActionType.OVERLAY_CLOSED, {})
|
||||
|
||||
# Check if tapped on a link (chapter)
|
||||
if query_result.get("is_interactive") and query_result.get("link_target"):
|
||||
link_target = query_result["link_target"]
|
||||
|
||||
# Parse "chapter:N" format
|
||||
if link_target.startswith("chapter:"):
|
||||
try:
|
||||
chapter_idx = int(link_target.split(":")[1])
|
||||
|
||||
# Get chapter title for response
|
||||
chapter_title = None
|
||||
for title, idx in self._cached_chapters:
|
||||
if idx == chapter_idx:
|
||||
chapter_title = title
|
||||
break
|
||||
|
||||
# Jump to selected chapter
|
||||
self.reader.jump_to_chapter(chapter_idx)
|
||||
|
||||
return GestureResponse(ActionType.CHAPTER_SELECTED, {
|
||||
"chapter_index": chapter_idx,
|
||||
"chapter_title": chapter_title or f"Chapter {chapter_idx}"
|
||||
})
|
||||
except (ValueError, IndexError):
|
||||
pass
|
||||
|
||||
# Not a chapter link, close overlay
|
||||
return GestureResponse(ActionType.OVERLAY_CLOSED, {})
|
||||
Reference in New Issue
Block a user