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
|
||||
|
||||
@@ -125,3 +125,4 @@ class ActionType:
|
||||
OVERLAY_OPENED = "overlay_opened"
|
||||
OVERLAY_CLOSED = "overlay_closed"
|
||||
CHAPTER_SELECTED = "chapter_selected"
|
||||
SETTING_CHANGED = "setting_changed"
|
||||
|
||||
+78
-113
@@ -192,131 +192,96 @@ def generate_reader_html(book_title: str, book_author: str, page_image_data: str
|
||||
return html
|
||||
|
||||
|
||||
def generate_settings_overlay() -> str:
|
||||
def generate_settings_overlay(
|
||||
font_scale: float = 1.0,
|
||||
line_spacing: int = 5,
|
||||
inter_block_spacing: int = 15,
|
||||
word_spacing: int = 0,
|
||||
page_size: tuple = (800, 1200)
|
||||
) -> str:
|
||||
"""
|
||||
Generate HTML for the settings overlay.
|
||||
Generate HTML for the settings overlay with current values.
|
||||
|
||||
Uses simple paragraphs with links, similar to TOC overlay,
|
||||
since pyWebLayout doesn't support HTML tables.
|
||||
|
||||
Args:
|
||||
font_scale: Current font scale (e.g., 1.0 = 100%, 1.2 = 120%)
|
||||
line_spacing: Current line spacing in pixels
|
||||
inter_block_spacing: Current inter-block spacing in pixels
|
||||
word_spacing: Current word spacing in pixels
|
||||
page_size: Page dimensions (width, height) for sizing the overlay
|
||||
|
||||
Returns:
|
||||
HTML string for settings overlay
|
||||
HTML string for settings overlay with clickable controls
|
||||
"""
|
||||
html = '''
|
||||
# Format current values for display
|
||||
font_percent = int(font_scale * 100)
|
||||
|
||||
html = f'''
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Settings</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
}
|
||||
.overlay-panel {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 16px rgba(0,0,0,0.3);
|
||||
padding: 20px;
|
||||
min-width: 400px;
|
||||
}
|
||||
.overlay-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 2px solid #ddd;
|
||||
}
|
||||
.overlay-title {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.close-button {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.close-button:hover {
|
||||
background-color: #c82333;
|
||||
}
|
||||
.settings-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.settings-table td {
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.setting-label {
|
||||
font-weight: bold;
|
||||
width: 40%;
|
||||
}
|
||||
.setting-control {
|
||||
width: 60%;
|
||||
text-align: right;
|
||||
}
|
||||
.control-button {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-left: 5px;
|
||||
}
|
||||
.control-button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="overlay-panel">
|
||||
<div class="overlay-header">
|
||||
<span class="overlay-title">Settings</span>
|
||||
<button class="close-button" id="btn-close">Close</button>
|
||||
</div>
|
||||
<body style="background-color: white; margin: 0; padding: 25px; font-family: Arial, sans-serif;">
|
||||
|
||||
<table class="settings-table">
|
||||
<tr>
|
||||
<td class="setting-label">Font Size</td>
|
||||
<td class="setting-control">
|
||||
<button class="control-button" id="btn-font-decrease">A-</button>
|
||||
<button class="control-button" id="btn-font-increase">A+</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="setting-label">Line Spacing</td>
|
||||
<td class="setting-control">
|
||||
<button class="control-button" id="btn-spacing-decrease">-</button>
|
||||
<button class="control-button" id="btn-spacing-increase">+</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="setting-label">Brightness</td>
|
||||
<td class="setting-control">
|
||||
<button class="control-button" id="btn-brightness-decrease">-</button>
|
||||
<button class="control-button" id="btn-brightness-increase">+</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="setting-label">WiFi</td>
|
||||
<td class="setting-control">
|
||||
<button class="control-button" id="btn-wifi">Configure</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h1 style="color: #000; margin: 0 0 8px 0; font-size: 24px; text-align: center; font-weight: bold;">
|
||||
Settings
|
||||
</h1>
|
||||
|
||||
<p style="text-align: center; color: #666; margin: 0 0 15px 0; padding-bottom: 12px;
|
||||
border-bottom: 2px solid #ccc; font-size: 13px;">
|
||||
Adjust reading preferences
|
||||
</p>
|
||||
|
||||
<div style="margin: 15px 0;">
|
||||
<p style="padding: 12px; margin: 5px 0; background-color: #f0f0f0; border-left: 3px solid #007bff;">
|
||||
<b>Font Size: {font_percent}%</b>
|
||||
</p>
|
||||
<p style="padding: 12px; margin: 5px 0; background-color: #f0f0f0;">
|
||||
<a href="setting:font_decrease" style="text-decoration: none; color: #000;">Decrease [ - ]</a>
|
||||
</p>
|
||||
<p style="padding: 12px; margin: 5px 0; background-color: #f0f0f0;">
|
||||
<a href="setting:font_increase" style="text-decoration: none; color: #000;">Increase [ + ]</a>
|
||||
</p>
|
||||
|
||||
<p style="padding: 12px; margin: 5px 0; background-color: #f0f0f0; border-left: 3px solid #28a745;">
|
||||
<b>Line Spacing: {line_spacing}px</b>
|
||||
</p>
|
||||
<p style="padding: 12px; margin: 5px 0; background-color: #f0f0f0;">
|
||||
<a href="setting:line_spacing_decrease" style="text-decoration: none; color: #000;">Decrease [ - ]</a>
|
||||
</p>
|
||||
<p style="padding: 12px; margin: 5px 0; background-color: #f0f0f0;">
|
||||
<a href="setting:line_spacing_increase" style="text-decoration: none; color: #000;">Increase [ + ]</a>
|
||||
</p>
|
||||
|
||||
<p style="padding: 12px; margin: 5px 0; background-color: #f0f0f0; border-left: 3px solid #17a2b8;">
|
||||
<b>Paragraph Spacing: {inter_block_spacing}px</b>
|
||||
</p>
|
||||
<p style="padding: 12px; margin: 5px 0; background-color: #f0f0f0;">
|
||||
<a href="setting:block_spacing_decrease" style="text-decoration: none; color: #000;">Decrease [ - ]</a>
|
||||
</p>
|
||||
<p style="padding: 12px; margin: 5px 0; background-color: #f0f0f0;">
|
||||
<a href="setting:block_spacing_increase" style="text-decoration: none; color: #000;">Increase [ + ]</a>
|
||||
</p>
|
||||
|
||||
<p style="padding: 12px; margin: 5px 0; background-color: #f0f0f0; border-left: 3px solid #ffc107;">
|
||||
<b>Word Spacing: {word_spacing}px</b>
|
||||
</p>
|
||||
<p style="padding: 12px; margin: 5px 0; background-color: #f0f0f0;">
|
||||
<a href="setting:word_spacing_decrease" style="text-decoration: none; color: #000;">Decrease [ - ]</a>
|
||||
</p>
|
||||
<p style="padding: 12px; margin: 5px 0; background-color: #f0f0f0;">
|
||||
<a href="setting:word_spacing_increase" style="text-decoration: none; color: #000;">Increase [ + ]</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p style="text-align: center; margin: 15px 0 0 0; padding-top: 12px;
|
||||
border-top: 2px solid #ccc; color: #888; font-size: 11px;">
|
||||
Changes apply in real-time • Tap outside to close
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
|
||||
+129
-8
@@ -200,29 +200,150 @@ class OverlayManager:
|
||||
# Composite and return
|
||||
return self.composite_overlay(base_page, overlay_panel)
|
||||
|
||||
def open_settings_overlay(self, base_page: Image.Image) -> Image.Image:
|
||||
def open_settings_overlay(
|
||||
self,
|
||||
base_page: Image.Image,
|
||||
font_scale: float = 1.0,
|
||||
line_spacing: int = 5,
|
||||
inter_block_spacing: int = 15,
|
||||
word_spacing: int = 0
|
||||
) -> Image.Image:
|
||||
"""
|
||||
Open the settings overlay.
|
||||
Open the settings overlay with current settings values.
|
||||
|
||||
Args:
|
||||
base_page: Current reading page to show underneath
|
||||
font_scale: Current font scale
|
||||
line_spacing: Current line spacing
|
||||
inter_block_spacing: Current inter-block spacing
|
||||
word_spacing: Current word spacing
|
||||
|
||||
Returns:
|
||||
Composited image with settings overlay on top
|
||||
"""
|
||||
# Generate settings HTML
|
||||
html = generate_settings_overlay()
|
||||
# Import here to avoid circular dependency
|
||||
from .application import EbookReader
|
||||
|
||||
# Render HTML to image
|
||||
overlay_image = self.render_html_to_image(html)
|
||||
# Calculate panel size (60% of screen)
|
||||
panel_width = int(self.page_size[0] * 0.6)
|
||||
panel_height = int(self.page_size[1] * 0.7)
|
||||
|
||||
# Generate settings HTML with current values
|
||||
html = generate_settings_overlay(
|
||||
font_scale=font_scale,
|
||||
line_spacing=line_spacing,
|
||||
inter_block_spacing=inter_block_spacing,
|
||||
word_spacing=word_spacing,
|
||||
page_size=(panel_width, panel_height)
|
||||
)
|
||||
|
||||
# Create reader for overlay and keep it alive for querying
|
||||
if self._overlay_reader:
|
||||
self._overlay_reader.close()
|
||||
|
||||
self._overlay_reader = EbookReader(
|
||||
page_size=(panel_width, panel_height),
|
||||
margin=15,
|
||||
background_color=(255, 255, 255)
|
||||
)
|
||||
|
||||
# Load the HTML content
|
||||
success = self._overlay_reader.load_html(
|
||||
html_string=html,
|
||||
title="Settings",
|
||||
author="",
|
||||
document_id="settings_overlay"
|
||||
)
|
||||
|
||||
if not success:
|
||||
raise ValueError("Failed to load settings overlay HTML")
|
||||
|
||||
# Get the rendered page
|
||||
overlay_panel = self._overlay_reader.get_current_page()
|
||||
|
||||
# Calculate and store panel position for coordinate translation
|
||||
panel_x = int((self.page_size[0] - panel_width) / 2)
|
||||
panel_y = int((self.page_size[1] - panel_height) / 2)
|
||||
self._overlay_panel_offset = (panel_x, panel_y)
|
||||
|
||||
# Cache for later use
|
||||
self._cached_base_page = base_page.copy()
|
||||
self._cached_overlay_image = overlay_image
|
||||
self._cached_overlay_image = overlay_panel
|
||||
self.current_overlay = OverlayState.SETTINGS
|
||||
|
||||
# Composite and return
|
||||
return self.composite_overlay(base_page, overlay_image)
|
||||
return self.composite_overlay(base_page, overlay_panel)
|
||||
|
||||
def refresh_settings_overlay(
|
||||
self,
|
||||
updated_base_page: Image.Image,
|
||||
font_scale: float,
|
||||
line_spacing: int,
|
||||
inter_block_spacing: int,
|
||||
word_spacing: int = 0
|
||||
) -> Image.Image:
|
||||
"""
|
||||
Refresh the settings overlay with updated values and background page.
|
||||
|
||||
This is used for live preview when settings change - it updates both
|
||||
the background page (with new settings applied) and the overlay panel
|
||||
(with new values displayed).
|
||||
|
||||
Args:
|
||||
updated_base_page: Updated reading page with new settings applied
|
||||
font_scale: Updated font scale
|
||||
line_spacing: Updated line spacing
|
||||
inter_block_spacing: Updated inter-block spacing
|
||||
word_spacing: Updated word spacing
|
||||
|
||||
Returns:
|
||||
Composited image with updated settings overlay
|
||||
"""
|
||||
# Import here to avoid circular dependency
|
||||
from .application import EbookReader
|
||||
|
||||
# Calculate panel size (60% of screen)
|
||||
panel_width = int(self.page_size[0] * 0.6)
|
||||
panel_height = int(self.page_size[1] * 0.7)
|
||||
|
||||
# Generate updated settings HTML
|
||||
html = generate_settings_overlay(
|
||||
font_scale=font_scale,
|
||||
line_spacing=line_spacing,
|
||||
inter_block_spacing=inter_block_spacing,
|
||||
word_spacing=word_spacing,
|
||||
page_size=(panel_width, panel_height)
|
||||
)
|
||||
|
||||
# Recreate overlay reader with updated HTML
|
||||
if self._overlay_reader:
|
||||
self._overlay_reader.close()
|
||||
|
||||
self._overlay_reader = EbookReader(
|
||||
page_size=(panel_width, panel_height),
|
||||
margin=15,
|
||||
background_color=(255, 255, 255)
|
||||
)
|
||||
|
||||
success = self._overlay_reader.load_html(
|
||||
html_string=html,
|
||||
title="Settings",
|
||||
author="",
|
||||
document_id="settings_overlay"
|
||||
)
|
||||
|
||||
if not success:
|
||||
raise ValueError("Failed to load updated settings overlay HTML")
|
||||
|
||||
# Get the updated rendered panel
|
||||
overlay_panel = self._overlay_reader.get_current_page()
|
||||
|
||||
# Update caches
|
||||
self._cached_base_page = updated_base_page.copy()
|
||||
self._cached_overlay_image = overlay_panel
|
||||
|
||||
# Composite and return
|
||||
return self.composite_overlay(updated_base_page, overlay_panel)
|
||||
|
||||
def open_bookmarks_overlay(self, bookmarks: List[Dict[str, Any]], base_page: Image.Image) -> Image.Image:
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user