2016-12-25 20:13:30 +00:00
--[[--
ReaderView module handles all the screen painting for document browsing .
] ]
2021-11-21 17:33:51 +00:00
local BD = require ( " ui/bidi " )
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 " )
2022-08-03 13:51:57 +00:00
local Font = require ( " ui/font " )
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 " )
2022-08-03 13:51:57 +00:00
local TextWidget = require ( " ui/widget/textwidget " )
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 " )
2022-03-12 11:16:50 +00:00
local Size = require ( " ui/size " )
2022-05-05 19:00:22 +00:00
local time = require ( " ui/time " )
2023-09-01 05:07:29 +00:00
local util = require ( " util " )
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 ,
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
view_modules = nil , -- array
2014-03-13 13:52:43 +00:00
-- single page state
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
state = nil , -- table
2022-10-10 20:21:27 +00:00
outer_page_color = Blitbuffer.gray ( G_defaults : readSetting ( " DOUTER_PAGE_COLOR " ) * ( 1 / 15 ) ) ,
2022-01-25 20:39:03 +00:00
-- highlight with "lighten" or "underscore" or "strikeout" or "invert"
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
highlight = nil , -- table
2014-03-13 13:52:43 +00:00
highlight_visible = true ,
2022-08-03 13:51:57 +00:00
note_mark_line_w = 3 , -- side line thickness
note_mark_sign = nil ,
note_mark_pos_x1 = nil , -- page 1
note_mark_pos_x2 = nil , -- page 2 in two-page mode
2014-03-13 13:52:43 +00:00
-- PDF/DjVu continuous paging
page_scroll = nil ,
2022-10-10 20:21:27 +00:00
page_bgcolor = Blitbuffer.gray ( G_defaults : readSetting ( " DBACKGROUND_COLOR " ) * ( 1 / 15 ) ) ,
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
page_states = nil , -- table
2016-11-05 15:12:19 +00:00
-- properties of the gap drawn between each page in scroll mode:
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
page_gap = nil , -- table
2014-03-13 13:52:43 +00:00
-- DjVu page rendering mode (used in djvu.c:drawPage())
2023-09-13 04:49:57 +00:00
render_mode = nil , -- default to COLOR, will be set in onReadSettings()
2014-03-13 13:52:43 +00:00
-- Crengine view mode
2022-09-27 23:10:50 +00:00
view_mode = G_defaults : readSetting ( " DCREREADER_VIEW_MODE " ) , -- default to page mode
2014-03-13 13:52:43 +00:00
hinting = true ,
2023-08-13 05:01:39 +00:00
emitHintPageEvent = nil ,
2014-03-13 13:52:43 +00:00
-- 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
2022-05-05 19:00:22 +00:00
settings_last_save_time = 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 ,
2023-11-26 04:51:47 +00:00
-- image content stats of the current page, if supported by the Document engine
img_count = nil ,
img_coverage = nil ,
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 = { }
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
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
self.state = {
page = nil ,
pos = 0 ,
zoom = 1.0 ,
rotation = 0 ,
gamma = 1.0 ,
offset = nil ,
bbox = nil ,
}
self.highlight = {
lighten_factor = G_reader_settings : readSetting ( " highlight_lighten_factor " , 0.2 ) ,
note_mark = G_reader_settings : readSetting ( " highlight_note_marker " ) ,
temp_drawer = " invert " ,
temp = { } ,
saved_drawer = " lighten " ,
indicator = nil , -- geom: non-touch highlight position indicator: {x = 50, y=50}
}
self.page_states = { }
self.page_gap = {
-- color (0 = white, 8 = gray, 15 = black)
2022-10-10 20:21:27 +00:00
color = Blitbuffer.gray ( ( G_reader_settings : readSetting ( " page_gap_color " ) or 8 ) * ( 1 / 15 ) ) ,
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
}
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
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 }
2023-11-26 04:51:47 +00:00
-- Zero-init for sanity
self.img_count = 0
self.img_coverage = 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
Clarify our OOP semantics across the codebase (#9586)
Basically:
* Use `extend` for class definitions
* Use `new` for object instantiations
That includes some minor code cleanups along the way:
* Updated `Widget`'s docs to make the semantics clearer.
* Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283)
* Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass).
* Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events.
* Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier.
* Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references.
* ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak).
* Terminal: Make sure the shell is killed on plugin teardown.
* InputText: Fix Home/End/Del physical keys to behave sensibly.
* InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...).
* OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of.
* ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed!
* Kobo: Minor code cleanups.
2022-10-06 00:14:48 +00:00
-- We've subclassed OverlapGroup, go through its init, because it does some funky stuff with self.dimen...
OverlapGroup.init ( self )
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
2022-02-06 17:01:45 +00:00
if self.ui . paging then
2014-03-13 13:52:43 +00:00
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
ReaderRolling: quicker partial rerenderings with EPUBs
Only available with EPUBs containing 2 or more fragments,
and a file size large enough to ensure a cache file is used.
The idea is simply, on any rendering setting change, to
skip the rerendering of the full book and to defer any
rerendering to the moment we draw a DocFragment, and
render only it.
So, on a setting change, only the fragment containing the
current page will be rerendered, and the new fragments we
may cross while turning pages.
When having done so, KOReader is in a degraded state (the
full page count is incorrect, the ToC is invalid...).
So, a full rerendering is needed, and one will happen
in the background, and when the user is idle, we reload
seamlessly and quickly from the cache file it has made.
ReaderFlipping will show some icons in the top left
corner to let it know at which steps in this procress
we are.
2023-02-16 22:30:58 +00:00
local should_repaint = self.ui . rolling : handlePartialRerendering ( )
if should_repaint then
-- ReaderRolling may have repositionned on another page containing
-- the xpointer of the top of the original page: recalling this is
-- all there is to do.
self : paintTo ( bb , x , y )
return
end
2014-03-13 13:52:43 +00:00
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 )
2023-05-07 17:28:18 +00:00
elseif self.page_overlap_style == " line " then
bb : paintRect ( 0 , self.dim_area . y == 0 and self.dim_area . h or self.dim_area . y ,
2024-05-07 16:54:57 +00:00
self.dim_area . w , Size.line . medium , Blitbuffer.COLOR_DARK_GRAY )
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
2022-03-12 11:16:50 +00:00
-- draw highlight position indicator for non-touch
if self.highlight . indicator then
self : drawHighlightIndicator ( bb , x , y )
end
2014-03-13 13:52:43 +00:00
-- 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
2023-03-13 07:52:10 +00:00
-- paint top left corner indicator
self.flipping : paintTo ( bb , x , y )
-- paint view modules
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.
2022-02-06 17:01:45 +00:00
if self.ui . paging then
if self.document . hw_dithering 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 ;)).
2022-02-06 17:01:45 +00:00
local img_count , img_coverage = self.document : getDrawnImagesStatistics ( )
2023-11-26 04:51:47 +00:00
-- We also want to deal with paging *away* from image content, which would have adverse effect on ghosting.
local coverage_diff = math.abs ( img_coverage - self.img_coverage )
-- Which is why we remember the stats of the *previous* page.
self.img_count , self.img_coverage = img_count , img_coverage
if img_coverage >= 0.075 or coverage_diff >= 0.075 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
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
2023-02-02 20:09:29 +00:00
if self.state . drawn == false and G_reader_settings : nilOrTrue ( " refresh_on_pages_with_images " ) then
2020-08-23 01:46:05 +00:00
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 )
2022-02-06 17:01:45 +00:00
if self.ui . paging then
2014-03-13 13:52:43 +00:00
if self.page_scroll then
return self : getScrollPagePosition ( pos )
else
return self : getSinglePagePosition ( pos )
end
else
2022-02-06 17:01:45 +00:00
pos.page = self.document : getCurrentPage ( )
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 )
2022-02-06 17:01:45 +00:00
if self.ui . paging then
2014-03-13 13:52:43 +00:00
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 )
2022-02-06 17:01:45 +00:00
if self.ui . paging then
2014-07-02 08:38:09 +00:00
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 +
2022-02-06 17:01:45 +00:00
self.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
2022-02-06 17:01:45 +00:00
self.document : drawPage (
2014-03-13 13:52:43 +00:00
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 = { }
2022-02-06 17:01:45 +00:00
if self.ui . paging then
2014-03-13 13:52:43 +00:00
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 )
2024-01-19 18:11:15 +00:00
local rect_s = Geom : new ( )
2014-03-13 13:52:43 +00:00
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 )
2022-02-06 17:01:45 +00:00
self.document : drawPage (
2014-03-13 13:52:43 +00:00
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 )
2024-01-19 18:11:15 +00:00
local rect_s = Geom : new ( )
2014-03-13 13:52:43 +00:00
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 )
2022-02-06 17:01:45 +00:00
self.document : drawCurrentViewByPage (
2014-03-13 13:52:43 +00:00
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 )
2022-02-06 17:01:45 +00:00
self.document : drawCurrentViewByPos (
2014-03-13 13:52:43 +00:00
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
2022-03-12 11:16:50 +00:00
function ReaderView : drawHighlightIndicator ( bb , x , y )
local rect = self.highlight . indicator
-- paint big cross line +
bb : paintRect (
rect.x ,
rect.y + rect.h / 2 - Size.border . thick / 2 ,
rect.w ,
Size.border . thick
)
bb : paintRect (
rect.x + rect.w / 2 - Size.border . thick / 2 ,
rect.y ,
Size.border . thick ,
rect.h
)
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 )
2024-05-03 06:08:57 +00:00
if # self.ui . annotation.annotations == 0 then return end
2022-02-06 17:01:45 +00:00
if self.ui . paging then
2014-03-13 13:52:43 +00:00
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 ( )
2022-12-02 18:22:27 +00:00
for _ , page in ipairs ( pages ) do
2024-05-03 06:08:57 +00:00
local items = self.ui . highlight : getPageSavedHighlights ( page )
2022-12-02 18:22:27 +00:00
for _ , item in ipairs ( items ) do
local boxes = self.document : getPageBoxesFromPositions ( page , item.pos0 , item.pos1 )
if boxes then
2024-05-03 06:08:57 +00:00
local draw_note_mark = item.note and self.highlight . note_mark
2022-12-02 18:22:27 +00:00
for _ , box in ipairs ( boxes ) do
local rect = self : pageToScreenTransform ( page , box )
if rect then
2024-05-03 06:08:57 +00:00
self : drawHighlightRect ( bb , x , y , rect , item.drawer , draw_note_mark )
2022-12-02 18:22:27 +00:00
if draw_note_mark and self.highlight . note_mark == " sidemark " then
draw_note_mark = false -- side mark in the first line only
2020-11-08 01:18:50 +00:00
end
2022-12-02 18:22:27 +00:00
end
end
end
2020-11-08 01:18:50 +00:00
end
2022-12-02 18:22:27 +00:00
end
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).
2024-05-03 06:08:57 +00:00
-- 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
local cur_view_top = self.document : getCurrentPos ( )
local cur_view_bottom
if self.view_mode == " page " and self.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
for _ , item in ipairs ( self.ui . annotation.annotations ) do
if item.drawer then
-- document:getScreenBoxesFromPositions() is expensive, so we
-- first check if this item is on current page
local start_pos = self.document : getPosFromXPointer ( item.pos0 )
local end_pos = self.document : getPosFromXPointer ( item.pos1 )
if start_pos <= cur_view_bottom and end_pos >= cur_view_top then
local boxes = self.document : getScreenBoxesFromPositions ( item.pos0 , item.pos1 , true ) -- get_segments=true
if boxes then
local draw_note_mark = item.note and self.highlight . note_mark
for _ , box in ipairs ( boxes ) do
if box.h ~= 0 then
self : drawHighlightRect ( bb , x , y , box , item.drawer , draw_note_mark )
if draw_note_mark and self.highlight . note_mark == " sidemark " then
draw_note_mark = false -- side mark in the first line only
2020-11-08 01:18:50 +00:00
end
2024-05-03 06:08:57 +00:00
end
end
2020-11-08 01:18:50 +00:00
end
2024-05-03 06:08:57 +00:00
end
2020-11-08 01:18:50 +00:00
end
2024-05-03 06:08:57 +00:00
end
2014-01-17 19:05:17 +00:00
end
2022-08-03 13:51:57 +00:00
function ReaderView : drawHighlightRect ( bb , _x , _y , rect , drawer , draw_note_mark )
2014-03-13 13:52:43 +00:00
local x , y , w , h = rect.x , rect.y , rect.w , rect.h
2022-01-25 20:39:03 +00:00
if drawer == " lighten " then
2014-10-22 13:34:11 +00:00
bb : lightenRect ( x , y , w , h , self.highlight . lighten_factor )
2022-01-25 20:39:03 +00:00
elseif drawer == " underscore " then
2024-03-29 08:38:31 +00:00
bb : paintRect ( x , y + h - 1 , w , Size.line . thick , Blitbuffer.COLOR_GRAY_4 )
2022-01-25 20:39:03 +00:00
elseif drawer == " strikeout " then
local line_y = y + math.floor ( h / 2 ) + 1
if self.ui . paging then
line_y = line_y + 2
end
2023-05-07 17:28:18 +00:00
bb : paintRect ( x , line_y , w , Size.line . medium , Blitbuffer.COLOR_BLACK )
2014-03-13 13:52:43 +00:00
elseif drawer == " invert " then
bb : invertRect ( x , y , w , h )
end
2022-08-03 13:51:57 +00:00
if draw_note_mark then
if self.highlight . note_mark == " underline " then
2023-05-07 17:28:18 +00:00
bb : paintRect ( x , y + h - 1 , w , Size.line . medium , Blitbuffer.COLOR_BLACK )
2022-08-03 13:51:57 +00:00
else
local note_mark_pos_x
if self.ui . paging or
2023-09-01 05:07:29 +00:00
( self.document : getVisiblePageCount ( ) == 1 ) or -- one-page mode
2022-08-03 13:51:57 +00:00
( x < Screen : getWidth ( ) / 2 ) then -- page 1 in two-page mode
note_mark_pos_x = self.note_mark_pos_x1
else
note_mark_pos_x = self.note_mark_pos_x2
end
if self.highlight . note_mark == " sideline " then
bb : paintRect ( note_mark_pos_x , y , self.note_mark_line_w , h , Blitbuffer.COLOR_BLACK )
elseif self.highlight . note_mark == " sidemark " then
self.note_mark_sign : paintTo ( bb , note_mark_pos_x , y )
end
end
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
2022-02-06 17:01:45 +00:00
return self.document : getUsedBBoxDimensions ( page , zoom , rotation )
2014-03-13 13:52:43 +00:00
else
2022-02-06 17:01:45 +00:00
return self.document : getPageDimensions ( page , zoom , rotation )
2014-03-13 13:52:43 +00:00
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
2022-02-06 17:01:45 +00:00
if self.ui . paging and self.state . page then
2014-03-13 13:52:43 +00:00
self.page_area = self : getPageArea (
self.state . page ,
self.state . zoom ,
self.state . rotation )
-- reset our size
self.visible_area : setSizeTo ( self.dimen )
2022-02-06 17:01:45 +00:00
if self.footer_visible and not self.footer . settings.reclaim_height then
self.visible_area . h = self.visible_area . h - self.footer : getHeight ( )
2019-11-21 09:05:40 +00:00
end
2022-02-06 17:01:45 +00:00
if self.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
2024-03-17 11:13:04 +00:00
-- Check if we are in zoom_bottom_to_top
if self.document . configurable.zoom_direction and self.document . configurable.zoom_direction >= 2 and self.document . configurable.zoom_direction <= 5 then
2020-11-28 16:18:57 +00:00
-- 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
2022-02-06 17:01:45 +00:00
if self.footer_visible and not self.footer . settings.reclaim_height then
self.state . offset.y = ( self.dimen . h - ( self.visible_area . h + self.footer : getHeight ( ) ) ) / 2
2019-11-21 09:05:40 +00:00
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
2022-08-03 13:51:57 +00:00
self : setupNoteMarkPosition ( )
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
2024-01-12 18:13:44 +00:00
local old_rotation = Screen : getRotationMode ( )
if rotation == old_rotation then
2024-05-06 20:53:13 +00:00
return
2014-03-13 13:52:43 +00:00
end
2024-01-12 18:13:44 +00:00
-- NOTE: We cannot rely on getScreenMode, as it actually checks the screen dimensions, instead of the rotation mode.
-- (i.e., it returns how the screen *looks* like, not how it's oriented relative to its native layout).
-- This would horribly break if you started in Portrait (both rotation and visually),
-- then resized your window to a Landscape layout *without* changing the rotation.
-- If you then attempted to switch to a Landscape *rotation*, it would mistakenly think the layout hadn't changed!
-- So, instead, as we're concerned with *rotation* layouts, just compare the two.
-- We use LinuxFB-style constants, so, Portraits are even, Landscapes are odds, making this trivial.
local matching_orientation = bit.band ( rotation , 1 ) == bit.band ( old_rotation , 1 )
if rotation ~= old_rotation and matching_orientation then
-- No layout change, just rotate & repaint with a flash
Screen : setRotationMode ( rotation )
UIManager : setDirty ( self.dialog , " full " )
Notification : notify ( T ( _ ( " Rotation mode set to: %1 " ) , optionsutil : getOptionText ( " SetRotationMode " , rotation ) ) )
2024-05-06 20:53:13 +00:00
return
2024-01-12 18:13:44 +00:00
end
2020-07-01 20:17:41 +00:00
Screen : setRotationMode ( rotation )
2014-03-13 13:52:43 +00:00
end
2024-01-12 18:13:44 +00:00
UIManager : setDirty ( nil , " full " ) -- SetDimensions will only request a partial, we want a flash
2020-07-01 20:17:41 +00:00
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 ) ) )
2024-05-06 20:53:13 +00:00
return
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 )
2022-02-06 17:01:45 +00:00
if self.ui . paging and page_scroll
2021-04-04 17:48:27 +00:00
and self.ui . zooming.paged_modes [ self.zoom_mode ]
2022-02-06 17:01:45 +00:00
and self.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
2022-02-06 17:01:45 +00:00
self.document . configurable.page_scroll = 0
2020-11-28 16:18:57 +00:00
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 )
2023-07-24 06:25:16 +00:00
if self.ui . paging then
self.document : setTileCacheValidity ( config : readSetting ( " tile_cache_validity_ts " ) )
2023-09-13 04:49:57 +00:00
self.render_mode = config : readSetting ( " render_mode " ) or G_defaults : readSetting ( " DRENDER_MODE " )
2023-09-02 06:41:27 +00:00
if config : has ( " gamma " ) then -- old doc contrast setting
config : saveSetting ( " kopt_contrast " , config : readSetting ( " gamma " ) )
config : delSetting ( " gamma " )
end
2023-07-24 06:25:16 +00:00
end
2023-09-08 05:41:44 +00:00
if G_reader_settings : nilOrFalse ( " lock_rotation " ) then
local setting_name = self.ui . paging and " kopt_rotation_mode " or " copt_rotation_mode "
-- document.configurable.rotation_mode is not ready yet
local rotation_mode = config : readSetting ( setting_name )
or G_reader_settings : readSetting ( setting_name )
or Screen.DEVICE_ROTATED_UPRIGHT
2020-07-01 20:17:41 +00:00
self : onSetRotationMode ( rotation_mode )
2014-03-13 13:52:43 +00:00
end
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
2021-11-21 17:33:51 +00:00
self.inverse_reading_order = config : isTrue ( " inverse_reading_order " ) or G_reader_settings : isTrue ( " inverse_reading_order " )
2022-09-27 23:10:50 +00:00
self.page_overlap_enable = config : isTrue ( " show_overlap_enable " ) or G_reader_settings : isTrue ( " page_overlap_enable " ) or G_defaults : readSetting ( " 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
2022-03-08 20:27:11 +00:00
function ReaderView : shouldInvertBiDiLayoutMirroring ( )
-- A few widgets may temporarily invert UI layout mirroring when both these settings are true
return self.inverse_reading_order and G_reader_settings : isTrue ( " invert_ui_layout_mirroring " )
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
2022-04-06 14:42:29 +00:00
function ReaderView : onPageChangeAnimation ( forward )
if Device : canDoSwipeAnimation ( ) and G_reader_settings : isTrue ( " swipe_animations " ) then
if self.inverse_reading_order then forward = not forward end
Screen : setSwipeAnimations ( true )
Screen : setSwipeDirection ( forward )
end
end
2022-05-23 07:19:47 +00:00
function ReaderView : onTogglePageChangeAnimation ( )
G_reader_settings : flipNilOrFalse ( " swipe_animations " )
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 ;)
2022-02-06 17:01:45 +00:00
if self.ui . paging and self.state . page then
2023-01-08 22:37:35 +00:00
-- We don't need to do anything if reclaim is enabled ;).
2022-02-06 17:01:45 +00:00
if not self.footer . settings.reclaim_height then
2023-01-08 22:37:35 +00:00
-- NOTE: Mimic what onSetFullScreen does, since, without reclaim, toggling the footer affects the available area,
-- so we need to recompute the full layout.
self.ui : handleEvent ( Event : new ( " SetDimensions " , Screen : getSize ( ) ) )
-- NOTE: Scroll mode's behavior after this might be suboptimal (until next page),
-- but I'm not familiar enough with it to make it behave...
-- (e.g., RedrawCurrentPage & co will snap to the top of the "current" page).
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
end
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
2023-09-02 06:41:27 +00:00
Notification : notify ( T ( _ ( " Contrast set to: %1. " ) , gamma ) )
2013-01-05 14:28:14 +00:00
end
2022-02-06 17:01:45 +00:00
-- For ReaderKOptListener
function ReaderView : onDitheringUpdate ( )
-- Do the device cap checks again, to avoid snafus when sharing configs between devices
if Device : hasEinkScreen ( ) then
if Device : canHWDither ( ) then
if self.document . configurable.hw_dithering then
self.document . hw_dithering = self.document . configurable.hw_dithering == 1
end
elseif Screen.fb_bpp == 8 then
if self.document . configurable.sw_dithering then
self.document . sw_dithering = self.document . configurable.sw_dithering == 1
end
end
end
end
-- For KOptOptions
function ReaderView : onHWDitheringUpdate ( toggle )
self.document . hw_dithering = toggle
Notification : notify ( T ( _ ( " Hardware dithering set to: %1. " ) , tostring ( toggle ) ) )
end
function ReaderView : onSWDitheringUpdate ( toggle )
self.document . sw_dithering = toggle
Notification : notify ( T ( _ ( " Software dithering set to: %1. " ) , tostring ( toggle ) ) )
end
2019-08-30 11:47:51 +00:00
function ReaderView : onFontSizeUpdate ( font_size )
2023-04-04 05:11:02 +00:00
if self.ui . paging then
self.ui : handleEvent ( Event : new ( " ReZoom " , font_size ) )
Notification : notify ( T ( _ ( " Font zoom set to: %1. " ) , font_size ) )
end
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
2022-02-06 17:01:45 +00:00
self.document : setViewMode ( new_mode )
2017-10-02 22:31:14 +00:00
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 ( )
2023-07-24 06:25:16 +00:00
if self.ui . paging then
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
self.ui . doc_settings : saveSetting ( " tile_cache_validity_ts " , self.document : getTileCacheValidity ( ) )
2023-09-13 04:49:57 +00:00
if self.document . is_djvu then
self.ui . doc_settings : saveSetting ( " render_mode " , self.render_mode )
end
2021-07-21 20:28:34 +00:00
end
2020-07-24 09:26:49 +00:00
-- Don't etch the current rotation in stone when sticky rotation is enabled
2023-09-08 05:41:44 +00:00
if G_reader_settings : nilOrFalse ( " lock_rotation " ) then
self.document . configurable.rotation_mode = Screen : getRotationMode ( ) -- will be saved by ReaderConfig
2020-07-24 09:26:49 +00:00
end
2021-11-21 17:33:51 +00:00
self.ui . doc_settings : saveSetting ( " inverse_reading_order " , self.inverse_reading_order )
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
2023-08-13 05:01:39 +00:00
function ReaderView : onCloseWidget ( )
-- Stop any pending HintPage event
2016-02-17 06:36:40 +00:00
UIManager : unschedule ( self.emitHintPageEvent )
2023-08-13 11:31:09 +00:00
--- @fixme: The awful readerhighlight_spec test *relies* on this pointer being left dangling...
if not self.ui . _testsuite then
self.emitHintPageEvent = nil
end
2016-02-17 06:36:40 +00:00
end
2016-07-13 06:53:23 +00:00
function ReaderView : onReaderReady ( )
2022-02-10 10:08:51 +00:00
self.ui . doc_settings : delSetting ( " docsettings_reset_done " )
2022-05-05 19:00:22 +00:00
self.settings_last_save_time = UIManager : getElapsedTimeSinceBoot ( )
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.
2022-05-05 19:00:22 +00:00
self.settings_last_save_time = UIManager : getElapsedTimeSinceBoot ( )
2020-01-01 11:27:51 +00:00
end
function ReaderView : checkAutoSaveSettings ( )
2022-05-05 19:00:22 +00:00
if not self.settings_last_save_time 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
2022-05-05 19:00:22 +00:00
local interval_m = G_reader_settings : readSetting ( " auto_save_settings_interval_minutes " )
local interval = time.s ( interval_m * 60 )
local now = UIManager : getElapsedTimeSinceBoot ( )
if now - self.settings_last_save_time >= interval then
self.settings_last_save_time = now
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 ( )
2022-02-06 17:01:45 +00:00
if self.ui . paging then
2021-09-06 19:30:35 +00:00
return not self.page_scroll
and ( self.ui . paging.zoom_mode ~= " page "
2023-06-14 04:36:37 +00:00
or ( self.ui . paging.zoom_mode == " page " and self.document . configurable.text_wrap == 1 ) )
2021-09-06 19:30:35 +00:00
and not self.ui . paging.zoom_mode : find ( " height " )
else
return self.view_mode ~= " page "
end
end
2021-11-23 17:16:10 +00:00
function ReaderView : setupTouchZones ( )
2023-07-24 06:25:16 +00:00
( self.ui . rolling or self.ui . paging ) : setupTouchZones ( )
2021-11-23 17:16:10 +00:00
end
function ReaderView : onToggleReadingOrder ( )
self.inverse_reading_order = not self.inverse_reading_order
self : setupTouchZones ( )
2021-11-21 17:33:51 +00:00
local is_rtl = self.inverse_reading_order ~= BD.mirroredUILayout ( ) -- mirrored reading
2023-02-07 00:01:05 +00:00
Notification : notify ( is_rtl and _ ( " RTL page turning. " ) or _ ( " LTR page turning. " ) )
2021-11-21 17:33:51 +00:00
return true
end
function ReaderView : getTapZones ( )
2021-11-23 17:16:10 +00:00
local forward_zone , backward_zone
local tap_zones_type = G_reader_settings : readSetting ( " page_turns_tap_zones " , " default " )
if tap_zones_type == " default " then
2022-09-27 23:10:50 +00:00
local DTAP_ZONE_FORWARD = G_defaults : readSetting ( " DTAP_ZONE_FORWARD " )
2021-11-23 17:16:10 +00:00
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 ,
}
2022-09-27 23:10:50 +00:00
local DTAP_ZONE_BACKWARD = G_defaults : readSetting ( " DTAP_ZONE_BACKWARD " )
2021-11-23 17:16:10 +00:00
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 ,
}
else -- user defined page turns tap zones
2022-09-27 23:10:50 +00:00
local tap_zone_forward_w = G_reader_settings : readSetting ( " page_turns_tap_zone_forward_size_ratio " , G_defaults : readSetting ( " DTAP_ZONE_FORWARD " ) . w )
2022-11-12 06:40:31 +00:00
local tap_zone_backward_w = G_reader_settings : readSetting ( " page_turns_tap_zone_backward_size_ratio " , G_defaults : readSetting ( " DTAP_ZONE_BACKWARD " ) . w )
2021-11-23 17:16:10 +00:00
if tap_zones_type == " left_right " then
forward_zone = {
2022-11-12 06:40:31 +00:00
ratio_x = 1 - tap_zone_forward_w , ratio_y = 0 ,
2021-11-23 17:16:10 +00:00
ratio_w = tap_zone_forward_w , ratio_h = 1 ,
}
backward_zone = {
ratio_x = 0 , ratio_y = 0 ,
ratio_w = tap_zone_backward_w , ratio_h = 1 ,
}
else
forward_zone = {
2022-11-12 06:40:31 +00:00
ratio_x = 0 , ratio_y = 1 - tap_zone_forward_w ,
2021-11-23 17:16:10 +00:00
ratio_w = 1 , ratio_h = tap_zone_forward_w ,
}
backward_zone = {
ratio_x = 0 , ratio_y = 0 ,
ratio_w = 1 , ratio_h = tap_zone_backward_w ,
}
end
end
2021-11-21 17:33:51 +00:00
if self.inverse_reading_order ~= BD.mirroredUILayout ( ) then -- mirrored reading
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
end
return forward_zone , backward_zone
end
2022-08-03 13:51:57 +00:00
function ReaderView : setupNoteMarkPosition ( )
local is_sidemark = self.highlight . note_mark == " sidemark "
-- set/free note marker sign
if is_sidemark then
if not self.note_mark_sign then
self.note_mark_sign = TextWidget : new {
text = " \u{F040} " , -- pencil
face = Font : getFace ( " smallinfofont " , 14 ) ,
padding = 0 ,
}
end
else
if self.note_mark_sign then
self.note_mark_sign : free ( )
self.note_mark_sign = nil
end
end
-- calculate position x of the note side line/mark
if is_sidemark or self.highlight . note_mark == " sideline " then
local screen_w = Screen : getWidth ( )
local sign_w = is_sidemark and self.note_mark_sign : getWidth ( ) or self.note_mark_line_w
local sign_gap = Screen : scaleBySize ( 5 ) -- to the text (cre) or to the screen edge (pdf)
if self.ui . paging then
if BD.mirroredUILayout ( ) then
self.note_mark_pos_x1 = sign_gap
else
self.note_mark_pos_x1 = screen_w - sign_gap - sign_w
end
else
2023-09-01 05:07:29 +00:00
local doc_margins = self.document : getPageMargins ( )
2022-08-03 13:51:57 +00:00
local pos_x_r = screen_w - doc_margins [ " right " ] + sign_gap -- mark in the right margin
local pos_x_l = doc_margins [ " left " ] - sign_gap - sign_w -- mark in the left margin
2023-09-01 05:07:29 +00:00
if self.document : getVisiblePageCount ( ) == 1 then
2022-08-03 13:51:57 +00:00
if BD.mirroredUILayout ( ) then
self.note_mark_pos_x1 = pos_x_l
else
self.note_mark_pos_x1 = pos_x_r
end
else -- two-page mode
2023-09-01 05:07:29 +00:00
local page2_x = self.document : getPageOffsetX ( self.document : getCurrentPage ( true ) + 1 )
2022-08-03 13:51:57 +00:00
if BD.mirroredUILayout ( ) then
self.note_mark_pos_x1 = pos_x_l
self.note_mark_pos_x2 = pos_x_l + page2_x
else
self.note_mark_pos_x1 = pos_x_r - page2_x
self.note_mark_pos_x2 = pos_x_r
end
end
end
end
end
2023-09-01 05:07:29 +00:00
function ReaderView : getCurrentPageLineWordCounts ( )
local lines_nb , words_nb = 0 , 0
if self.ui . rolling then
local res = self.document : getTextFromPositions ( { x = 0 , y = 0 } ,
{ x = Screen : getWidth ( ) , y = Screen : getHeight ( ) } , true ) -- do not highlight
if res then
lines_nb = # self.document : getScreenBoxesFromPositions ( res.pos0 , res.pos1 , true )
for word in util.gsplit ( res.text , " [%s%p]+ " , false ) do
if util.hasCJKChar ( word ) then
for char in util.gsplit ( word , " [ \192 - \255 ][ \128 - \191 ]+ " , true ) do
words_nb = words_nb + 1
end
else
words_nb = words_nb + 1
end
end
end
else
local page_boxes = self.document : getTextBoxes ( self.ui : getCurrentPage ( ) )
if page_boxes and page_boxes [ 1 ] [ 1 ] . word then
lines_nb = # page_boxes
for _ , line in ipairs ( page_boxes ) do
if # line == 1 and line [ 1 ] . word == " " then -- empty line
lines_nb = lines_nb - 1
else
words_nb = words_nb + # line
local last_word = line [ # line ] . word
if last_word : sub ( - 1 ) == " - " and last_word ~= " - " then -- hyphenated
words_nb = words_nb - 1
end
end
end
end
end
return lines_nb , words_nb
end
2013-10-18 20:38:07 +00:00
return ReaderView