2016-12-25 20:13:30 +00:00
--[[--
ReaderView module handles all the screen painting for document browsing .
] ]
2017-05-22 14:21:23 +00:00
local Blitbuffer = require ( " ffi/blitbuffer " )
2016-10-14 18:11:35 +00:00
local Device = require ( " device " )
2013-10-18 20:38:07 +00:00
local Geom = require ( " ui/geometry " )
local Event = require ( " ui/event " )
2020-12-19 11:18:30 +00:00
local IconWidget = require ( " ui/widget/iconwidget " )
2019-08-05 16:38:10 +00:00
local InfoMessage = require ( " ui/widget/infomessage " )
2021-05-20 21:14:11 +00:00
local Notification = require ( " ui/widget/notification " )
2017-05-22 14:21:23 +00:00
local OverlapGroup = require ( " ui/widget/overlapgroup " )
local ReaderDogear = require ( " apps/reader/modules/readerdogear " )
local ReaderFlipping = require ( " apps/reader/modules/readerflipping " )
local ReaderFooter = require ( " apps/reader/modules/readerfooter " )
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
2021-03-30 00:57:59 +00:00
local TimeVal = require ( " ui/timeval " )
2017-05-22 14:21:23 +00:00
local UIManager = require ( " ui/uimanager " )
2016-04-19 06:50:36 +00:00
local dbg = require ( " dbg " )
2016-12-29 08:10:38 +00:00
local logger = require ( " logger " )
2021-05-20 21:14:11 +00:00
local optionsutil = require ( " ui/data/optionsutil " )
2014-10-15 12:31:24 +00:00
local _ = require ( " gettext " )
2017-05-22 14:21:23 +00:00
local Screen = Device.screen
local T = require ( " ffi/util " ) . template
2013-10-18 20:38:07 +00:00
2016-12-25 20:13:30 +00:00
local ReaderView = OverlapGroup : extend {
2014-03-13 13:52:43 +00:00
document = nil ,
-- single page state
state = {
page = nil ,
pos = 0 ,
zoom = 1.0 ,
rotation = 0 ,
gamma = 1.0 ,
offset = nil ,
bbox = nil ,
} ,
2021-03-06 21:44:18 +00:00
outer_page_color = Blitbuffer.gray ( DOUTER_PAGE_COLOR / 15 ) ,
2017-11-20 20:58:58 +00:00
-- highlight with "lighten" or "underscore" or "invert"
2014-03-13 13:52:43 +00:00
highlight = {
2021-04-05 08:02:41 +00:00
lighten_factor = G_reader_settings : readSetting ( " highlight_lighten_factor " , 0.2 ) ,
2014-03-13 13:52:43 +00:00
temp_drawer = " invert " ,
temp = { } ,
saved_drawer = " lighten " ,
saved = { } ,
} ,
highlight_visible = true ,
-- PDF/DjVu continuous paging
page_scroll = nil ,
2021-03-06 21:44:18 +00:00
page_bgcolor = Blitbuffer.gray ( DBACKGROUND_COLOR / 15 ) ,
2014-03-13 13:52:43 +00:00
page_states = { } ,
2016-11-05 15:12:19 +00:00
-- properties of the gap drawn between each page in scroll mode:
2014-03-13 13:52:43 +00:00
page_gap = {
2016-11-05 15:12:19 +00:00
-- color (0 = white, 8 = gray, 15 = black)
2021-03-06 21:44:18 +00:00
color = Blitbuffer.gray ( ( G_reader_settings : readSetting ( " page_gap_color " ) or 8 ) / 15 ) ,
2014-03-13 13:52:43 +00:00
} ,
-- DjVu page rendering mode (used in djvu.c:drawPage())
render_mode = DRENDER_MODE , -- default to COLOR
-- Crengine view mode
view_mode = DCREREADER_VIEW_MODE , -- default to page mode
hinting = true ,
-- visible area within current viewing page
Revamp flash_ui handling, once more, with feeling ;) (#7262)
* Simplify flash_ui handling (by handling the unhighlight pre-callback, c.f., #7262 for more details).
* UIManager: Handle translucent window-level widgets (and those wrapped in a translucent MovableContainer) properly in setDirty directly, making sure what's *underneath* them gets repainted to avoid alpha layering glitches. (This was previously handled via localized hacks).
* Update UIManager's documentation, and format it properly for ldoc parsing, making the HTML docs more useful.
* ReaderView: Reinitialize the various page areas when opening a new document, to prevent poisoning from the previous document.
* Event: Handle nils in an event's arguments.
* CheckButton/RadioButton: Switch to simple inversion to handle highlighting
* CheckButton: Make the highlight span the inner frame's width, instead of just the text's width, if possible.
* AlphaContainer: Fix & simplify, given the UIManager alpha handling.
* MovableContainer: When translucent, cache the canvas bb used for composition.
* Avoid spurious refreshes in a few widgets using various dummy *TextWidgets in order to first compute a text height.
* KeyValuePage: Avoid floats in size computations.
2021-02-20 17:22:48 +00:00
visible_area = nil ,
2014-03-13 13:52:43 +00:00
-- dimen for current viewing page
Revamp flash_ui handling, once more, with feeling ;) (#7262)
* Simplify flash_ui handling (by handling the unhighlight pre-callback, c.f., #7262 for more details).
* UIManager: Handle translucent window-level widgets (and those wrapped in a translucent MovableContainer) properly in setDirty directly, making sure what's *underneath* them gets repainted to avoid alpha layering glitches. (This was previously handled via localized hacks).
* Update UIManager's documentation, and format it properly for ldoc parsing, making the HTML docs more useful.
* ReaderView: Reinitialize the various page areas when opening a new document, to prevent poisoning from the previous document.
* Event: Handle nils in an event's arguments.
* CheckButton/RadioButton: Switch to simple inversion to handle highlighting
* CheckButton: Make the highlight span the inner frame's width, instead of just the text's width, if possible.
* AlphaContainer: Fix & simplify, given the UIManager alpha handling.
* MovableContainer: When translucent, cache the canvas bb used for composition.
* Avoid spurious refreshes in a few widgets using various dummy *TextWidgets in order to first compute a text height.
* KeyValuePage: Avoid floats in size computations.
2021-02-20 17:22:48 +00:00
page_area = nil ,
2014-03-13 13:52:43 +00:00
-- dimen for area to dim
2014-11-13 04:37:10 +00:00
dim_area = nil ,
2014-03-13 13:52:43 +00:00
-- has footer
footer_visible = nil ,
-- has dogear
dogear_visible = false ,
-- in flipping state
flipping_visible = false ,
2020-01-01 11:27:51 +00:00
-- to ensure periodic flush of settings
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
2021-03-30 00:57:59 +00:00
settings_last_save_tv = nil ,
2021-05-19 20:57:54 +00:00
-- might be directly updated by readerpaging/readerrolling when
-- they handle some panning/scrolling, to request "fast" refreshes
currently_scrolling = false ,
2012-05-18 22:50:26 +00:00
}
2013-02-24 11:49:23 +00:00
function ReaderView : init ( )
2016-12-25 20:13:30 +00:00
self.view_modules = { }
2014-04-30 15:19:24 +00:00
-- fix recalculate from close document pageno
self.state . page = nil
Revamp flash_ui handling, once more, with feeling ;) (#7262)
* Simplify flash_ui handling (by handling the unhighlight pre-callback, c.f., #7262 for more details).
* UIManager: Handle translucent window-level widgets (and those wrapped in a translucent MovableContainer) properly in setDirty directly, making sure what's *underneath* them gets repainted to avoid alpha layering glitches. (This was previously handled via localized hacks).
* Update UIManager's documentation, and format it properly for ldoc parsing, making the HTML docs more useful.
* ReaderView: Reinitialize the various page areas when opening a new document, to prevent poisoning from the previous document.
* Event: Handle nils in an event's arguments.
* CheckButton/RadioButton: Switch to simple inversion to handle highlighting
* CheckButton: Make the highlight span the inner frame's width, instead of just the text's width, if possible.
* AlphaContainer: Fix & simplify, given the UIManager alpha handling.
* MovableContainer: When translucent, cache the canvas bb used for composition.
* Avoid spurious refreshes in a few widgets using various dummy *TextWidgets in order to first compute a text height.
* KeyValuePage: Avoid floats in size computations.
2021-02-20 17:22:48 +00:00
-- Reset the various areas across documents
self.visible_area = Geom : new { x = 0 , y = 0 , w = 0 , h = 0 }
self.page_area = Geom : new { x = 0 , y = 0 , w = 0 , h = 0 }
self.dim_area = Geom : new { x = 0 , y = 0 , w = 0 , h = 0 }
2015-03-12 06:35:43 +00:00
self : addWidgets ( )
2016-02-17 06:36:40 +00:00
self.emitHintPageEvent = function ( )
self.ui : handleEvent ( Event : new ( " HintPage " , self.hinting ) )
end
2013-02-24 11:49:23 +00:00
end
2015-03-12 06:35:43 +00:00
function ReaderView : addWidgets ( )
2014-03-13 13:52:43 +00:00
self.dogear = ReaderDogear : new {
view = self ,
ui = self.ui ,
}
self.footer = ReaderFooter : new {
view = self ,
ui = self.ui ,
}
self.flipping = ReaderFlipping : new {
view = self ,
ui = self.ui ,
}
2020-12-19 11:18:30 +00:00
local arrow_size = Screen : scaleBySize ( 16 )
Page Overlap: Fix rectangle computation and arrow mode (#7269)
* In ReaderPaging, the panning step pre-PanningUpdate can be wildly overshot near page edges, so, use the corrected value instead by recomputing it after the panning has been effectively computed by ReaderView.
This fixes slight inaccuracies, as well as glaring mistakes when going backwards, or when near page edges.
This is in line with how ReaderRolling computes the value, which I only realized later because I'm an idiot.
* Minor cleanups around the handling of the dim_area Geom object in general.
* Fix the "Arrow" page overlap mode to be painted in the right coordinates when going backward. Issue might not have been terribly clear because of the previous issue ;).
* Center the arrow's point, while we're here.
* Don't use AlphaContainer to make it translucent, because AlphaContainer is horribly broken, and has weird quirks and behavior that make no sense to me unless some very specific and unlikely constraints are met, and they definitely aren't here.
This fixes the arrow copying an arrow-sized square of the original page the book was opened on on the top-left corner of *every* page with an arrow. (lol).
* Do real proper alpha-blending via Icon/ImageWidget from the original icon, instead of faking it via addBlitFrom, in order to avoid the dimming *around* the triangle's shape.
2021-02-10 19:06:41 +00:00
self.arrow = IconWidget : new {
icon = " control.expand.alpha " ,
width = arrow_size ,
height = arrow_size ,
alpha = true , -- Keep the alpha layer intact, the fill opacity is set at 75%
2014-11-17 13:44:13 +00:00
}
Page Overlap: Fix rectangle computation and arrow mode (#7269)
* In ReaderPaging, the panning step pre-PanningUpdate can be wildly overshot near page edges, so, use the corrected value instead by recomputing it after the panning has been effectively computed by ReaderView.
This fixes slight inaccuracies, as well as glaring mistakes when going backwards, or when near page edges.
This is in line with how ReaderRolling computes the value, which I only realized later because I'm an idiot.
* Minor cleanups around the handling of the dim_area Geom object in general.
* Fix the "Arrow" page overlap mode to be painted in the right coordinates when going backward. Issue might not have been terribly clear because of the previous issue ;).
* Center the arrow's point, while we're here.
* Don't use AlphaContainer to make it translucent, because AlphaContainer is horribly broken, and has weird quirks and behavior that make no sense to me unless some very specific and unlikely constraints are met, and they definitely aren't here.
This fixes the arrow copying an arrow-sized square of the original page the book was opened on on the top-left corner of *every* page with an arrow. (lol).
* Do real proper alpha-blending via Icon/ImageWidget from the original icon, instead of faking it via addBlitFrom, in order to avoid the dimming *around* the triangle's shape.
2021-02-10 19:06:41 +00:00
2014-03-13 13:52:43 +00:00
self [ 1 ] = self.dogear
self [ 2 ] = self.footer
self [ 3 ] = self.flipping
2013-02-23 18:25:57 +00:00
end
2016-12-25 20:13:30 +00:00
--[[--
Register a view UI widget module for document browsing .
@ tparam string name module name , registered widget can be accessed by readerui.view . view_modules [ name ] .
@ tparam ui.widget . widget.Widget widget paintable widget , i.e . has a paintTo method .
@ usage
local ImageWidget = require ( " ui/widget/imagewidget " )
local dummy_image = ImageWidget : new {
2020-12-19 11:18:30 +00:00
file = " resources/koreader.png " ,
2016-12-25 20:13:30 +00:00
}
-- the image will be painted on all book pages
readerui.view : registerViewModule ( ' dummy_image ' , dummy_image )
] ]
function ReaderView : registerViewModule ( name , widget )
if not widget.paintTo then
print ( name .. " view module does not have paintTo method! " )
return
end
widget.view = self
widget.ui = self.ui
self.view_modules [ name ] = widget
end
2015-03-12 06:35:43 +00:00
function ReaderView : resetLayout ( )
2016-12-25 20:13:30 +00:00
for _ , widget in ipairs ( self ) do
2016-03-08 06:42:46 +00:00
widget : resetLayout ( )
2015-03-12 06:35:43 +00:00
end
2016-12-25 20:13:30 +00:00
for _ , m in pairs ( self.view_modules ) do
if m.resetLayout then m : resetLayout ( ) end
end
2015-03-12 06:35:43 +00:00
end
2012-05-18 22:50:26 +00:00
function ReaderView : paintTo ( bb , x , y )
2016-08-12 09:47:35 +00:00
dbg : v ( " readerview painting " , self.visible_area , " to " , x , y )
2014-03-13 13:52:43 +00:00
if self.page_scroll then
self : drawPageBackground ( bb , x , y )
else
self : drawPageSurround ( bb , x , y )
end
-- draw page content
if self.ui . document.info . has_pages then
if self.page_scroll then
self : drawScrollPages ( bb , x , y )
else
self : drawSinglePage ( bb , x , y )
end
else
if self.view_mode == " page " then
self : drawPageView ( bb , x , y )
elseif self.view_mode == " scroll " then
self : drawScrollView ( bb , x , y )
end
end
-- dim last read area
2021-09-06 19:30:35 +00:00
if not self.dim_area : isEmpty ( ) and self : isOverlapAllowed ( ) then
2014-11-17 13:44:13 +00:00
if self.page_overlap_style == " dim " then
bb : dimRect (
self.dim_area . x , self.dim_area . y ,
self.dim_area . w , self.dim_area . h
)
elseif self.page_overlap_style == " arrow " then
Page Overlap: Fix rectangle computation and arrow mode (#7269)
* In ReaderPaging, the panning step pre-PanningUpdate can be wildly overshot near page edges, so, use the corrected value instead by recomputing it after the panning has been effectively computed by ReaderView.
This fixes slight inaccuracies, as well as glaring mistakes when going backwards, or when near page edges.
This is in line with how ReaderRolling computes the value, which I only realized later because I'm an idiot.
* Minor cleanups around the handling of the dim_area Geom object in general.
* Fix the "Arrow" page overlap mode to be painted in the right coordinates when going backward. Issue might not have been terribly clear because of the previous issue ;).
* Center the arrow's point, while we're here.
* Don't use AlphaContainer to make it translucent, because AlphaContainer is horribly broken, and has weird quirks and behavior that make no sense to me unless some very specific and unlikely constraints are met, and they definitely aren't here.
This fixes the arrow copying an arrow-sized square of the original page the book was opened on on the top-left corner of *every* page with an arrow. (lol).
* Do real proper alpha-blending via Icon/ImageWidget from the original icon, instead of faking it via addBlitFrom, in order to avoid the dimming *around* the triangle's shape.
2021-02-10 19:06:41 +00:00
local center_offset = bit.rshift ( self.arrow . height , 1 )
-- Paint at the proper y origin depending on wheter we paged forward (dim_area.y == 0) or backward
self.arrow : paintTo ( bb , 0 , self.dim_area . y == 0 and self.dim_area . h - center_offset or self.dim_area . y - center_offset )
2014-11-17 13:44:13 +00:00
end
2014-03-13 13:52:43 +00:00
end
-- draw saved highlight
if self.highlight_visible then
self : drawSavedHighlight ( bb , x , y )
end
-- draw temporary highlight
if self.highlight . temp then
self : drawTempHighlight ( bb , x , y )
end
-- paint dogear
if self.dogear_visible then
self.dogear : paintTo ( bb , x , y )
end
-- paint footer
if self.footer_visible then
self.footer : paintTo ( bb , x , y )
end
-- paint flipping
if self.flipping_visible then
self.flipping : paintTo ( bb , x , y )
end
2016-12-25 20:13:30 +00:00
for _ , m in pairs ( self.view_modules ) do
m : paintTo ( bb , x , y )
end
2014-03-13 13:52:43 +00:00
-- stop activity indicator
self.ui : handleEvent ( Event : new ( " StopActivityIndicator " ) )
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
-- Most pages should not require dithering
self.dialog . dithered = nil
-- For KOpt, let the user choose.
if self.ui . document.info . has_pages then
2019-02-08 17:31:40 +00:00
-- Also enforce dithering in PicDocument
if self.ui . document.is_pic or self.document . configurable.hw_dithering == 1 then
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
self.dialog . dithered = true
end
else
-- Whereas for CRe,
-- If we're attempting to show a large enough amount of image data, request dithering (without triggering another repaint ;)).
local img_count , img_coverage = self.ui . document : getDrawnImagesStatistics ( )
-- With some nil guards because this may not be implemented in every engine ;).
if img_count and img_count > 0 and img_coverage and img_coverage >= 0.075 then
self.dialog . dithered = true
2020-08-23 01:46:05 +00:00
-- Request a flashing update while we're at it, but only if it's the first time we're painting it
if self.state . drawn == false then
UIManager : setDirty ( nil , " full " )
end
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
end
2020-08-23 01:46:05 +00:00
self.state . drawn = true
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
end
2012-05-18 22:50:26 +00:00
end
2013-04-23 22:59:52 +00:00
--[[
Given coordinates on the screen return position in original page
] ] --
function ReaderView : screenToPageTransform ( pos )
2014-03-13 13:52:43 +00:00
if self.ui . document.info . has_pages then
if self.page_scroll then
return self : getScrollPagePosition ( pos )
else
return self : getSinglePagePosition ( pos )
end
else
pos.page = self.ui . document : getCurrentPage ( )
2016-02-15 09:33:48 +00:00
-- local last_y = self.ui.document:getCurrentPos()
2016-12-29 08:10:38 +00:00
logger.dbg ( " document has no pages at " , pos )
2014-03-13 13:52:43 +00:00
return pos
end
2013-04-23 22:59:52 +00:00
end
--[[
Given rectangle in original page return rectangle on the screen
] ] --
function ReaderView : pageToScreenTransform ( page , rect )
2014-03-13 13:52:43 +00:00
if self.ui . document.info . has_pages then
if self.page_scroll then
return self : getScrollPageRect ( page , rect )
else
return self : getSinglePageRect ( rect )
end
else
return rect
end
2013-04-23 22:59:52 +00:00
end
2014-07-02 08:38:09 +00:00
--[[
Get page area on screen for a given page number
--]]
function ReaderView : getScreenPageArea ( page )
if self.ui . document.info . has_pages then
local area = Geom : new { x = 0 , y = 0 }
if self.page_scroll then
for _ , state in ipairs ( self.page_states ) do
if page ~= state.page then
area.y = area.y + state.visible_area . h + state.offset . y
area.y = area.y + self.page_gap . height
else
area.x = state.offset . x
area.w = state.visible_area . w
area.h = state.visible_area . h
return area
end
end
else
area.x = self.state . offset.x
area.y = self.state . offset.y
area.w = self.visible_area . w
area.h = self.visible_area . h
return area
end
else
2014-11-25 03:02:33 +00:00
return self.dimen
2014-07-02 08:38:09 +00:00
end
end
2013-03-10 06:23:26 +00:00
function ReaderView : drawPageBackground ( bb , x , y )
2014-03-13 13:52:43 +00:00
bb : paintRect ( x , y , self.dimen . w , self.dimen . h , self.page_bgcolor )
2013-03-10 06:23:26 +00:00
end
function ReaderView : drawPageSurround ( bb , x , y )
2014-03-13 13:52:43 +00:00
if self.dimen . h > self.visible_area . h then
bb : paintRect ( x , y , self.dimen . w , self.state . offset.y , self.outer_page_color )
2019-11-21 09:05:40 +00:00
local bottom_margin = y + self.visible_area . h + self.state . offset.y
bb : paintRect ( x , bottom_margin , self.dimen . w , self.state . offset.y +
self.ui . view.footer : getHeight ( ) , self.outer_page_color )
2014-03-13 13:52:43 +00:00
end
if self.dimen . w > self.visible_area . w then
bb : paintRect ( x , y , self.state . offset.x , self.dimen . h , self.outer_page_color )
bb : paintRect ( x + self.dimen . w - self.state . offset.x - 1 , y ,
self.state . offset.x + 1 , self.dimen . h , self.outer_page_color )
end
2013-03-10 06:23:26 +00:00
end
function ReaderView : drawScrollPages ( bb , x , y )
2014-03-13 13:52:43 +00:00
local pos = Geom : new { x = x , y = y }
for page , state in ipairs ( self.page_states ) do
self.ui . document : drawPage (
bb ,
pos.x + state.offset . x ,
pos.y + state.offset . y ,
state.visible_area ,
state.page ,
state.zoom ,
state.rotation ,
state.gamma ,
self.render_mode )
pos.y = pos.y + state.visible_area . h
-- draw page gap if not the last part
if page ~= # self.page_states then
self : drawPageGap ( bb , pos.x , pos.y )
pos.y = pos.y + self.page_gap . height
end
end
2016-02-17 06:36:40 +00:00
UIManager : nextTick ( self.emitHintPageEvent )
2013-03-10 06:23:26 +00:00
end
2013-06-15 15:13:19 +00:00
function ReaderView : getCurrentPageList ( )
2014-03-13 13:52:43 +00:00
local pages = { }
if self.ui . document.info . has_pages then
if self.page_scroll then
for _ , state in ipairs ( self.page_states ) do
table.insert ( pages , state.page )
end
else
table.insert ( pages , self.state . page )
end
end
return pages
2013-06-15 15:13:19 +00:00
end
2013-04-23 22:59:52 +00:00
function ReaderView : getScrollPagePosition ( pos )
2016-02-15 09:33:48 +00:00
local x_p , y_p
2014-03-13 13:52:43 +00:00
local x_s , y_s = pos.x , pos.y
for _ , state in ipairs ( self.page_states ) do
if y_s < state.visible_area . h + state.offset . y then
y_p = ( state.visible_area . y + y_s - state.offset . y ) / state.zoom
x_p = ( state.visible_area . x + x_s - state.offset . x ) / state.zoom
return {
x = x_p ,
y = y_p ,
page = state.page ,
zoom = state.zoom ,
rotation = state.rotation ,
}
else
y_s = y_s - state.visible_area . h - self.page_gap . height
end
end
2013-04-23 22:59:52 +00:00
end
function ReaderView : getScrollPageRect ( page , rect_p )
2014-03-13 13:52:43 +00:00
local rect_s = Geom : new { }
for _ , state in ipairs ( self.page_states ) do
local trans_p = Geom : new ( rect_p ) : copy ( )
trans_p : transformByScale ( state.zoom , state.zoom )
2014-10-21 09:24:19 +00:00
if page == state.page and state.visible_area : intersectWith ( trans_p ) then
2014-03-13 13:52:43 +00:00
rect_s.x = rect_s.x + state.offset . x + trans_p.x - state.visible_area . x
rect_s.y = rect_s.y + state.offset . y + trans_p.y - state.visible_area . y
rect_s.w = trans_p.w
rect_s.h = trans_p.h
return rect_s
end
rect_s.y = rect_s.y + state.visible_area . h + self.page_gap . height
end
2013-04-23 22:59:52 +00:00
end
2013-03-10 06:23:26 +00:00
function ReaderView : drawPageGap ( bb , x , y )
2020-01-02 20:30:03 +00:00
bb : paintRect ( x , y , self.dimen . w , self.page_gap . height , self.page_gap . color )
2013-03-10 06:23:26 +00:00
end
function ReaderView : drawSinglePage ( bb , x , y )
2014-03-13 13:52:43 +00:00
self.ui . document : drawPage (
bb ,
x + self.state . offset.x ,
y + self.state . offset.y ,
self.visible_area ,
self.state . page ,
self.state . zoom ,
self.state . rotation ,
self.state . gamma ,
self.render_mode )
2016-02-17 06:36:40 +00:00
UIManager : nextTick ( self.emitHintPageEvent )
2013-03-10 06:23:26 +00:00
end
2013-04-23 22:59:52 +00:00
function ReaderView : getSinglePagePosition ( pos )
2014-03-13 13:52:43 +00:00
local x_s , y_s = pos.x , pos.y
return {
x = ( self.visible_area . x + x_s - self.state . offset.x ) / self.state . zoom ,
y = ( self.visible_area . y + y_s - self.state . offset.y ) / self.state . zoom ,
page = self.state . page ,
zoom = self.state . zoom ,
rotation = self.state . rotation ,
}
2013-04-23 22:59:52 +00:00
end
function ReaderView : getSinglePageRect ( rect_p )
2014-03-13 13:52:43 +00:00
local rect_s = Geom : new { }
local trans_p = Geom : new ( rect_p ) : copy ( )
trans_p : transformByScale ( self.state . zoom , self.state . zoom )
2014-10-21 09:24:19 +00:00
if self.visible_area : intersectWith ( trans_p ) then
2014-03-13 13:52:43 +00:00
rect_s.x = self.state . offset.x + trans_p.x - self.visible_area . x
rect_s.y = self.state . offset.y + trans_p.y - self.visible_area . y
rect_s.w = trans_p.w
rect_s.h = trans_p.h
return rect_s
end
2013-04-23 22:59:52 +00:00
end
2013-03-10 06:23:26 +00:00
function ReaderView : drawPageView ( bb , x , y )
2014-03-13 13:52:43 +00:00
self.ui . document : drawCurrentViewByPage (
bb ,
x + self.state . offset.x ,
y + self.state . offset.y ,
self.visible_area ,
self.state . page )
2013-03-10 06:23:26 +00:00
end
function ReaderView : drawScrollView ( bb , x , y )
2014-03-13 13:52:43 +00:00
self.ui . document : drawCurrentViewByPos (
bb ,
x + self.state . offset.x ,
y + self.state . offset.y ,
self.visible_area ,
self.state . pos )
2013-03-10 06:23:26 +00:00
end
2013-06-15 15:13:19 +00:00
function ReaderView : drawTempHighlight ( bb , x , y )
2014-03-13 13:52:43 +00:00
for page , boxes in pairs ( self.highlight . temp ) do
for i = 1 , # boxes do
local rect = self : pageToScreenTransform ( page , boxes [ i ] )
if rect then
self : drawHighlightRect ( bb , x , y , rect , self.highlight . temp_drawer )
end
end
end
2013-06-15 15:13:19 +00:00
end
function ReaderView : drawSavedHighlight ( bb , x , y )
2014-03-13 13:52:43 +00:00
if self.ui . document.info . has_pages then
self : drawPageSavedHighlight ( bb , x , y )
else
self : drawXPointerSavedHighlight ( bb , x , y )
end
2014-01-17 19:05:17 +00:00
end
function ReaderView : drawPageSavedHighlight ( bb , x , y )
2014-03-13 13:52:43 +00:00
local pages = self : getCurrentPageList ( )
for _ , page in pairs ( pages ) do
local items = self.highlight . saved [ page ]
2020-11-08 01:18:50 +00:00
if items then
for i = 1 , # items do
local item = items [ i ]
local pos0 , pos1 = item.pos0 , item.pos1
local boxes = self.ui . document : getPageBoxesFromPositions ( page , pos0 , pos1 )
if boxes then
for _ , box in pairs ( boxes ) do
local rect = self : pageToScreenTransform ( page , box )
if rect then
self : drawHighlightRect ( bb , x , y , rect , item.drawer or self.highlight . saved_drawer )
end
end -- end for each box
end -- end if boxes
end -- end for each highlight
end
2014-03-13 13:52:43 +00:00
end -- end for each page
2013-06-15 15:13:19 +00:00
end
2014-01-17 19:05:17 +00:00
function ReaderView : drawXPointerSavedHighlight ( bb , x , y )
2018-10-08 16:57:59 +00:00
-- Getting screen boxes is done for each tap on screen (changing pages,
-- showing menu...). We might want to cache these boxes per page (and
-- clear that cache when page layout change or highlights are added
-- or removed).
2019-03-13 12:05:50 +00:00
local cur_view_top , cur_view_bottom
2020-11-08 01:18:50 +00:00
for page , items in pairs ( self.highlight . saved ) do
if items then
for j = 1 , # items do
local item = items [ j ]
local pos0 , pos1 = item.pos0 , item.pos1
-- document:getScreenBoxesFromPositions() is expensive, so we
-- first check this item is on current page
if not cur_view_top then
-- Even in page mode, it's safer to use pos and ui.dimen.h
-- than pages' xpointers pos, even if ui.dimen.h is a bit
-- larger than pages' heights
cur_view_top = self.ui . document : getCurrentPos ( )
if self.view_mode == " page " and self.ui . document : getVisiblePageCount ( ) > 1 then
cur_view_bottom = cur_view_top + 2 * self.ui . dimen.h
else
cur_view_bottom = cur_view_top + self.ui . dimen.h
end
2019-02-26 06:16:43 +00:00
end
2020-11-08 01:18:50 +00:00
local spos0 = self.ui . document : getPosFromXPointer ( pos0 )
local spos1 = self.ui . document : getPosFromXPointer ( pos1 )
local start_pos = math.min ( spos0 , spos1 )
local end_pos = math.max ( spos0 , spos1 )
if start_pos <= cur_view_bottom and end_pos >= cur_view_top then
local boxes = self.ui . document : getScreenBoxesFromPositions ( pos0 , pos1 , true ) -- get_segments=true
if boxes then
for _ , box in pairs ( boxes ) do
local rect = self : pageToScreenTransform ( page , box )
if rect then
self : drawHighlightRect ( bb , x , y , rect , item.drawer or self.highlight . saved_drawer )
end
end -- end for each box
end -- end if boxes
end
end -- end for each highlight
end
2014-03-13 13:52:43 +00:00
end -- end for all saved highlight
2014-01-17 19:05:17 +00:00
end
2016-06-27 16:43:23 +00:00
function ReaderView : drawHighlightRect ( bb , _x , _y , rect , drawer )
2014-03-13 13:52:43 +00:00
local x , y , w , h = rect.x , rect.y , rect.w , rect.h
2014-04-02 20:59:17 +00:00
2014-03-13 13:52:43 +00:00
if drawer == " underscore " then
self.highlight . line_width = self.highlight . line_width or 2
2019-03-14 19:58:45 +00:00
self.highlight . line_color = self.highlight . line_color or Blitbuffer.COLOR_GRAY
2014-03-13 13:52:43 +00:00
bb : paintRect ( x , y + h - 1 , w ,
self.highlight . line_width ,
self.highlight . line_color )
elseif drawer == " lighten " then
2014-10-22 13:34:11 +00:00
bb : lightenRect ( x , y , w , h , self.highlight . lighten_factor )
2014-03-13 13:52:43 +00:00
elseif drawer == " invert " then
bb : invertRect ( x , y , w , h )
end
2013-04-23 22:59:52 +00:00
end
2013-03-10 06:23:26 +00:00
function ReaderView : getPageArea ( page , zoom , rotation )
2014-03-13 13:52:43 +00:00
if self.use_bbox then
return self.ui . document : getUsedBBoxDimensions ( page , zoom , rotation )
else
return self.ui . document : getPageDimensions ( page , zoom , rotation )
end
2013-03-10 06:23:26 +00:00
end
2012-12-08 06:05:10 +00:00
--[[
This method is supposed to be only used by ReaderPaging
--]]
2012-05-18 22:50:26 +00:00
function ReaderView : recalculate ( )
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
-- Start by resetting the dithering flag early, so it doesn't carry over from the previous page.
self.dialog . dithered = nil
2014-03-13 13:52:43 +00:00
if self.ui . document.info . has_pages and self.state . page then
self.page_area = self : getPageArea (
self.state . page ,
self.state . zoom ,
self.state . rotation )
-- reset our size
self.visible_area : setSizeTo ( self.dimen )
Another round of ReaderFooter fixes (#6830)
* When auto_refresh_time is enabled, don't actually refresh anything when the footer is hidden.
* Fix a bunch of state tracking related to height computations, meaning `getHeight()` is now actually accurate, always, and we don't need shitty workarounds anymore.
* `footer_container.dimen.h` *includes* the progress bar, so, never reset it to 0 unless the progress bar is disabled (some `settings.progress_bar_position` codepaths were mistakenly doing just that).
* More aggressively set/reset `footer_text.height` (not sure this one makes much of a difference, and/or if it's actually useful at all, but, the tracking was already there, but hella inconsistent, so, just fix it).
* Honor `settings.reclaim_height` in other bits of code that were only checking `footer_visible` to figure out the visible page area.
* Ask ReaderView to update the `visible_area` *now* when toggling the footer's visibility (for ReaderPaging).
2020-10-27 15:48:34 +00:00
if self.ui . view.footer_visible and not self.ui . view.footer . settings.reclaim_height then
2019-11-21 09:05:40 +00:00
self.visible_area . h = self.visible_area . h - self.ui . view.footer : getHeight ( )
end
2014-08-06 14:06:34 +00:00
if self.ui . document.configurable . writing_direction == 0 then
2020-11-28 16:18:57 +00:00
-- starts from left of page_area
2014-08-06 14:06:34 +00:00
self.visible_area . x = self.page_area . x
else
2020-11-28 16:18:57 +00:00
-- start from right of page_area
2014-08-06 14:06:34 +00:00
self.visible_area . x = self.page_area . x + self.page_area . w - self.visible_area . w
2020-11-28 16:18:57 +00:00
end
if self.ui . zooming.zoom_bottom_to_top then
-- starts from bottom of page_area
self.visible_area . y = self.page_area . y + self.page_area . h - self.visible_area . h
else
-- starts from top of page_area
2014-08-06 14:06:34 +00:00
self.visible_area . y = self.page_area . y
end
2020-02-20 22:00:32 +00:00
if not self.page_scroll then
-- and recalculate it according to page size
self.visible_area : offsetWithin ( self.page_area , 0 , 0 )
end
2014-03-13 13:52:43 +00:00
-- clear dim area
Page Overlap: Fix rectangle computation and arrow mode (#7269)
* In ReaderPaging, the panning step pre-PanningUpdate can be wildly overshot near page edges, so, use the corrected value instead by recomputing it after the panning has been effectively computed by ReaderView.
This fixes slight inaccuracies, as well as glaring mistakes when going backwards, or when near page edges.
This is in line with how ReaderRolling computes the value, which I only realized later because I'm an idiot.
* Minor cleanups around the handling of the dim_area Geom object in general.
* Fix the "Arrow" page overlap mode to be painted in the right coordinates when going backward. Issue might not have been terribly clear because of the previous issue ;).
* Center the arrow's point, while we're here.
* Don't use AlphaContainer to make it translucent, because AlphaContainer is horribly broken, and has weird quirks and behavior that make no sense to me unless some very specific and unlikely constraints are met, and they definitely aren't here.
This fixes the arrow copying an arrow-sized square of the original page the book was opened on on the top-left corner of *every* page with an arrow. (lol).
* Do real proper alpha-blending via Icon/ImageWidget from the original icon, instead of faking it via addBlitFrom, in order to avoid the dimming *around* the triangle's shape.
2021-02-10 19:06:41 +00:00
self.dim_area : clear ( )
2014-03-13 13:52:43 +00:00
self.ui : handleEvent (
Event : new ( " ViewRecalculate " , self.visible_area , self.page_area ) )
else
self.visible_area : setSizeTo ( self.dimen )
end
self.state . offset = Geom : new { x = 0 , y = 0 }
if self.dimen . h > self.visible_area . h then
Another round of ReaderFooter fixes (#6830)
* When auto_refresh_time is enabled, don't actually refresh anything when the footer is hidden.
* Fix a bunch of state tracking related to height computations, meaning `getHeight()` is now actually accurate, always, and we don't need shitty workarounds anymore.
* `footer_container.dimen.h` *includes* the progress bar, so, never reset it to 0 unless the progress bar is disabled (some `settings.progress_bar_position` codepaths were mistakenly doing just that).
* More aggressively set/reset `footer_text.height` (not sure this one makes much of a difference, and/or if it's actually useful at all, but, the tracking was already there, but hella inconsistent, so, just fix it).
* Honor `settings.reclaim_height` in other bits of code that were only checking `footer_visible` to figure out the visible page area.
* Ask ReaderView to update the `visible_area` *now* when toggling the footer's visibility (for ReaderPaging).
2020-10-27 15:48:34 +00:00
if self.ui . view.footer_visible and not self.ui . view.footer . settings.reclaim_height then
2019-11-21 09:05:40 +00:00
self.state . offset.y = ( self.dimen . h - ( self.visible_area . h + self.ui . view.footer : getHeight ( ) ) ) / 2
else
self.state . offset.y = ( self.dimen . h - self.visible_area . h ) / 2
end
2014-03-13 13:52:43 +00:00
end
if self.dimen . w > self.visible_area . w then
self.state . offset.x = ( self.dimen . w - self.visible_area . w ) / 2
end
Another round of ReaderFooter fixes (#6830)
* When auto_refresh_time is enabled, don't actually refresh anything when the footer is hidden.
* Fix a bunch of state tracking related to height computations, meaning `getHeight()` is now actually accurate, always, and we don't need shitty workarounds anymore.
* `footer_container.dimen.h` *includes* the progress bar, so, never reset it to 0 unless the progress bar is disabled (some `settings.progress_bar_position` codepaths were mistakenly doing just that).
* More aggressively set/reset `footer_text.height` (not sure this one makes much of a difference, and/or if it's actually useful at all, but, the tracking was already there, but hella inconsistent, so, just fix it).
* Honor `settings.reclaim_height` in other bits of code that were only checking `footer_visible` to figure out the visible page area.
* Ask ReaderView to update the `visible_area` *now* when toggling the footer's visibility (for ReaderPaging).
2020-10-27 15:48:34 +00:00
-- Flag a repaint so self:paintTo will be called
Enable HW dithering in a few key places (#4541)
* Enable HW dithering on supported devices (Clara HD, Forma; Oasis 2, PW4)
* FileManager and co. (where appropriate, i.e., when covers are shown)
* Book Status
* Reader, where appropriate:
* CRe: on pages whith image content (for over 7.5% of the screen area, should hopefully leave stuff like bullet points or small scene breaks alone).
* Other engines: on user-request (in the gear tab of the bottom menu), via the new "Dithering" knob (will only appear on supported devices).
* ScreenSaver
* ImageViewer
* Minimize repaints when flash_ui is enabled (by, almost everywhere, only repainting the flashing element, and not the toplevel window which hosts it).
(The first pass of this involved fixing a few Button instances whose show_parent was wrong, in particular, chevrons in the FM & TopMenu).
* Hunted down a few redundant repaints (unneeded setDirty("all") calls),
either by switching the widget to nil when only a refresh was needed, and not a repaint,
or by passing the appropritate widget to setDirty.
(Note to self: Enable *verbose* debugging to catch broken setDirty calls via its post guard).
There were also a few instances of 'em right behind a widget close.
* Don't repaint the underlying widget when initially showing TopMenu & ConfigDialog.
We unfortunately do need to do it when switching tabs, because of their variable heights.
* On Kobo, disabled the extra and completely useless full refresh before suspend/reboot/poweroff, as well as on resume. No more double refreshes!
* Fix another debug guard in Kobo sysfs_light
* Switch ImageWidget & ImageViewer mostly to "ui" updates, which will be better suited to image content pretty much everywhere, REAGL or not.
PS: (Almost :100: commits! :D)
2019-02-07 00:14:37 +00:00
-- NOTE: This is also unfortunately called during panning, essentially making sure we'll never be using "fast" for pans ;).
2021-05-19 20:57:54 +00:00
UIManager : setDirty ( self.dialog , self.currently_scrolling and " fast " or " partial " )
2012-05-18 22:50:26 +00:00
end
function ReaderView : PanningUpdate ( dx , dy )
2016-12-29 08:10:38 +00:00
logger.dbg ( " pan by " , dx , dy )
2014-03-13 13:52:43 +00:00
local old = self.visible_area : copy ( )
self.visible_area : offsetWithin ( self.page_area , dx , dy )
if self.visible_area ~= old then
-- flag a repaint
2019-02-11 02:28:46 +00:00
UIManager : setDirty ( self.dialog , " partial " )
2016-12-29 08:10:38 +00:00
logger.dbg ( " on pan: page_area " , self.page_area )
logger.dbg ( " on pan: visible_area " , self.visible_area )
2014-03-13 13:52:43 +00:00
self.ui : handleEvent (
Event : new ( " ViewRecalculate " , self.visible_area , self.page_area ) )
end
return true
2012-05-18 22:50:26 +00:00
end
2014-01-02 03:08:06 +00:00
function ReaderView : PanningStart ( x , y )
2016-12-29 08:10:38 +00:00
logger.dbg ( " panning start " , x , y )
2014-03-13 13:52:43 +00:00
if not self.panning_visible_area then
self.panning_visible_area = self.visible_area : copy ( )
end
self.visible_area = self.panning_visible_area : copy ( )
self.visible_area : offsetWithin ( self.page_area , x , y )
self.ui : handleEvent ( Event : new ( " ViewRecalculate " , self.visible_area , self.page_area ) )
2019-02-11 02:28:46 +00:00
UIManager : setDirty ( self.dialog , " partial " )
2014-01-02 03:08:06 +00:00
end
function ReaderView : PanningStop ( )
2014-03-13 13:52:43 +00:00
self.panning_visible_area = nil
2014-01-02 03:08:06 +00:00
end
function ReaderView : SetZoomCenter ( x , y )
2014-03-13 13:52:43 +00:00
local old = self.visible_area : copy ( )
self.visible_area : centerWithin ( self.page_area , x , y )
if self.visible_area ~= old then
self.ui : handleEvent ( Event : new ( " ViewRecalculate " , self.visible_area , self.page_area ) )
2014-11-30 00:12:00 +00:00
UIManager : setDirty ( self.dialog , " partial " )
2014-03-13 13:52:43 +00:00
end
2014-01-02 03:08:06 +00:00
end
2016-03-27 08:26:37 +00:00
function ReaderView : getViewContext ( )
if self.page_scroll then
return self.page_states
else
return {
{
page = self.state . page ,
pos = self.state . pos ,
zoom = self.state . zoom ,
rotation = self.state . rotation ,
gamma = self.state . gamma ,
offset = self.state . offset : copy ( ) ,
bbox = self.state . bbox ,
} ,
self.visible_area : copy ( ) ,
self.page_area : copy ( ) ,
}
end
end
function ReaderView : restoreViewContext ( ctx )
2020-11-03 21:51:11 +00:00
-- The format of the context is different depending on page_scroll.
-- If we're asked to restore the other format, just ignore it
-- (our only caller, ReaderPaging:onRestoreBookLocation(), will
-- at least change to the page of the context, which is all that
-- can be done when restoring from a different mode)
2016-03-27 08:26:37 +00:00
if self.page_scroll then
2020-11-03 21:51:11 +00:00
if ctx [ 1 ] and ctx [ 1 ] . visible_area then
self.page_states = ctx
return true
end
2016-03-27 08:26:37 +00:00
else
2020-11-03 21:51:11 +00:00
if ctx [ 1 ] and ctx [ 1 ] . pos then
self.state = ctx [ 1 ]
self.visible_area = ctx [ 2 ]
self.page_area = ctx [ 3 ]
return true
end
2016-03-27 08:26:37 +00:00
end
2020-11-03 21:51:11 +00:00
return false
2016-03-27 08:26:37 +00:00
end
2020-07-01 20:17:41 +00:00
function ReaderView : onSetRotationMode ( rotation )
if rotation ~= nil then
if rotation == Screen : getRotationMode ( ) then
return true
2014-03-13 13:52:43 +00:00
end
2020-07-01 20:17:41 +00:00
Screen : setRotationMode ( rotation )
2014-03-13 13:52:43 +00:00
end
2020-07-01 20:17:41 +00:00
UIManager : setDirty ( self.dialog , " full " )
local new_screen_size = Screen : getSize ( )
self.ui : handleEvent ( Event : new ( " SetDimensions " , new_screen_size ) )
self.ui : onScreenResize ( new_screen_size )
self.ui : handleEvent ( Event : new ( " InitScrollPageStates " ) )
2021-05-31 20:19:24 +00:00
Notification : notify ( T ( _ ( " Rotation mode set to: %1 " ) , optionsutil : getOptionText ( " SetRotationMode " , rotation ) ) )
2014-03-13 13:52:43 +00:00
return true
2013-02-02 08:46:06 +00:00
end
2012-06-12 16:14:23 +00:00
function ReaderView : onSetDimensions ( dimensions )
2014-03-13 13:52:43 +00:00
self : resetLayout ( )
self.dimen = dimensions
-- recalculate view
self : recalculate ( )
2013-02-23 18:25:57 +00:00
end
function ReaderView : onRestoreDimensions ( dimensions )
2014-03-13 13:52:43 +00:00
self : resetLayout ( )
self.dimen = dimensions
-- recalculate view
self : recalculate ( )
2012-06-12 16:14:23 +00:00
end
2013-02-23 18:25:57 +00:00
function ReaderView : onSetFullScreen ( full_screen )
2014-03-13 13:52:43 +00:00
self.footer_visible = not full_screen
self.ui : handleEvent ( Event : new ( " SetDimensions " , Screen : getSize ( ) ) )
2013-02-23 18:25:57 +00:00
end
2016-03-27 22:39:47 +00:00
function ReaderView : onSetScrollMode ( page_scroll )
2020-12-11 18:28:55 +00:00
if self.ui . document.info . has_pages and page_scroll
2021-04-04 17:48:27 +00:00
and self.ui . zooming.paged_modes [ self.zoom_mode ]
and self.ui . document.configurable . text_wrap == 0 then
2019-08-05 16:38:10 +00:00
UIManager : show ( InfoMessage : new {
2019-08-22 15:11:47 +00:00
text = _ ( [ [
2020-12-11 18:28:55 +00:00
Continuous view ( scroll mode ) works best with zoom to page width , zoom to content width or zoom to rows .
2019-08-05 16:38:10 +00:00
2020-12-11 18:28:55 +00:00
In combination with zoom to fit page , page height , content height , content or columns , continuous view can cause unexpected shifts when turning pages . ] ] ) ,
2019-08-05 16:38:10 +00:00
timeout = 5 ,
} )
end
2014-03-13 13:52:43 +00:00
self.page_scroll = page_scroll
2020-11-28 16:18:57 +00:00
if not page_scroll then
self.ui . document.configurable . page_scroll = 0
end
2014-03-13 13:52:43 +00:00
self : recalculate ( )
self.ui : handleEvent ( Event : new ( " InitScrollPageStates " ) )
2013-03-10 06:23:26 +00:00
end
2012-10-09 22:26:01 +00:00
function ReaderView : onReadSettings ( config )
2021-07-18 17:56:19 +00:00
self.document : setTileCacheValidity ( config : readSetting ( " tile_cache_validity_ts " ) )
2014-03-13 13:52:43 +00:00
self.render_mode = config : readSetting ( " render_mode " ) or 0
2020-07-09 17:11:44 +00:00
local rotation_mode = nil
local locked = G_reader_settings : isTrue ( " lock_rotation " )
-- Keep current rotation by doing nothing when sticky rota is enabled.
if not locked then
-- Honor docsettings's rotation
2021-03-06 21:44:18 +00:00
if config : has ( " rotation_mode " ) then
rotation_mode = config : readSetting ( " rotation_mode " ) -- Doc's
else
2020-07-09 17:11:44 +00:00
-- No doc specific rotation, pickup global defaults for the doc type
if self.ui . document.info . has_pages then
rotation_mode = G_reader_settings : readSetting ( " kopt_rotation_mode " ) or Screen.ORIENTATION_PORTRAIT
else
rotation_mode = G_reader_settings : readSetting ( " copt_rotation_mode " ) or Screen.ORIENTATION_PORTRAIT
end
2020-07-01 20:17:41 +00:00
end
2014-07-17 17:22:54 +00:00
end
2020-07-01 20:17:41 +00:00
if rotation_mode then
self : onSetRotationMode ( rotation_mode )
2014-03-13 13:52:43 +00:00
end
2020-01-07 19:16:59 +00:00
self.state . gamma = config : readSetting ( " gamma " ) or 1.0
2014-03-13 13:52:43 +00:00
local full_screen = config : readSetting ( " kopt_full_screen " ) or self.document . configurable.full_screen
2016-07-24 00:57:29 +00:00
if full_screen == 0 then
2016-04-28 07:02:15 +00:00
self.footer_visible = false
end
2014-03-13 13:52:43 +00:00
self : resetLayout ( )
local page_scroll = config : readSetting ( " kopt_page_scroll " ) or self.document . configurable.page_scroll
self.page_scroll = page_scroll == 1 and true or false
self.highlight . saved = config : readSetting ( " highlight " ) or { }
2021-09-06 19:30:35 +00:00
self.page_overlap_enable = config : isTrue ( " show_overlap_enable " ) or G_reader_settings : isTrue ( " page_overlap_enable " ) or DSHOWOVERLAP
2017-05-22 14:21:23 +00:00
self.page_overlap_style = config : readSetting ( " page_overlap_style " ) or G_reader_settings : readSetting ( " page_overlap_style " ) or " dim "
2021-03-06 21:44:18 +00:00
self.page_gap . height = Screen : scaleBySize ( config : readSetting ( " kopt_page_gap_height " )
or G_reader_settings : readSetting ( " kopt_page_gap_height " )
or 8 )
2012-10-09 22:26:01 +00:00
end
2012-05-18 22:50:26 +00:00
function ReaderView : onPageUpdate ( new_page_no )
2014-03-13 13:52:43 +00:00
self.state . page = new_page_no
2020-08-23 01:46:05 +00:00
self.state . drawn = false
2014-03-13 13:52:43 +00:00
self : recalculate ( )
self.highlight . temp = { }
2020-01-01 11:27:51 +00:00
self : checkAutoSaveSettings ( )
2012-05-18 22:50:26 +00:00
end
2012-06-05 07:23:36 +00:00
function ReaderView : onPosUpdate ( new_pos )
2014-03-13 13:52:43 +00:00
self.state . pos = new_pos
self : recalculate ( )
self.highlight . temp = { }
2020-01-01 11:27:51 +00:00
self : checkAutoSaveSettings ( )
2012-06-05 07:23:36 +00:00
end
2012-11-26 07:30:24 +00:00
function ReaderView : onZoomUpdate ( zoom )
2014-03-13 13:52:43 +00:00
self.state . zoom = zoom
self : recalculate ( )
self.highlight . temp = { }
2012-05-18 22:50:26 +00:00
end
2012-12-02 09:09:32 +00:00
function ReaderView : onBBoxUpdate ( bbox )
2014-03-13 13:52:43 +00:00
self.use_bbox = bbox and true or false
2012-12-02 09:09:32 +00:00
end
2012-05-18 22:50:26 +00:00
function ReaderView : onRotationUpdate ( rotation )
2014-03-13 13:52:43 +00:00
self.state . rotation = rotation
self : recalculate ( )
2012-05-18 22:50:26 +00:00
end
Another round of ReaderFooter fixes (#6830)
* When auto_refresh_time is enabled, don't actually refresh anything when the footer is hidden.
* Fix a bunch of state tracking related to height computations, meaning `getHeight()` is now actually accurate, always, and we don't need shitty workarounds anymore.
* `footer_container.dimen.h` *includes* the progress bar, so, never reset it to 0 unless the progress bar is disabled (some `settings.progress_bar_position` codepaths were mistakenly doing just that).
* More aggressively set/reset `footer_text.height` (not sure this one makes much of a difference, and/or if it's actually useful at all, but, the tracking was already there, but hella inconsistent, so, just fix it).
* Honor `settings.reclaim_height` in other bits of code that were only checking `footer_visible` to figure out the visible page area.
* Ask ReaderView to update the `visible_area` *now* when toggling the footer's visibility (for ReaderPaging).
2020-10-27 15:48:34 +00:00
function ReaderView : onReaderFooterVisibilityChange ( )
-- Don't bother ReaderRolling with this nonsense, the footer's height is NOT handled via visible_area there ;)
if self.ui . document.info . has_pages and self.state . page then
-- NOTE: Simply relying on recalculate would be a wee bit too much: it'd reset the in-page offsets,
-- which would be wrong, and is also not necessary, since the footer is at the bottom of the screen ;).
-- So, simply mangle visible_area's height ourselves...
if not self.ui . view.footer . settings.reclaim_height then
-- NOTE: Yes, this means that toggling reclaim_height requires a page switch (for a proper recalculate).
-- Thankfully, most of the time, the quirks are barely noticeable ;).
if self.ui . view.footer_visible then
self.visible_area . h = self.visible_area . h - self.ui . view.footer : getHeight ( )
else
self.visible_area . h = self.visible_area . h + self.ui . view.footer : getHeight ( )
end
end
self.ui : handleEvent ( Event : new ( " ViewRecalculate " , self.visible_area , self.page_area ) )
end
end
2013-02-20 06:32:51 +00:00
function ReaderView : onGammaUpdate ( gamma )
2014-03-13 13:52:43 +00:00
self.state . gamma = gamma
if self.page_scroll then
self.ui : handleEvent ( Event : new ( " UpdateScrollPageGamma " , gamma ) )
end
2021-05-31 20:19:24 +00:00
Notification : notify ( T ( _ ( " Font gamma set to: %1. " ) , gamma ) )
2013-01-05 14:28:14 +00:00
end
2019-08-30 11:47:51 +00:00
function ReaderView : onFontSizeUpdate ( font_size )
self.ui : handleEvent ( Event : new ( " ReZoom " , font_size ) )
2021-05-31 20:19:24 +00:00
Notification : notify ( T ( _ ( " Font zoom set to: %1. " ) , font_size ) )
2013-04-20 08:17:38 +00:00
end
2013-04-14 07:16:42 +00:00
function ReaderView : onDefectSizeUpdate ( )
2014-03-13 13:52:43 +00:00
self.ui : handleEvent ( Event : new ( " ReZoom " ) )
2013-04-14 07:16:42 +00:00
end
function ReaderView : onPageCrop ( )
2014-03-13 13:52:43 +00:00
self.ui : handleEvent ( Event : new ( " ReZoom " ) )
2013-04-14 07:16:42 +00:00
end
function ReaderView : onMarginUpdate ( )
2014-03-13 13:52:43 +00:00
self.ui : handleEvent ( Event : new ( " ReZoom " ) )
2013-04-14 07:16:42 +00:00
end
2013-01-07 12:05:48 +00:00
function ReaderView : onSetViewMode ( new_mode )
2017-10-02 22:31:14 +00:00
if new_mode ~= self.view_mode then
self.view_mode = new_mode
self.ui . document : setViewMode ( new_mode )
self.ui : handleEvent ( Event : new ( " ChangeViewMode " ) )
2021-05-31 20:19:24 +00:00
Notification : notify ( T ( _ ( " View mode set to: %1 " ) , optionsutil : getOptionText ( " SetViewMode " , new_mode ) ) )
2017-10-02 22:31:14 +00:00
end
2013-01-05 14:28:14 +00:00
end
2020-01-02 20:30:03 +00:00
--Refresh after changing a variable done by koptoptions.lua since all of them
--requires full screen refresh. If this handler used for changing page gap from
--another source (eg. coptions.lua) triggering a redraw is needed.
function ReaderView : onPageGapUpdate ( page_gap )
self.page_gap . height = page_gap
2021-05-20 21:14:11 +00:00
Notification : notify ( T ( _ ( " Page gap set to %1. " ) , page_gap ) )
2020-01-02 20:30:03 +00:00
return true
end
2013-12-27 15:18:16 +00:00
function ReaderView : onSaveSettings ( )
2021-07-21 20:28:34 +00:00
if self.document : isEdited ( ) and G_reader_settings : readSetting ( " save_document " ) ~= " always " then
-- Either "disable" (and the current tiles will be wrong) or "prompt" (but the
-- prompt will happen later, too late to catch "Don't save"), so force cached
-- tiles to be ignored on next opening.
self.document : resetTileCacheValidity ( )
end
2021-07-18 17:56:19 +00:00
self.ui . doc_settings : saveSetting ( " tile_cache_validity_ts " , self.document : getTileCacheValidity ( ) )
2014-03-13 13:52:43 +00:00
self.ui . doc_settings : saveSetting ( " render_mode " , self.render_mode )
2020-07-24 09:26:49 +00:00
-- Don't etch the current rotation in stone when sticky rotation is enabled
local locked = G_reader_settings : isTrue ( " lock_rotation " )
if not locked then
self.ui . doc_settings : saveSetting ( " rotation_mode " , Screen : getRotationMode ( ) )
end
2014-03-13 13:52:43 +00:00
self.ui . doc_settings : saveSetting ( " gamma " , self.state . gamma )
2014-04-02 20:59:17 +00:00
self.ui . doc_settings : saveSetting ( " highlight " , self.highlight . saved )
2021-09-06 19:30:35 +00:00
self.ui . doc_settings : saveSetting ( " show_overlap_enable " , self.page_overlap_enable )
2014-11-17 13:44:13 +00:00
self.ui . doc_settings : saveSetting ( " page_overlap_style " , self.page_overlap_style )
2012-10-09 22:26:01 +00:00
end
2013-10-18 20:38:07 +00:00
2014-10-15 12:31:24 +00:00
function ReaderView : getRenderModeMenuTable ( )
local view = self
local function make_mode ( text , mode )
return {
text = text ,
checked_func = function ( ) return view.render_mode == mode end ,
callback = function ( ) view.render_mode = mode end ,
}
end
return {
2019-08-24 07:25:38 +00:00
-- @translators Selects which layers of the DjVu image should be rendered. Valid rendering modes are color, black, mask, foreground, and background. See http://djvu.sourceforge.net/ and https://en.wikipedia.org/wiki/DjVu for more information about the format.
2014-10-15 12:31:24 +00:00
text = _ ( " DjVu render mode " ) ,
sub_item_table = {
make_mode ( _ ( " COLOUR (works for both colour and b&w pages) " ) , 0 ) ,
make_mode ( _ ( " BLACK & WHITE (for b&w pages only, much faster) " ) , 1 ) ,
make_mode ( _ ( " COLOUR ONLY (slightly faster than COLOUR) " ) , 2 ) ,
make_mode ( _ ( " MASK ONLY (for b&w pages only) " ) , 3 ) ,
make_mode ( _ ( " COLOUR BACKGROUND (show only background) " ) , 4 ) ,
make_mode ( _ ( " COLOUR FOREGROUND (show only foreground) " ) , 5 ) ,
}
}
end
2016-02-17 06:36:40 +00:00
function ReaderView : onCloseDocument ( )
self.hinting = false
-- stop any in fly HintPage event
UIManager : unschedule ( self.emitHintPageEvent )
end
2016-07-13 06:53:23 +00:00
function ReaderView : onReaderReady ( )
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
2021-03-30 00:57:59 +00:00
self.settings_last_save_tv = UIManager : getTime ( )
2020-01-01 11:27:51 +00:00
end
function ReaderView : onResume ( )
-- As settings were saved on suspend, reset this on resume,
-- as there's no need for a possibly immediate save.
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
2021-03-30 00:57:59 +00:00
self.settings_last_save_tv = UIManager : getTime ( )
2020-01-01 11:27:51 +00:00
end
function ReaderView : checkAutoSaveSettings ( )
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
2021-03-30 00:57:59 +00:00
if not self.settings_last_save_tv then -- reader not yet ready
2020-01-01 11:27:51 +00:00
return
end
2021-03-06 21:44:18 +00:00
if G_reader_settings : nilOrFalse ( " auto_save_settings_interval_minutes " ) then
-- no auto save
2020-01-01 11:27:51 +00:00
return
end
2020-11-28 21:59:27 +00:00
2021-03-06 21:44:18 +00:00
local interval = G_reader_settings : readSetting ( " auto_save_settings_interval_minutes " )
2021-04-14 23:00:28 +00:00
interval = TimeVal : new { sec = interval * 60 , usec = 0 }
The great Input/GestureDetector/TimeVal spring cleanup (a.k.a., a saner main loop) (#7415)
* ReaderDictionary: Port delay computations to TimeVal
* ReaderHighlight: Port delay computations to TimeVal
* ReaderView: Port delay computations to TimeVal
* Android: Reset gesture detection state on APP_CMD_TERM_WINDOW.
This prevents potentially being stuck in bogus gesture states when switching apps.
* GestureDetector:
* Port delay computations to TimeVal
* Fixed delay computations to handle time warps (large and negative deltas).
* Simplified timed callback handling to invalidate timers much earlier, preventing accumulating useless timers that no longer have any chance of ever detecting a gesture.
* Fixed state clearing to handle the actual effective slots, instead of hard-coding slot 0 & slot 1.
* Simplified timed callback handling in general, and added support for a timerfd backend for better performance and accuracy.
* The improved timed callback handling allows us to detect and honor (as much as possible) the three possible clock sources usable by Linux evdev events.
The only case where synthetic timestamps are used (and that only to handle timed callbacks) is limited to non-timerfd platforms where input events use
a clock source that is *NOT* MONOTONIC.
AFAICT, that's pretty much... PocketBook, and that's it?
* Input:
* Use the <linux/input.h> FFI module instead of re-declaring every constant
* Fixed (verbose) debug logging of input events to actually translate said constants properly.
* Completely reset gesture detection state on suspend. This should prevent bogus gesture detection on resume.
* Refactored the waitEvent loop to make it easier to comprehend (hopefully) and much more efficient.
Of specific note, it no longer does a crazy select spam every 100µs, instead computing and relying on sane timeouts,
as afforded by switching the UI event/input loop to the MONOTONIC time base, and the refactored timed callbacks in GestureDetector.
* reMarkable: Stopped enforcing synthetic timestamps on input events, as it should no longer be necessary.
* TimeVal:
* Refactored and simplified, especially as far as metamethods are concerned (based on <bsd/sys/time.h>).
* Added a host of new methods to query the various POSIX clock sources, and made :now default to MONOTONIC.
* Removed the debug guard in __sub, as time going backwards can be a perfectly normal occurrence.
* New methods:
* Clock sources: :realtime, :monotonic, :monotonic_coarse, :realtime_coarse, :boottime
* Utility: :tonumber, :tousecs, :tomsecs, :fromnumber, :isPositive, :isZero
* UIManager:
* Ported event loop & scheduling to TimeVal, and switched to the MONOTONIC time base.
This ensures reliable and consistent scheduling, as time is ensured never to go backwards.
* Added a :getTime() method, that returns a cached TimeVal:now(), updated at the top of every UI frame.
It's used throughout the codebase to cadge a syscall in circumstances where we are guaranteed that a syscall would return a mostly identical value,
because very few time has passed.
The only code left that does live syscalls does it because it's actually necessary for accuracy,
and the only code left that does that in a REALTIME time base is code that *actually* deals with calendar time (e.g., Statistics).
* DictQuickLookup: Port delay computations to TimeVal
* FootNoteWidget: Port delay computations to TimeVal
* HTMLBoxWidget: Port delay computations to TimeVal
* Notification: Port delay computations to TimeVal
* TextBoxWidget: Port delay computations to TimeVal
* AutoSuspend: Port to TimeVal
* AutoTurn:
* Fix it so that settings are actually honored.
* Port to TimeVal
* BackgroundRunner: Port to TimeVal
* Calibre: Port benchmarking code to TimeVal
* BookInfoManager: Removed unnecessary yield in the metadata extraction subprocess now that subprocesses get scheduled properly.
* All in all, these changes reduced the CPU cost of a single tap by a factor of ten (!), and got rid of an insane amount of weird poll/wakeup cycles that must have been hell on CPU schedulers and batteries..
2021-03-30 00:57:59 +00:00
local now_tv = UIManager : getTime ( )
if now_tv - self.settings_last_save_tv >= interval then
self.settings_last_save_tv = now_tv
2020-11-28 21:59:27 +00:00
-- I/O, delay until after the pageturn
UIManager : tickAfterNext ( function ( )
2020-01-01 11:27:51 +00:00
self.ui : saveSettings ( )
end )
2016-07-13 06:53:23 +00:00
end
end
2021-09-06 19:30:35 +00:00
function ReaderView : isOverlapAllowed ( )
if self.ui . document.info . has_pages then
return not self.page_scroll
and ( self.ui . paging.zoom_mode ~= " page "
or ( self.ui . paging.zoom_mode == " page " and self.ui . paging.is_reflowed ) )
and not self.ui . paging.zoom_mode : find ( " height " )
else
return self.view_mode ~= " page "
end
end
2013-10-18 20:38:07 +00:00
return ReaderView