This commit is contained in:
+183
-62
@@ -245,15 +245,27 @@ class EbookReader:
|
||||
"""
|
||||
Get the current page as a PIL Image.
|
||||
|
||||
If an overlay is currently open, returns the composited overlay image.
|
||||
Otherwise returns the base reading page.
|
||||
|
||||
Args:
|
||||
include_highlights: Whether to overlay highlights on the page
|
||||
include_highlights: Whether to overlay highlights on the page (only applies to base page)
|
||||
|
||||
Returns:
|
||||
PIL Image of the current page, or None if no book is loaded
|
||||
PIL Image of the current page (or overlay), or None if no book is loaded
|
||||
"""
|
||||
if not self.manager:
|
||||
return None
|
||||
|
||||
# If an overlay is open, return the cached composited overlay image
|
||||
if self.is_overlay_open() and self.overlay_manager._cached_base_page:
|
||||
# Return the last composited overlay image
|
||||
# The overlay manager keeps this updated when settings change
|
||||
return self.overlay_manager.composite_overlay(
|
||||
self.overlay_manager._cached_base_page,
|
||||
self.overlay_manager._cached_overlay_image
|
||||
)
|
||||
|
||||
try:
|
||||
page = self.manager.get_current_page()
|
||||
img = page.render()
|
||||
@@ -503,42 +515,30 @@ class EbookReader:
|
||||
|
||||
def set_line_spacing(self, spacing: int) -> Optional[Image.Image]:
|
||||
"""
|
||||
Set line spacing and re-render current page.
|
||||
|
||||
Set line spacing using pyWebLayout's native support.
|
||||
|
||||
Args:
|
||||
spacing: Line spacing in pixels
|
||||
|
||||
|
||||
Returns:
|
||||
PIL Image of the re-rendered page
|
||||
"""
|
||||
if not self.manager:
|
||||
return None
|
||||
|
||||
|
||||
try:
|
||||
# Update page style
|
||||
self.page_style.line_spacing = max(0, spacing)
|
||||
|
||||
# Need to recreate the manager with new page style
|
||||
current_pos = self.manager.current_position
|
||||
current_font_scale = self.base_font_scale
|
||||
self.manager.shutdown()
|
||||
|
||||
self.manager = EreaderLayoutManager(
|
||||
blocks=self.blocks,
|
||||
page_size=self.page_size,
|
||||
document_id=self.document_id,
|
||||
buffer_size=self.buffer_size,
|
||||
page_style=self.page_style,
|
||||
bookmarks_dir=self.bookmarks_dir
|
||||
)
|
||||
|
||||
# Restore position
|
||||
self.manager.current_position = current_pos
|
||||
|
||||
# Restore font scale using the method (not direct assignment)
|
||||
if current_font_scale != 1.0:
|
||||
self.manager.set_font_scale(current_font_scale)
|
||||
|
||||
# Calculate delta from current spacing
|
||||
current_spacing = self.manager.page_style.line_spacing
|
||||
target_spacing = max(0, spacing)
|
||||
delta = target_spacing - current_spacing
|
||||
|
||||
# Use pyWebLayout's built-in methods to adjust spacing
|
||||
if delta > 0:
|
||||
self.manager.increase_line_spacing(abs(delta))
|
||||
elif delta < 0:
|
||||
self.manager.decrease_line_spacing(abs(delta))
|
||||
|
||||
# Get re-rendered page
|
||||
page = self.manager.get_current_page()
|
||||
return page.render()
|
||||
except Exception as e:
|
||||
@@ -547,48 +547,68 @@ class EbookReader:
|
||||
|
||||
def set_inter_block_spacing(self, spacing: int) -> Optional[Image.Image]:
|
||||
"""
|
||||
Set spacing between blocks (paragraphs, headings, etc.) and re-render.
|
||||
|
||||
Set inter-block spacing using pyWebLayout's native support.
|
||||
|
||||
Args:
|
||||
spacing: Inter-block spacing in pixels
|
||||
|
||||
|
||||
Returns:
|
||||
PIL Image of the re-rendered page
|
||||
"""
|
||||
if not self.manager:
|
||||
return None
|
||||
|
||||
|
||||
try:
|
||||
# Update page style
|
||||
self.page_style.inter_block_spacing = max(0, spacing)
|
||||
|
||||
# Need to recreate the manager with new page style
|
||||
current_pos = self.manager.current_position
|
||||
current_font_scale = self.base_font_scale
|
||||
self.manager.shutdown()
|
||||
|
||||
self.manager = EreaderLayoutManager(
|
||||
blocks=self.blocks,
|
||||
page_size=self.page_size,
|
||||
document_id=self.document_id,
|
||||
buffer_size=self.buffer_size,
|
||||
page_style=self.page_style,
|
||||
bookmarks_dir=self.bookmarks_dir
|
||||
)
|
||||
|
||||
# Restore position
|
||||
self.manager.current_position = current_pos
|
||||
|
||||
# Restore font scale using the method (not direct assignment)
|
||||
if current_font_scale != 1.0:
|
||||
self.manager.set_font_scale(current_font_scale)
|
||||
|
||||
# Calculate delta from current spacing
|
||||
current_spacing = self.manager.page_style.inter_block_spacing
|
||||
target_spacing = max(0, spacing)
|
||||
delta = target_spacing - current_spacing
|
||||
|
||||
# Use pyWebLayout's built-in methods to adjust spacing
|
||||
if delta > 0:
|
||||
self.manager.increase_inter_block_spacing(abs(delta))
|
||||
elif delta < 0:
|
||||
self.manager.decrease_inter_block_spacing(abs(delta))
|
||||
|
||||
# Get re-rendered page
|
||||
page = self.manager.get_current_page()
|
||||
return page.render()
|
||||
except Exception as e:
|
||||
print(f"Error setting inter-block spacing: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def set_word_spacing(self, spacing: int) -> Optional[Image.Image]:
|
||||
"""
|
||||
Set word spacing using pyWebLayout's native support.
|
||||
|
||||
Args:
|
||||
spacing: Word spacing in pixels
|
||||
|
||||
Returns:
|
||||
PIL Image of the re-rendered page
|
||||
"""
|
||||
if not self.manager:
|
||||
return None
|
||||
|
||||
try:
|
||||
# Calculate delta from current spacing
|
||||
current_spacing = self.manager.page_style.word_spacing
|
||||
target_spacing = max(0, spacing)
|
||||
delta = target_spacing - current_spacing
|
||||
|
||||
# Use pyWebLayout's built-in methods to adjust spacing
|
||||
if delta > 0:
|
||||
self.manager.increase_word_spacing(abs(delta))
|
||||
elif delta < 0:
|
||||
self.manager.decrease_word_spacing(abs(delta))
|
||||
|
||||
# Get re-rendered page
|
||||
page = self.manager.get_current_page()
|
||||
return page.render()
|
||||
except Exception as e:
|
||||
print(f"Error setting word spacing: {e}")
|
||||
return None
|
||||
|
||||
def get_position_info(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Get detailed information about the current position.
|
||||
@@ -725,6 +745,9 @@ class EbookReader:
|
||||
elif event.gesture == GestureType.SWIPE_UP:
|
||||
# Swipe up from bottom opens TOC overlay
|
||||
return self._handle_swipe_up(event.y)
|
||||
elif event.gesture == GestureType.SWIPE_DOWN:
|
||||
# Swipe down from top opens settings overlay
|
||||
return self._handle_swipe_down(event.y)
|
||||
elif event.gesture == GestureType.PINCH_IN:
|
||||
return self._handle_zoom_out()
|
||||
elif event.gesture == GestureType.PINCH_OUT:
|
||||
@@ -915,8 +938,26 @@ class EbookReader:
|
||||
|
||||
return GestureResponse(ActionType.NONE, {})
|
||||
|
||||
def _handle_swipe_down(self, y: int) -> GestureResponse:
|
||||
"""Handle swipe down gesture - opens settings overlay if from top of screen"""
|
||||
# Check if swipe started from top 20% of screen
|
||||
top_threshold = self.page_size[1] * 0.2
|
||||
|
||||
if y <= top_threshold:
|
||||
# Open settings overlay
|
||||
overlay_image = self.open_settings_overlay()
|
||||
if overlay_image:
|
||||
return GestureResponse(ActionType.OVERLAY_OPENED, {
|
||||
"overlay_type": "settings",
|
||||
"font_scale": self.base_font_scale,
|
||||
"line_spacing": self.page_style.line_spacing,
|
||||
"inter_block_spacing": self.page_style.inter_block_spacing
|
||||
})
|
||||
|
||||
return GestureResponse(ActionType.NONE, {})
|
||||
|
||||
def _handle_overlay_tap(self, x: int, y: int) -> GestureResponse:
|
||||
"""Handle tap when overlay is open - select chapter or close overlay"""
|
||||
"""Handle tap when overlay is open - select chapter, adjust settings, or close overlay"""
|
||||
# For TOC overlay, use pyWebLayout link query to detect chapter clicks
|
||||
if self.current_overlay_state == OverlayState.TOC:
|
||||
# Query the overlay to see what was tapped
|
||||
@@ -961,6 +1002,74 @@ class EbookReader:
|
||||
self.close_overlay()
|
||||
return GestureResponse(ActionType.OVERLAY_CLOSED, {})
|
||||
|
||||
# For settings overlay, handle setting adjustments
|
||||
elif self.current_overlay_state == OverlayState.SETTINGS:
|
||||
# Query the overlay to see what was tapped
|
||||
query_result = self.overlay_manager.query_overlay_pixel(x, y)
|
||||
|
||||
# If query failed (tap outside overlay), close it
|
||||
if not query_result:
|
||||
self.close_overlay()
|
||||
return GestureResponse(ActionType.OVERLAY_CLOSED, {})
|
||||
|
||||
# Check if tapped on a settings control link
|
||||
if query_result.get("is_interactive") and query_result.get("link_target"):
|
||||
link_target = query_result["link_target"]
|
||||
|
||||
# Parse "setting:action" format
|
||||
if link_target.startswith("setting:"):
|
||||
action = link_target.split(":", 1)[1]
|
||||
|
||||
# Apply the setting change
|
||||
if action == "font_increase":
|
||||
self.increase_font_size()
|
||||
elif action == "font_decrease":
|
||||
self.decrease_font_size()
|
||||
elif action == "line_spacing_increase":
|
||||
new_spacing = self.page_style.line_spacing + 2
|
||||
self.set_line_spacing(new_spacing)
|
||||
elif action == "line_spacing_decrease":
|
||||
new_spacing = max(0, self.page_style.line_spacing - 2)
|
||||
self.set_line_spacing(new_spacing)
|
||||
elif action == "block_spacing_increase":
|
||||
new_spacing = self.page_style.inter_block_spacing + 3
|
||||
self.set_inter_block_spacing(new_spacing)
|
||||
elif action == "block_spacing_decrease":
|
||||
new_spacing = max(0, self.page_style.inter_block_spacing - 3)
|
||||
self.set_inter_block_spacing(new_spacing)
|
||||
elif action == "word_spacing_increase":
|
||||
new_spacing = self.page_style.word_spacing + 2
|
||||
self.set_word_spacing(new_spacing)
|
||||
elif action == "word_spacing_decrease":
|
||||
new_spacing = max(0, self.page_style.word_spacing - 2)
|
||||
self.set_word_spacing(new_spacing)
|
||||
|
||||
# Re-render the base page with new settings applied
|
||||
# Must get directly from manager, not get_current_page() which returns overlay
|
||||
page = self.manager.get_current_page()
|
||||
updated_page = page.render()
|
||||
|
||||
# Refresh the settings overlay with updated values and page
|
||||
self.overlay_manager.refresh_settings_overlay(
|
||||
updated_base_page=updated_page,
|
||||
font_scale=self.base_font_scale,
|
||||
line_spacing=self.page_style.line_spacing,
|
||||
inter_block_spacing=self.page_style.inter_block_spacing,
|
||||
word_spacing=self.page_style.word_spacing
|
||||
)
|
||||
|
||||
return GestureResponse(ActionType.SETTING_CHANGED, {
|
||||
"action": action,
|
||||
"font_scale": self.base_font_scale,
|
||||
"line_spacing": self.page_style.line_spacing,
|
||||
"inter_block_spacing": self.page_style.inter_block_spacing,
|
||||
"word_spacing": self.page_style.word_spacing
|
||||
})
|
||||
|
||||
# Not a setting control, close overlay
|
||||
self.close_overlay()
|
||||
return GestureResponse(ActionType.OVERLAY_CLOSED, {})
|
||||
|
||||
# For other overlays, just close on any tap for now
|
||||
self.close_overlay()
|
||||
return GestureResponse(ActionType.OVERLAY_CLOSED, {})
|
||||
@@ -1208,7 +1317,7 @@ class EbookReader:
|
||||
|
||||
def open_settings_overlay(self) -> Optional[Image.Image]:
|
||||
"""
|
||||
Open the settings overlay.
|
||||
Open the settings overlay with current settings values.
|
||||
|
||||
Returns:
|
||||
Composited image with settings overlay on top of current page, or None if no book loaded
|
||||
@@ -1221,8 +1330,20 @@ class EbookReader:
|
||||
if not base_page:
|
||||
return None
|
||||
|
||||
# Get current settings
|
||||
font_scale = self.base_font_scale
|
||||
line_spacing = self.page_style.line_spacing
|
||||
inter_block_spacing = self.page_style.inter_block_spacing
|
||||
word_spacing = self.page_style.word_spacing
|
||||
|
||||
# Open overlay and get composited image
|
||||
result = self.overlay_manager.open_settings_overlay(base_page)
|
||||
result = self.overlay_manager.open_settings_overlay(
|
||||
base_page,
|
||||
font_scale=font_scale,
|
||||
line_spacing=line_spacing,
|
||||
inter_block_spacing=inter_block_spacing,
|
||||
word_spacing=word_spacing
|
||||
)
|
||||
self.current_overlay_state = OverlayState.SETTINGS
|
||||
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user