From 766b1998803c9dd6cd258bdbaa1f218c6cd35090 Mon Sep 17 00:00:00 2001 From: poire-z Date: Wed, 13 Mar 2019 13:10:32 +0100 Subject: [PATCH] cre 2-pages view: allow extending selection across pages Similar to what's been added for 1 page view, but just turn one page instead of switching to scroll mode when reaching top left or bottom right corners. Also make the selection start xpointer more accurate by getting them in onHold(), instead of possibly too late in onHoldPan() where we have already moved. --- .../apps/reader/modules/readerhighlight.lua | 85 ++++++++++++++----- frontend/document/credocument.lua | 5 ++ 2 files changed, 68 insertions(+), 22 deletions(-) diff --git a/frontend/apps/reader/modules/readerhighlight.lua b/frontend/apps/reader/modules/readerhighlight.lua index 78a2b5118..487319f3d 100644 --- a/frontend/apps/reader/modules/readerhighlight.lua +++ b/frontend/apps/reader/modules/readerhighlight.lua @@ -434,6 +434,12 @@ function ReaderHighlight:onHold(arg, ges) -- Unfortunately, CREngine does not return good coordinates -- UIManager:setDirty(self.dialog, "partial", self.selected_word.sbox) self.hold_start_tv = TimeVal.now() + if word.pos0 then + -- Remember original highlight start position, so we can show + -- a marker when back from across-pages text selection, which + -- is handled in onHoldPan() + self.selected_text_start_xpointer = word.pos0 + end end return true end @@ -466,26 +472,60 @@ function ReaderHighlight:onHoldPan(_, ges) 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 + if self.ui.document:getVisiblePageCount() == 1 then -- single page mode + -- 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 -- two pages mode + -- We don't switch to scroll mode: we just turn 1 page to + -- allow continuing the selection. + -- Unlike in 1-page mode, we have a limitation here: we can't adjust + -- the selection to further than current page and prev/next one. + -- So don't handle another corner if we already handled one: + if self.restore_page_mode_func then + return true + end + -- Also, we are not able to move hold_pos.x out of screen, + -- so if we started on the right page, ignore top left corner, + -- and if we started on the left page, ignore bottom right corner. + local screen_half_width = math.floor(Screen:getWidth() * 1/2) + if self.hold_pos.x >= screen_half_width and is_in_top_left_corner then + return true + elseif self.hold_pos.x <= screen_half_width and is_in_bottom_right_corner then + return true + end + local cur_page = self.ui.document:getCurrentPage() 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")) + if is_in_bottom_right_corner then + self.ui.rolling:_gotoPage(cur_page + 1, true) -- no odd left page enforcement + self.hold_pos.x = self.hold_pos.x - screen_half_width + else + self.ui.rolling:_gotoPage(cur_page - 1, true) -- no odd left page enforcement + self.hold_pos.x = self.hold_pos.x + screen_half_width + end + UIManager:setDirty(self.dialog, "ui") + return true 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 @@ -495,14 +535,15 @@ function ReaderHighlight:onHoldPan(_, ges) 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 + -- This should have been set in onHold(), where we would get + -- a precise pos0 on the first word selected. + -- Do it here too in case onHold() missed it, but it could be + -- less precise (getTextFromPositions() does order pos0 and pos1, + -- so it's not certain pos0 is where we started from; we get + -- the ones from the first pan, and if it is not small enough + -- and spans quite some height, the marker could point away + -- from the start position) self.selected_text_start_xpointer = self.selected_text.pos0 end end diff --git a/frontend/document/credocument.lua b/frontend/document/credocument.lua index 174363032..71812058e 100644 --- a/frontend/document/credocument.lua +++ b/frontend/document/credocument.lua @@ -280,6 +280,11 @@ function CreDocument:getWordFromPosition(pos) w = 20, h = 20, } end + if text_range then + -- add xpointers if found, might be useful for across pages highlighting + wordbox.pos0 = text_range.pos0 + wordbox.pos1 = text_range.pos1 + end return wordbox end