mirror of
https://github.com/koreader/koreader
synced 2024-10-31 21:20:20 +00:00
cre: allow text selection/highlighting across pages
Panning to the bottom right corner (or top left corner) switches to scroll mode and scroll the page forward (resp. backward) 1/3rd of the screen. One has to pan out of the corner to continue selection. Panning again to that corner scrolls another 1/3rd of screen. Page mode is restored when highlighting or dismissing the highlight dialog, and a little marker is shown at where selection was started so one does not get lost after all that scrolling and restoring.
This commit is contained in:
parent
6e3b40e2bf
commit
e802b96e45
@ -10,6 +10,7 @@ local UIManager = require("ui/uimanager")
|
||||
local logger = require("logger")
|
||||
local _ = require("gettext")
|
||||
local T = require("ffi/util").template
|
||||
local Screen = Device.screen
|
||||
|
||||
local ReaderHighlight = InputContainer:new{}
|
||||
|
||||
@ -140,6 +141,11 @@ function ReaderHighlight:clear(clear_id)
|
||||
else
|
||||
self.ui.document:clearSelection()
|
||||
end
|
||||
if self.restore_page_mode_func then
|
||||
self.restore_page_mode_func()
|
||||
self.restore_page_mode_func = nil
|
||||
end
|
||||
self.selected_text_start_xpointer = nil
|
||||
if self.hold_pos then
|
||||
self.hold_pos = nil
|
||||
self.selected_text = nil
|
||||
@ -336,8 +342,62 @@ function ReaderHighlight:onHoldPan(_, ges)
|
||||
|
||||
self.holdpan_pos = self.view:screenToPageTransform(ges.pos)
|
||||
logger.dbg("holdpan position in page", self.holdpan_pos)
|
||||
|
||||
if not self.ui.document.info.has_pages and self.selected_text_start_xpointer then
|
||||
-- With CreDocuments, allow text selection across multiple pages
|
||||
-- by (temporarily) switching to scroll mode when panning to the
|
||||
-- top left or bottom right corners.
|
||||
local is_in_top_left_corner = self.holdpan_pos.y < 1/8*Screen:getHeight()
|
||||
and self.holdpan_pos.x < 1/8*Screen:getWidth()
|
||||
local is_in_bottom_right_corner = self.holdpan_pos.y > 7/8*Screen:getHeight()
|
||||
and self.holdpan_pos.x > 7/8*Screen:getWidth()
|
||||
if is_in_top_left_corner or is_in_bottom_right_corner then
|
||||
if self.was_in_some_corner then
|
||||
-- Do nothing, wait for the user to move his finger out of that corner
|
||||
return true
|
||||
end
|
||||
self.was_in_some_corner = true
|
||||
-- We'll adjust hold_pos.y after the mode switch and the scroll
|
||||
-- so it's accurate in the new screen coordinates
|
||||
local orig_y = self.ui.document:getScreenPositionFromXPointer(self.selected_text_start_xpointer)
|
||||
if self.view.view_mode ~= "scroll" then
|
||||
-- Switch from page mode to scroll mode
|
||||
local restore_page_mode_xpointer = self.ui.document:getXPointer() -- top of current page
|
||||
self.restore_page_mode_func = function()
|
||||
self.ui:handleEvent(Event:new("SetViewMode", "page"))
|
||||
self.ui.rolling:onGotoXPointer(restore_page_mode_xpointer, self.selected_text_start_xpointer)
|
||||
end
|
||||
self.ui:handleEvent(Event:new("SetViewMode", "scroll"))
|
||||
end
|
||||
-- (using rolling:onGotoViewRel(1/3) has some strange side effects)
|
||||
local scroll_distance = math.floor(Screen:getHeight() * 1/3)
|
||||
local move_y = is_in_bottom_right_corner and scroll_distance or -scroll_distance
|
||||
self.ui.rolling:_gotoPos(self.ui.document:getCurrentPos() + move_y)
|
||||
local new_y = self.ui.document:getScreenPositionFromXPointer(self.selected_text_start_xpointer)
|
||||
self.hold_pos.y = self.hold_pos.y - orig_y + new_y
|
||||
UIManager:setDirty(self.dialog, "ui")
|
||||
return true
|
||||
else
|
||||
self.was_in_some_corner = nil
|
||||
end
|
||||
end
|
||||
|
||||
local old_text = self.selected_text and self.selected_text.text
|
||||
self.selected_text = self.ui.document:getTextFromPositions(self.hold_pos, self.holdpan_pos)
|
||||
|
||||
if self.selected_text and self.selected_text.pos0 then
|
||||
-- Remember original highlight start position, so we can show
|
||||
-- a marker when back from scroll mode if that switch happened.
|
||||
-- (getTextFromPositions() does order pos0 and pos1, so it's not
|
||||
-- certain pos0 is where we started from - we get the one from the
|
||||
-- first pan, which is hopefully small enough to not span too
|
||||
-- much height, so the marker points to the start position if the
|
||||
-- user later pans backward)
|
||||
if not self.selected_text_start_xpointer then
|
||||
self.selected_text_start_xpointer = self.selected_text.pos0
|
||||
end
|
||||
end
|
||||
|
||||
if self.selected_text and old_text and old_text == self.selected_text.text then
|
||||
-- no modification
|
||||
return
|
||||
|
Loading…
Reference in New Issue
Block a user