2017-09-11 17:11:04 +02:00
local Blitbuffer = require ( " ffi/blitbuffer " )
2018-05-21 01:19:36 +02:00
local ConfirmBox = require ( " ui/widget/confirmbox " )
2014-10-30 19:42:18 +01:00
local Device = require ( " device " )
2017-05-06 19:54:31 +02:00
local InputContainer = require ( " ui/widget/container/inputcontainer " )
2013-10-22 17:11:31 +02:00
local Event = require ( " ui/event " )
2017-05-06 19:54:31 +02:00
local ReaderPanning = require ( " apps/reader/modules/readerpanning " )
2013-12-26 06:24:29 +08:00
local UIManager = require ( " ui/uimanager " )
2016-12-29 00:10:38 -08:00
local logger = require ( " logger " )
2013-10-18 22:38:07 +02:00
local _ = require ( " gettext " )
2017-05-06 19:54:31 +02:00
local Input = Device.input
local Screen = Device.screen
2016-12-17 15:58:09 -08:00
2014-10-10 18:12:25 +08:00
--[[
Rolling is just like paging in page - based documents except that
sometimes ( in scroll mode ) there is no concept of page number to indicate
current progress .
There are three kind of progress measurements for credocuments .
1. page number ( in page mode )
2. progress percentage ( in scroll mode )
3. xpointer ( in document dom structure )
We found that the first two measurements are not suitable for keeping a
record of the real progress . For example , when switching screen orientation
from portrait to landscape , or switching view mode from page to scroll , the
internal xpointer should not be used as the view dimen / mode is changed and
crengine ' s pagination mechanism will find a closest xpointer for the new view.
So if we change the screen orientation or view mode back , we cannot find the
original place since the internal xpointer is changed , which is counter -
intuitive as users didn ' t goto any other page.
The solution is that we keep a record of the internal xpointer and only change
it in explicit page turning . And use that xpointer for non - page - turning
rendering .
--]]
2013-10-18 22:38:07 +02:00
local ReaderRolling = InputContainer : new {
2017-03-23 11:40:42 -07:00
pan_rate = 30 , -- default 30 ops, will be adjusted in readerui
2014-03-13 21:52:43 +08:00
old_doc_height = nil ,
old_page = nil ,
current_pos = 0 ,
2016-06-10 21:17:42 +08:00
inverse_reading_order = false ,
2014-03-13 21:52:43 +08:00
-- only used for page view mode
current_page = nil ,
doc_height = nil ,
2014-10-10 18:12:25 +08:00
xpointer = nil ,
2014-03-13 21:52:43 +08:00
panning_steps = ReaderPanning.panning_steps ,
2014-11-13 12:37:10 +08:00
show_overlap_enable = nil ,
2018-04-14 00:26:57 +02:00
-- nb of lines from previous page to show on next page (scroll mode only)
overlap_lines = G_reader_settings : readSetting ( " copt_overlap_lines " ) or 1 ,
2017-10-05 21:49:59 +02:00
cre_top_bar_enabled = false ,
2012-06-05 15:23:36 +08:00
}
function ReaderRolling : init ( )
2014-06-10 15:57:10 +08:00
if Device : hasKeyboard ( ) or Device : hasKeys ( ) then
2014-03-13 21:52:43 +08:00
self.key_events = {
GotoNextView = {
{ Input.group . PgFwd } ,
2014-06-05 14:58:53 +08:00
doc = " go to next view " ,
2014-03-13 21:52:43 +08:00
event = " GotoViewRel " , args = 1
} ,
GotoPrevView = {
{ Input.group . PgBack } ,
2014-06-05 14:58:53 +08:00
doc = " go to previous view " ,
2014-03-13 21:52:43 +08:00
event = " GotoViewRel " , args = - 1
} ,
MoveUp = {
{ " Up " } ,
2014-06-05 14:58:53 +08:00
doc = " move view up " ,
2014-03-13 21:52:43 +08:00
event = " Panning " , args = { 0 , - 1 }
} ,
MoveDown = {
{ " Down " } ,
2014-06-05 14:58:53 +08:00
doc = " move view down " ,
2014-03-13 21:52:43 +08:00
event = " Panning " , args = { 0 , 1 }
} ,
GotoFirst = {
2014-06-05 14:58:53 +08:00
{ " 1 " } , doc = " go to start " , event = " GotoPercent " , args = 0 } ,
2014-03-13 21:52:43 +08:00
Goto11 = {
2014-06-05 14:58:53 +08:00
{ " 2 " } , doc = " go to 11% " , event = " GotoPercent " , args = 11 } ,
2014-03-13 21:52:43 +08:00
Goto22 = {
2014-06-05 14:58:53 +08:00
{ " 3 " } , doc = " go to 22% " , event = " GotoPercent " , args = 22 } ,
2014-03-13 21:52:43 +08:00
Goto33 = {
2014-06-05 14:58:53 +08:00
{ " 4 " } , doc = " go to 33% " , event = " GotoPercent " , args = 33 } ,
2014-03-13 21:52:43 +08:00
Goto44 = {
2014-06-05 14:58:53 +08:00
{ " 5 " } , doc = " go to 44% " , event = " GotoPercent " , args = 44 } ,
2014-03-13 21:52:43 +08:00
Goto55 = {
2014-06-05 14:58:53 +08:00
{ " 6 " } , doc = " go to 55% " , event = " GotoPercent " , args = 55 } ,
2014-03-13 21:52:43 +08:00
Goto66 = {
2014-06-05 14:58:53 +08:00
{ " 7 " } , doc = " go to 66% " , event = " GotoPercent " , args = 66 } ,
2014-03-13 21:52:43 +08:00
Goto77 = {
2014-06-05 14:58:53 +08:00
{ " 8 " } , doc = " go to 77% " , event = " GotoPercent " , args = 77 } ,
2014-03-13 21:52:43 +08:00
Goto88 = {
2014-06-05 14:58:53 +08:00
{ " 9 " } , doc = " go to 88% " , event = " GotoPercent " , args = 88 } ,
2014-03-13 21:52:43 +08:00
GotoLast = {
2014-06-05 14:58:53 +08:00
{ " 0 " } , doc = " go to end " , event = " GotoPercent " , args = 100 } ,
2014-03-13 21:52:43 +08:00
}
end
table.insert ( self.ui . postInitCallback , function ( )
self.doc_height = self.ui . document.info . doc_height
self.old_doc_height = self.doc_height
2017-10-03 00:31:14 +02:00
self.ui . document : _readMetadata ( )
self.old_page = self.ui . document.info . number_of_pages
2014-03-13 21:52:43 +08:00
end )
2017-10-05 17:12:49 +02:00
table.insert ( self.ui . postReaderCallback , function ( )
self : updatePos ( )
2018-03-12 20:46:40 +01:00
-- Disable crengine internal history, with required redraw
self.ui . document : enableInternalHistory ( false )
self : onRedrawCurrentView ( )
2017-10-05 17:12:49 +02:00
end )
2014-11-13 12:37:10 +08:00
self.ui . menu : registerToMainMenu ( self )
2012-06-05 15:23:36 +08:00
end
2012-12-04 17:05:40 +08:00
function ReaderRolling : onReadSettings ( config )
2018-05-05 00:38:50 +02:00
-- 20180503: some fix in crengine has changed the way the DOM is built
-- for HTML documents and may make XPATHs obtained from previous version
-- invalid.
-- We may request the previous (buggy) behaviour though, which we do
-- if we use a DocSetting previously made that may contain bookmarks
-- and highlights with old XPATHs.
-- (EPUB will use the same correct DOM code no matter what DOM version
-- we request here.)
if not config : readSetting ( " cre_dom_version " ) then
-- Not previously set, guess which DOM version to use
if config : readSetting ( " last_xpointer " ) then
-- We have a last_xpointer: this book was previously opened
-- with possibly a very old version: request the oldest
config : saveSetting ( " cre_dom_version " , self.ui . document : getOldestDomVersion ( ) )
else
-- No previous xpointer: book never opened (or sidecar file
-- purged): we can use the latest DOM version
config : saveSetting ( " cre_dom_version " , self.ui . document : getLatestDomVersion ( ) )
end
end
self.ui . document : requestDomVersion ( config : readSetting ( " cre_dom_version " ) )
2014-03-13 21:52:43 +08:00
local last_xp = config : readSetting ( " last_xpointer " )
2014-10-10 18:12:25 +08:00
local last_per = config : readSetting ( " last_percent " )
2014-03-13 21:52:43 +08:00
if last_xp then
2016-10-04 10:38:32 -07:00
self.xpointer = last_xp
2016-12-17 15:58:09 -08:00
self.setupXpointer = function ( )
2016-03-27 15:39:47 -07:00
self : _gotoXPointer ( self.xpointer )
2014-03-13 21:52:43 +08:00
-- we have to do a real jump in self.ui.document._document to
-- update status information in CREngine.
2014-10-10 18:12:25 +08:00
self.ui . document : gotoXPointer ( self.xpointer )
2016-10-04 10:38:32 -07:00
end
2014-03-13 21:52:43 +08:00
-- we read last_percent just for backward compatibility
2016-03-28 21:23:33 -07:00
-- FIXME: remove this branch with migration script
2014-10-10 18:12:25 +08:00
elseif last_per then
2016-12-17 15:58:09 -08:00
self.setupXpointer = function ( )
2016-03-27 15:39:47 -07:00
self : _gotoPercent ( last_per )
2016-03-28 21:23:33 -07:00
-- _gotoPercent calls _gotoPos, which only updates self.current_pos
-- and self.view.
-- we need to do a real pos change in self.ui.document._document
2014-10-10 18:12:25 +08:00
-- to update status information in CREngine.
self.ui . document : gotoPos ( self.current_pos )
2016-03-28 21:23:33 -07:00
-- _gotoPercent already calls gotoPos, so no need to emit
-- PosUpdate event in scroll mode
if self.view . view_mode == " page " then
self.ui : handleEvent (
Event : new ( " PageUpdate " , self.ui . document : getCurrentPage ( ) ) )
end
2014-10-10 18:12:25 +08:00
self.xpointer = self.ui . document : getXPointer ( )
2016-10-04 10:38:32 -07:00
end
2014-10-10 18:12:25 +08:00
else
2016-12-17 15:58:09 -08:00
self.setupXpointer = function ( )
2016-10-04 10:38:32 -07:00
self.xpointer = self.ui . document : getXPointer ( )
if self.view . view_mode == " page " then
self.ui : handleEvent ( Event : new ( " PageUpdate " , 1 ) )
end
2014-03-13 21:52:43 +08:00
end
end
2014-11-13 12:37:10 +08:00
self.show_overlap_enable = config : readSetting ( " show_overlap_enable " )
if self.show_overlap_enable == nil then
self.show_overlap_enable = DSHOWOVERLAP
end
2016-06-10 21:17:42 +08:00
self.inverse_reading_order = config : readSetting ( " inverse_reading_order " ) or false
2017-10-05 21:49:59 +02:00
self : onSetStatusLine ( config : readSetting ( " copt_status_line " ) or DCREREADER_PROGRESS_BAR )
2012-06-05 15:23:36 +08:00
end
2017-09-05 18:22:36 +02:00
-- in scroll mode percent_finished must be save before close document
-- we cannot do it in onSaveSettings() because getLastPercent() uses self.ui.document
function ReaderRolling : onCloseDocument ( )
self.ui . doc_settings : saveSetting ( " percent_finished " , self : getLastPercent ( ) )
2018-05-21 01:19:36 +02:00
-- also checks if DOM is coherent with styles; if not, invalidate the
-- cache, so a new DOM is built on next opening
if self.ui . document : isBuiltDomStale ( ) then
if self.ui . document : hasCacheFile ( ) then
logger.dbg ( " cre DOM may not be in sync with styles, invalidating cache file for a full reload at next opening " )
self.ui . document : invalidateCacheFile ( )
end
end
logger.dbg ( " cre cache used: " , self.ui . document : getCacheFilePath ( ) or " none " )
end
function ReaderRolling : onCheckDomStyleCoherence ( )
if self.ui . document : isBuiltDomStale ( ) then
UIManager : show ( ConfirmBox : new {
text = _ ( " Styles have changed in such a way that fully reloading the document may be needed for a correct rendering. \n Do you want to reload the document? " ) ,
ok_callback = function ( )
-- Allow for ConfirmBox to be closed before showing
-- "Opening file" InfoMessage
UIManager : scheduleIn ( 0.5 , function ( )
self.ui : reloadDocument ( )
end )
end ,
} )
end
2017-09-05 18:22:36 +02:00
end
2013-12-27 23:18:16 +08:00
function ReaderRolling : onSaveSettings ( )
2014-03-13 21:52:43 +08:00
-- remove last_percent config since its deprecated
self.ui . doc_settings : saveSetting ( " last_percent " , nil )
2014-10-10 18:12:25 +08:00
self.ui . doc_settings : saveSetting ( " last_xpointer " , self.xpointer )
2017-09-05 18:22:36 +02:00
-- in scrolling mode, the document may already be closed,
-- so we have to check the condition to avoid crash function self:getLastPercent()
-- that uses self.ui.document
if self.ui . document then
self.ui . doc_settings : saveSetting ( " percent_finished " , self : getLastPercent ( ) )
end
2014-11-13 12:37:10 +08:00
self.ui . doc_settings : saveSetting ( " show_overlap_enable " , self.show_overlap_enable )
2016-06-10 21:17:42 +08:00
self.ui . doc_settings : saveSetting ( " inverse_reading_order " , self.inverse_reading_order )
2014-11-13 12:37:10 +08:00
end
2016-12-17 15:58:09 -08:00
function ReaderRolling : onReaderReady ( )
self : setupTouchZones ( )
2017-10-03 21:33:12 +02:00
self.setupXpointer ( )
2016-12-17 15:58:09 -08:00
end
function ReaderRolling : setupTouchZones ( )
self.ges_events = { }
self.onGesture = nil
if not Device : isTouchDevice ( ) then return end
local forward_zone = {
ratio_x = DTAP_ZONE_FORWARD.x , ratio_y = DTAP_ZONE_FORWARD.y ,
ratio_w = DTAP_ZONE_FORWARD.w , ratio_h = DTAP_ZONE_FORWARD.h ,
}
local backward_zone = {
ratio_x = DTAP_ZONE_BACKWARD.x , ratio_y = DTAP_ZONE_BACKWARD.y ,
ratio_w = DTAP_ZONE_BACKWARD.w , ratio_h = DTAP_ZONE_BACKWARD.h ,
}
local forward_double_tap_zone = {
ratio_x = DDOUBLE_TAP_ZONE_NEXT_CHAPTER.x , ratio_y = DDOUBLE_TAP_ZONE_NEXT_CHAPTER.y ,
ratio_w = DDOUBLE_TAP_ZONE_NEXT_CHAPTER.w , ratio_h = DDOUBLE_TAP_ZONE_NEXT_CHAPTER.h ,
}
local backward_double_tap_zone = {
ratio_x = DDOUBLE_TAP_ZONE_PREV_CHAPTER.x , ratio_y = DDOUBLE_TAP_ZONE_PREV_CHAPTER.y ,
ratio_w = DDOUBLE_TAP_ZONE_PREV_CHAPTER.w , ratio_h = DDOUBLE_TAP_ZONE_PREV_CHAPTER.h ,
}
if self.inverse_reading_order then
forward_zone.ratio_x = 1 - forward_zone.ratio_x - forward_zone.ratio_w
backward_zone.ratio_x = 1 - backward_zone.ratio_x - backward_zone.ratio_w
forward_double_tap_zone.ratio_x =
1 - forward_double_tap_zone.ratio_x - forward_double_tap_zone.ratio_w
backward_double_tap_zone.ratio_x =
1 - backward_double_tap_zone.ratio_x - backward_double_tap_zone.ratio_w
end
self.ui : registerTouchZones ( {
{
id = " tap_forward " ,
ges = " tap " ,
screen_zone = forward_zone ,
handler = function ( ) return self : onTapForward ( ) end
} ,
{
id = " tap_backward " ,
ges = " tap " ,
screen_zone = backward_zone ,
handler = function ( ) return self : onTapBackward ( ) end
} ,
{
id = " double_tap_forward " ,
ges = " double_tap " ,
screen_zone = forward_double_tap_zone ,
handler = function ( ) return self : onDoubleTapForward ( ) end
} ,
{
id = " double_tap_backward " ,
ges = " double_tap " ,
screen_zone = backward_double_tap_zone ,
handler = function ( ) return self : onDoubleTapBackward ( ) end
} ,
{
id = " rolling_swipe " ,
ges = " swipe " ,
screen_zone = {
ratio_x = 0 , ratio_y = 0 , ratio_w = 1 , ratio_h = 1 ,
} ,
handler = function ( ges ) return self : onSwipe ( nil , ges ) end
} ,
{
id = " rolling_pan " ,
ges = " pan " ,
2017-03-23 11:40:42 -07:00
rate = self.pan_rate ,
2016-12-17 15:58:09 -08:00
screen_zone = {
ratio_x = 0 , ratio_y = 0 , ratio_w = 1 , ratio_h = 1 ,
} ,
handler = function ( ges ) return self : onPan ( nil , ges ) end
} ,
} )
end
2015-03-09 20:20:32 +08:00
function ReaderRolling : getLastProgress ( )
return self.xpointer
end
2017-03-04 14:46:38 +01:00
function ReaderRolling : addToMainMenu ( menu_items )
2014-11-17 21:44:13 +08:00
-- FIXME: repeated code with page overlap menu for readerpaging
-- needs to keep only one copy of the logic as for the DRY principle.
-- The difference between the two menus is only the enabled func.
local page_overlap_menu = {
{
text_func = function ( )
return self.show_overlap_enable and _ ( " Disable " ) or _ ( " Enable " )
end ,
callback = function ( )
self.show_overlap_enable = not self.show_overlap_enable
if not self.show_overlap_enable then
self.view : resetDimArea ( )
end
end
} ,
}
for _ , menu_entry in ipairs ( self.view : genOverlapStyleMenu ( ) ) do
table.insert ( page_overlap_menu , menu_entry )
end
2017-03-04 14:46:38 +01:00
menu_items.page_overlap = {
2014-11-17 21:44:13 +08:00
text = _ ( " Page overlap " ) ,
2014-11-13 12:37:10 +08:00
enabled_func = function ( ) return self.view . view_mode ~= " page " end ,
2014-11-17 21:44:13 +08:00
sub_item_table = page_overlap_menu ,
2017-02-28 22:46:32 +01:00
}
2013-01-17 22:18:32 +08:00
end
function ReaderRolling : getLastPercent ( )
2014-03-13 21:52:43 +08:00
if self.view . view_mode == " page " then
2017-10-03 21:33:12 +02:00
return self.current_page / self.old_page
2014-03-13 21:52:43 +08:00
else
-- FIXME: the calculated percent is not accurate in "scroll" mode.
return self.ui . document : getPosFromXPointer (
self.ui . document : getXPointer ( ) ) / self.doc_height
end
2012-06-12 17:42:02 +08:00
end
2012-12-04 17:05:40 +08:00
function ReaderRolling : onTapForward ( )
2014-03-13 21:52:43 +08:00
self : onGotoViewRel ( 1 )
return true
2012-06-27 01:00:21 +08:00
end
2012-12-04 17:05:40 +08:00
function ReaderRolling : onTapBackward ( )
2014-03-13 21:52:43 +08:00
self : onGotoViewRel ( - 1 )
return true
2012-06-27 01:00:21 +08:00
end
2016-12-17 15:58:09 -08:00
function ReaderRolling : onSwipe ( _ , ges )
2016-06-10 21:17:42 +08:00
if ges.direction == " north " then
2016-02-14 13:47:36 -08:00
self : onGotoViewRel ( 1 )
2016-06-10 21:17:42 +08:00
elseif ges.direction == " south " then
2016-02-14 13:47:36 -08:00
self : onGotoViewRel ( - 1 )
2016-06-10 21:17:42 +08:00
elseif ges.direction == " west " then
if self.inverse_reading_order then
2016-06-17 00:00:58 +08:00
self : onGotoViewRel ( - 1 )
2016-06-10 21:17:42 +08:00
else
2016-06-17 00:00:58 +08:00
self : onGotoViewRel ( 1 )
2016-06-10 21:17:42 +08:00
end
elseif ges.direction == " east " then
if self.inverse_reading_order then
2016-06-17 00:00:58 +08:00
self : onGotoViewRel ( 1 )
2016-06-10 21:17:42 +08:00
else
2016-06-17 00:00:58 +08:00
self : onGotoViewRel ( - 1 )
2016-06-10 21:17:42 +08:00
end
2017-03-19 21:35:18 +01:00
else
-- update footer (time & battery)
self.view . footer : updateFooter ( )
-- trigger full refresh
UIManager : setDirty ( nil , " full " )
2014-03-13 21:52:43 +08:00
end
2013-04-14 18:19:42 +08:00
end
2016-12-17 15:58:09 -08:00
function ReaderRolling : onPan ( _ , ges )
2014-03-13 21:52:43 +08:00
if self.view . view_mode == " scroll " then
if ges.direction == " north " then
2016-03-27 15:39:47 -07:00
self : _gotoPos ( self.current_pos + ges.distance )
2014-03-13 21:52:43 +08:00
elseif ges.direction == " south " then
2016-03-27 15:39:47 -07:00
self : _gotoPos ( self.current_pos - ges.distance )
2014-03-13 21:52:43 +08:00
end
end
return true
2013-04-21 05:55:17 +08:00
end
2012-12-04 17:05:40 +08:00
function ReaderRolling : onPosUpdate ( new_pos )
2014-03-13 21:52:43 +08:00
self.current_pos = new_pos
self : updateBatteryState ( )
2012-06-12 00:34:30 +08:00
end
2012-12-22 13:27:46 +08:00
function ReaderRolling : onPageUpdate ( new_page )
2014-03-13 21:52:43 +08:00
self.current_page = new_page
self : updateBatteryState ( )
2012-12-22 13:27:46 +08:00
end
2014-01-16 18:34:46 -05:00
function ReaderRolling : onResume ( )
2017-03-24 18:57:07 +01:00
self : updateBatteryState ( )
2014-01-16 18:34:46 -05:00
end
2014-07-03 18:18:33 +02:00
function ReaderRolling : onDoubleTapForward ( )
2014-10-10 18:12:25 +08:00
local visible_page_count = self.ui . document : getVisiblePageCount ( )
local pageno = self.current_page + ( visible_page_count > 1 and 1 or 0 )
2014-10-09 09:42:31 +08:00
self : onGotoPage ( self.ui . toc : getNextChapter ( pageno , 0 ) )
2014-07-03 18:18:33 +02:00
return true
end
function ReaderRolling : onDoubleTapBackward ( )
2014-10-09 09:42:31 +08:00
local pageno = self.current_page
self : onGotoPage ( self.ui . toc : getPreviousChapter ( pageno , 0 ) )
2014-07-03 18:18:33 +02:00
return true
end
2014-01-16 18:34:46 -05:00
function ReaderRolling : onNotCharging ( )
2014-03-13 21:52:43 +08:00
self : updateBatteryState ( )
2014-01-16 18:34:46 -05:00
end
2012-06-05 15:23:36 +08:00
function ReaderRolling : onGotoPercent ( percent )
2016-12-29 00:10:38 -08:00
logger.dbg ( " goto document offset in percent: " , percent )
2016-03-27 15:39:47 -07:00
self : _gotoPercent ( percent )
self.xpointer = self.ui . document : getXPointer ( )
2014-03-13 21:52:43 +08:00
return true
2012-06-05 15:23:36 +08:00
end
2014-10-10 18:12:25 +08:00
function ReaderRolling : onGotoPage ( number )
if number then
2016-03-27 15:39:47 -07:00
self : _gotoPage ( number )
2014-10-10 18:12:25 +08:00
end
self.xpointer = self.ui . document : getXPointer ( )
return true
end
2015-03-12 15:45:58 +08:00
function ReaderRolling : onGotoRelativePage ( number )
if number then
2016-03-27 15:39:47 -07:00
self : _gotoPage ( self.current_page + number )
2015-03-12 15:45:58 +08:00
end
self.xpointer = self.ui . document : getXPointer ( )
return true
end
2018-02-09 17:06:16 +01:00
function ReaderRolling : onGotoXPointer ( xp , marker_xp )
if self.mark_func then
-- unschedule previous marker as it's no more accurate
UIManager : unschedule ( self.mark_func )
self.mark_func = nil
end
if self.unmark_func then
-- execute scheduled unmark now to clean previous marker
self.unmark_func ( )
self.unmark_func = nil
end
2016-03-27 15:39:47 -07:00
self : _gotoXPointer ( xp )
2014-10-20 22:55:21 +08:00
self.xpointer = xp
2018-02-09 17:06:16 +01:00
-- Allow tweaking this marker behaviour with a manual setting:
-- followed_link_marker = false: no marker shown
-- followed_link_marker = true: maker shown and not auto removed
-- followed_link_marker = <number>: removed after <number> seconds
-- (no real need for a menu item, the default is the finest)
local marker_setting = G_reader_settings : readSetting ( " followed_link_marker " )
if marker_setting == nil then
marker_setting = 1 -- default is: shown and removed after 1 second
end
if marker_xp and marker_setting then
-- Show a mark on left side of screen to give a visual feedback of
-- where xpointer target is (and remove if after 1s)
local doc_y = self.ui . document : getPosFromXPointer ( marker_xp )
2017-09-11 17:11:04 +02:00
local top_y = self.ui . document : getCurrentPos ( )
2018-02-09 17:06:16 +01:00
local screen_y = doc_y - top_y
2017-09-11 17:11:04 +02:00
local doc_margins = self.ui . document._document : getPageMargins ( )
2018-02-09 17:06:16 +01:00
if self.view . view_mode == " page " then
screen_y = screen_y + doc_margins [ " top " ]
end
2017-09-11 17:11:04 +02:00
local marker_h = Screen : scaleBySize ( self.ui . font.font_size * 1.1 * self.ui . font.line_space_percent / 100.0 )
2018-02-09 17:06:16 +01:00
-- Make it 4/5 of left margin wide (and bigger when huge margin)
local marker_w = math.floor ( math.max ( doc_margins [ " left " ] - Screen : scaleBySize ( 5 ) , doc_margins [ " left " ] * 4 / 5 ) )
self.mark_func = function ( )
self.mark_func = nil
2017-09-11 17:11:04 +02:00
Screen.bb : paintRect ( 0 , screen_y , marker_w , marker_h , Blitbuffer.COLOR_BLACK )
2018-02-09 17:06:16 +01:00
Screen [ " refreshUI " ] ( Screen , 0 , screen_y , marker_w , marker_h )
if type ( marker_setting ) == " number " then -- hide it
self.unmark_func = function ( )
self.unmark_func = nil
-- UIManager:setDirty(self.view.dialog, "ui", Geom:new({x=0, y=screen_y, w=marker_w, h=marker_h}))
-- No need to use setDirty (which would ask crengine to
-- re-render the page, which may take a few seconds on big
-- documents): we drew our black marker in the margin, we
-- can just draw a white one to make it disappear
Screen.bb : paintRect ( 0 , screen_y , marker_w , marker_h , Blitbuffer.COLOR_WHITE )
Screen [ " refreshUI " ] ( Screen , 0 , screen_y , marker_w , marker_h )
end
UIManager : scheduleIn ( marker_setting , self.unmark_func )
end
end
UIManager : scheduleIn ( 0.5 , self.mark_func )
2017-09-11 17:11:04 +02:00
end
2014-10-20 22:55:21 +08:00
return true
end
2016-03-27 15:39:47 -07:00
function ReaderRolling : getBookLocation ( )
return self.xpointer
end
function ReaderRolling : onRestoreBookLocation ( saved_location )
2018-02-09 17:06:16 +01:00
return self : onGotoXPointer ( saved_location.xpointer , saved_location.marker_xpointer )
2016-03-27 15:39:47 -07:00
end
2012-06-05 15:23:36 +08:00
function ReaderRolling : onGotoViewRel ( diff )
2016-12-29 00:10:38 -08:00
logger.dbg ( " goto relative screen: " , diff , " , in mode: " , self.view . view_mode )
2014-03-13 21:52:43 +08:00
if self.view . view_mode == " scroll " then
2018-04-14 00:26:57 +02:00
local footer_height = ( self.view . footer_visible and 1 or 0 ) * self.view . footer : getHeight ( )
local page_visible_height = self.ui . dimen.h - footer_height
local pan_diff = diff * page_visible_height
2014-03-13 21:52:43 +08:00
if self.show_overlap_enable then
2018-04-14 00:26:57 +02:00
local overlap_h = Screen : scaleBySize ( self.ui . font.font_size * 1.1 * self.ui . font.line_space_percent / 100.0 ) * self.overlap_lines
if pan_diff > overlap_h then
pan_diff = pan_diff - overlap_h
elseif pan_diff < - overlap_h then
pan_diff = pan_diff + overlap_h
2014-03-13 21:52:43 +08:00
end
end
2016-04-20 21:41:34 -07:00
local old_pos = self.current_pos
2018-04-14 00:26:57 +02:00
-- Only draw dim area when we moved a whole page (not when smaller scroll with Pan)
local do_dim_area = math.abs ( diff ) == 1
self : _gotoPos ( self.current_pos + pan_diff , do_dim_area )
2016-04-20 21:41:34 -07:00
if diff > 0 and old_pos == self.current_pos then
self.ui : handleEvent ( Event : new ( " EndOfBook " ) )
end
2014-03-13 21:52:43 +08:00
elseif self.view . view_mode == " page " then
2014-07-04 22:09:19 +08:00
local page_count = self.ui . document : getVisiblePageCount ( )
2016-04-20 21:41:34 -07:00
local old_page = self.current_page
2016-03-27 15:39:47 -07:00
self : _gotoPage ( self.current_page + diff * page_count )
2016-04-20 21:41:34 -07:00
if diff > 0 and old_page == self.current_page then
self.ui : handleEvent ( Event : new ( " EndOfBook " ) )
end
2014-03-13 21:52:43 +08:00
end
2018-05-13 13:07:23 +02:00
if self.ui . document ~= nil then
self.xpointer = self.ui . document : getXPointer ( )
end
2014-03-13 21:52:43 +08:00
return true
2012-06-05 15:23:36 +08:00
end
2016-12-29 00:10:38 -08:00
function ReaderRolling : onPanning ( args , _ )
2014-03-13 21:52:43 +08:00
--@TODO disable panning in page view_mode? 22.12 2012 (houqp)
local _ , dy = unpack ( args )
2016-03-27 15:39:47 -07:00
self : _gotoPos ( self.current_pos + dy * self.panning_steps . normal )
2014-10-10 18:12:25 +08:00
self.xpointer = self.ui . document : getXPointer ( )
2014-03-13 21:52:43 +08:00
return true
2012-06-05 19:03:06 +08:00
end
2012-06-05 15:23:36 +08:00
function ReaderRolling : onZoom ( )
2014-03-13 21:52:43 +08:00
--@TODO re-read doc_height info after font or lineheight changes 05.06 2012 (houqp)
self : updatePos ( )
2012-06-05 15:23:36 +08:00
end
2012-06-27 01:00:21 +08:00
2012-12-22 13:27:46 +08:00
--[[
2014-03-13 21:52:43 +08:00
remember to signal this event when the document has been zoomed ,
font has been changed , or line height has been changed .
2014-10-10 18:12:25 +08:00
Note that xpointer should not be changed .
2012-12-22 13:27:46 +08:00
--]]
2012-12-04 17:05:40 +08:00
function ReaderRolling : onUpdatePos ( )
2017-10-05 17:12:49 +02:00
if self.ui . postReaderCallback ~= nil then -- ReaderUI:init() not yet done
-- Don't schedule any updatePos as long as ReaderUI:init() is
-- not finished (one will be called in the ui.postReaderCallback
-- we have set above) to avoid multiple refreshes.
return true
end
2014-03-13 21:52:43 +08:00
UIManager : scheduleIn ( 0.1 , function ( ) self : updatePos ( ) end )
return true
2013-12-26 06:24:29 +08:00
end
function ReaderRolling : updatePos ( )
2014-03-13 21:52:43 +08:00
-- reread document height
self.ui . document : _readMetadata ( )
-- update self.current_pos if the height of document has been changed.
local new_height = self.ui . document.info . doc_height
local new_page = self.ui . document.info . number_of_pages
if self.old_doc_height ~= new_height or self.old_page ~= new_page then
2017-10-03 21:33:12 +02:00
self : _gotoXPointer ( self.xpointer )
2014-03-13 21:52:43 +08:00
self.old_doc_height = new_height
self.old_page = new_page
self.ui : handleEvent ( Event : new ( " UpdateToc " ) )
2018-05-14 22:06:35 +02:00
self.view . footer : updateFooter ( )
2014-03-13 21:52:43 +08:00
end
2014-11-30 00:12:00 +00:00
UIManager : setDirty ( self.view . dialog , " partial " )
2018-05-21 01:19:36 +02:00
-- Allow for the new rendering to be shown before possibly showing
-- the "Styles have changes..." ConfirmBox so the user can decide
-- if it is really needed
UIManager : scheduleIn ( 0.1 , function ( )
self : onCheckDomStyleCoherence ( )
end )
2012-12-04 17:05:40 +08:00
end
2014-10-10 18:12:25 +08:00
--[[
switching screen mode should not change current page number
--]]
2013-05-18 13:35:12 -04:00
function ReaderRolling : onChangeViewMode ( )
2014-03-13 21:52:43 +08:00
self.ui . document : _readMetadata ( )
self.old_doc_height = self.ui . document.info . doc_height
self.old_page = self.ui . document.info . number_of_pages
self.ui : handleEvent ( Event : new ( " UpdateToc " ) )
2017-10-03 21:33:12 +02:00
if self.xpointer then
2016-03-27 15:39:47 -07:00
self : _gotoXPointer ( self.xpointer )
2017-10-03 21:33:12 +02:00
else
2014-10-10 18:12:25 +08:00
table.insert ( self.ui . postInitCallback , function ( )
2016-03-27 15:39:47 -07:00
self : _gotoXPointer ( self.xpointer )
2014-10-10 18:12:25 +08:00
end )
2014-03-13 21:52:43 +08:00
end
return true
2013-05-18 13:35:12 -04:00
end
2013-01-07 16:43:28 -05:00
function ReaderRolling : onRedrawCurrentView ( )
2014-03-13 21:52:43 +08:00
if self.view . view_mode == " page " then
self.ui : handleEvent ( Event : new ( " PageUpdate " , self.current_page ) )
else
self.ui : handleEvent ( Event : new ( " PosUpdate " , self.current_pos ) )
end
return true
2013-01-07 16:43:28 -05:00
end
2014-10-10 18:12:25 +08:00
function ReaderRolling : onSetDimensions ( dimen )
self.ui . document : setViewDimen ( Screen : getSize ( ) )
2013-02-02 14:36:29 +08:00
end
2014-02-02 00:18:06 +08:00
function ReaderRolling : onChangeScreenMode ( mode )
2018-03-12 20:46:40 +01:00
-- We need to temporarily re-enable internal history as crengine
-- uses it to reposition after resize
self.ui . document : enableInternalHistory ( true )
2014-03-13 21:52:43 +08:00
self.ui : handleEvent ( Event : new ( " SetScreenMode " , mode ) )
2014-10-10 18:12:25 +08:00
self.ui . document : setViewDimen ( Screen : getSize ( ) )
2014-03-13 21:52:43 +08:00
self : onChangeViewMode ( )
2014-07-16 14:47:27 +02:00
self : onUpdatePos ( )
2018-03-12 20:46:40 +01:00
-- Re-disable internal history, with required redraw
self.ui . document : enableInternalHistory ( false )
self : onRedrawCurrentView ( )
2014-02-02 00:18:06 +08:00
end
2017-10-01 19:23:06 +02:00
function ReaderRolling : onColorRenderingUpdate ( )
self.ui . document : updateColorRendering ( )
end
2012-12-22 13:27:46 +08:00
--[[
2014-03-13 21:52:43 +08:00
PosUpdate event is used to signal other widgets that pos has been changed .
2012-12-22 13:27:46 +08:00
--]]
2018-04-14 00:26:57 +02:00
function ReaderRolling : _gotoPos ( new_pos , do_dim_area )
2014-03-13 21:52:43 +08:00
if new_pos == self.current_pos then return end
if new_pos < 0 then new_pos = 0 end
if new_pos > self.doc_height then new_pos = self.doc_height end
-- adjust dim_area according to new_pos
2018-04-14 00:26:57 +02:00
if self.view . view_mode ~= " page " and self.show_overlap_enable and do_dim_area then
local footer_height = ( self.view . footer_visible and 1 or 0 ) * self.view . footer : getHeight ( )
local page_visible_height = self.ui . dimen.h - footer_height
2014-03-13 21:52:43 +08:00
local panned_step = new_pos - self.current_pos
self.view . dim_area.x = 0
2018-04-14 00:26:57 +02:00
self.view . dim_area.h = page_visible_height - math.abs ( panned_step )
2014-03-13 21:52:43 +08:00
self.view . dim_area.w = self.ui . dimen.w
if panned_step < 0 then
2018-04-14 00:26:57 +02:00
self.view . dim_area.y = page_visible_height - self.view . dim_area.h
2014-03-13 21:52:43 +08:00
elseif panned_step > 0 then
self.view . dim_area.y = 0
end
2018-04-14 00:26:57 +02:00
else
self.view : resetDimArea ( )
2014-03-13 21:52:43 +08:00
end
2017-10-10 11:57:57 +02:00
self.ui . document : gotoPos ( new_pos )
2017-10-05 21:49:59 +02:00
-- The current page we get in scroll mode may be a bit innacurate,
-- but we give it anyway to onPosUpdate so footer and statistics can
-- keep up with page.
self.ui : handleEvent ( Event : new ( " PosUpdate " , new_pos , self.ui . document : getCurrentPage ( ) ) )
2012-12-04 17:05:40 +08:00
end
2016-03-27 15:39:47 -07:00
function ReaderRolling : _gotoPercent ( new_percent )
self : _gotoPos ( new_percent * self.doc_height / 10000 )
2014-10-10 18:12:25 +08:00
end
2016-03-27 15:39:47 -07:00
function ReaderRolling : _gotoPage ( new_page )
2014-03-13 21:52:43 +08:00
self.ui . document : gotoPage ( new_page )
2017-10-10 11:57:57 +02:00
if self.view . view_mode == " page " then
self.ui : handleEvent ( Event : new ( " PageUpdate " , self.ui . document : getCurrentPage ( ) ) )
else
self.ui : handleEvent ( Event : new ( " PosUpdate " , self.ui . document : getCurrentPos ( ) , self.ui . document : getCurrentPage ( ) ) )
end
2012-12-22 13:27:46 +08:00
end
2016-03-27 15:39:47 -07:00
function ReaderRolling : _gotoXPointer ( xpointer )
2014-03-13 21:52:43 +08:00
if self.view . view_mode == " page " then
2016-03-27 15:39:47 -07:00
self : _gotoPage ( self.ui . document : getPageFromXPointer ( xpointer ) )
2014-03-13 21:52:43 +08:00
else
2016-03-27 15:39:47 -07:00
self : _gotoPos ( self.ui . document : getPosFromXPointer ( xpointer ) )
2014-03-13 21:52:43 +08:00
end
2012-12-22 13:27:46 +08:00
end
2014-01-20 20:41:01 +08:00
--[[
currently we don ' t need to get page links on each page/pos update
since we can check link on the fly when tapping on the screen
--]]
2014-01-15 23:34:37 +08:00
function ReaderRolling : updatePageLink ( )
2016-12-29 00:10:38 -08:00
logger.dbg ( " update page link " )
2014-03-13 21:52:43 +08:00
local links = self.ui . document : getPageLinks ( )
self.view . links = links
2014-01-15 23:34:37 +08:00
end
2017-10-05 21:49:59 +02:00
function ReaderRolling : onSetStatusLine ( status_line )
self.cre_top_bar_enabled = status_line == 0
end
2014-01-04 22:30:36 +08:00
function ReaderRolling : updateBatteryState ( )
2017-10-05 21:49:59 +02:00
if self.view . view_mode == " page " and self.cre_top_bar_enabled then
logger.dbg ( " update battery state " )
2014-03-13 21:52:43 +08:00
local powerd = Device : getPowerDevice ( )
2015-09-09 17:37:35 +02:00
-- -1 is CR_BATTERY_STATE_CHARGING @ crengine/crengine/include/lvdocview.h
2014-03-13 21:52:43 +08:00
local state = powerd : isCharging ( ) and - 1 or powerd : getCapacity ( )
if state then
self.ui . document : setBatteryState ( state )
end
end
2014-01-04 22:30:36 +08:00
end
2013-10-18 22:38:07 +02:00
return ReaderRolling