mirror of
https://github.com/koreader/koreader
synced 2024-10-31 21:20:20 +00:00
b1e9b35da8
Otherwise, current_page can acquire negative values, or values greater than the page count, when the user tries to go back the first page or past the last page.
390 lines
11 KiB
Lua
390 lines
11 KiB
Lua
local InputContainer = require("ui/widget/container/inputcontainer")
|
|
local Screen = require("ui/screen")
|
|
local Device = require("ui/device")
|
|
local Geom = require("ui/geometry")
|
|
local Input = require("ui/input")
|
|
local Event = require("ui/event")
|
|
local GestureRange = require("ui/gesturerange")
|
|
local ReaderPanning = require("ui/reader/readerpanning")
|
|
local UIManager = require("ui/uimanager")
|
|
local DEBUG = require("dbg")
|
|
local _ = require("gettext")
|
|
|
|
local ReaderRolling = InputContainer:new{
|
|
old_doc_height = nil,
|
|
old_page = nil,
|
|
current_pos = 0,
|
|
-- only used for page view mode
|
|
current_page= nil,
|
|
doc_height = nil,
|
|
panning_steps = ReaderPanning.panning_steps,
|
|
show_overlap_enable = true,
|
|
overlap = 20,
|
|
}
|
|
|
|
function ReaderRolling:init()
|
|
if Device:hasKeyboard() then
|
|
self.key_events = {
|
|
GotoNextView = {
|
|
{ Input.group.PgFwd },
|
|
doc = _("go to next view"),
|
|
event = "GotoViewRel", args = 1
|
|
},
|
|
GotoPrevView = {
|
|
{ Input.group.PgBack },
|
|
doc = _("go to previous view"),
|
|
event = "GotoViewRel", args = -1
|
|
},
|
|
MoveUp = {
|
|
{ "Up" },
|
|
doc = _("move view up"),
|
|
event = "Panning", args = {0, -1}
|
|
},
|
|
MoveDown = {
|
|
{ "Down" },
|
|
doc = _("move view down"),
|
|
event = "Panning", args = {0, 1}
|
|
},
|
|
GotoFirst = {
|
|
{"1"}, doc = _("go to start"), event = "GotoPercent", args = 0},
|
|
Goto11 = {
|
|
{"2"}, doc = _("go to 11%"), event = "GotoPercent", args = 11},
|
|
Goto22 = {
|
|
{"3"}, doc = _("go to 22%"), event = "GotoPercent", args = 22},
|
|
Goto33 = {
|
|
{"4"}, doc = _("go to 33%"), event = "GotoPercent", args = 33},
|
|
Goto44 = {
|
|
{"5"}, doc = _("go to 44%"), event = "GotoPercent", args = 44},
|
|
Goto55 = {
|
|
{"6"}, doc = _("go to 55%"), event = "GotoPercent", args = 55},
|
|
Goto66 = {
|
|
{"7"}, doc = _("go to 66%"), event = "GotoPercent", args = 66},
|
|
Goto77 = {
|
|
{"8"}, doc = _("go to 77%"), event = "GotoPercent", args = 77},
|
|
Goto88 = {
|
|
{"9"}, doc = _("go to 88%"), event = "GotoPercent", args = 88},
|
|
GotoLast = {
|
|
{"0"}, doc = _("go to end"), event = "GotoPercent", args = 100},
|
|
}
|
|
end
|
|
|
|
table.insert(self.ui.postInitCallback, function()
|
|
self.doc_height = self.ui.document.info.doc_height
|
|
self.old_doc_height = self.doc_height
|
|
self.old_page = self.ui.document.info.number_of_pages
|
|
end)
|
|
end
|
|
|
|
-- This method will be called in onSetDimensions handler
|
|
function ReaderRolling:initGesListener()
|
|
self.ges_events = {
|
|
TapForward = {
|
|
GestureRange:new{
|
|
ges = "tap",
|
|
range = Geom:new{
|
|
x = Screen:getWidth()*DTAP_ZONE_FORWARD.x,
|
|
y = Screen:getHeight()*DTAP_ZONE_FORWARD.y,
|
|
w = Screen:getWidth()*DTAP_ZONE_FORWARD.w,
|
|
h = Screen:getHeight()*DTAP_ZONE_FORWARD.h,
|
|
}
|
|
}
|
|
},
|
|
TapBackward = {
|
|
GestureRange:new{
|
|
ges = "tap",
|
|
range = Geom:new{
|
|
x = Screen:getWidth()*DTAP_ZONE_BACKWARD.x,
|
|
y = Screen:getHeight()*DTAP_ZONE_BACKWARD.y,
|
|
w = Screen:getWidth()*DTAP_ZONE_BACKWARD.w,
|
|
h = Screen:getHeight()*DTAP_ZONE_BACKWARD.h,
|
|
}
|
|
}
|
|
},
|
|
Swipe = {
|
|
GestureRange:new{
|
|
ges = "swipe",
|
|
range = Geom:new{
|
|
x = 0, y = 0,
|
|
w = Screen:getWidth(),
|
|
h = Screen:getHeight(),
|
|
}
|
|
}
|
|
},
|
|
Pan = {
|
|
GestureRange:new{
|
|
ges = "pan",
|
|
range = Geom:new{
|
|
x = 0, y = 0,
|
|
w = Screen:getWidth(),
|
|
h = Screen:getHeight(),
|
|
},
|
|
rate = 4.0,
|
|
}
|
|
},
|
|
}
|
|
end
|
|
|
|
function ReaderRolling:onReadSettings(config)
|
|
local soe = config:readSetting("show_overlap_enable")
|
|
if not soe then
|
|
self.show_overlap_enable = soe
|
|
end
|
|
local last_xp = config:readSetting("last_xpointer")
|
|
if last_xp then
|
|
table.insert(self.ui.postInitCallback, function()
|
|
self:gotoXPointer(last_xp)
|
|
-- we have to do a real jump in self.ui.document._document to
|
|
-- update status information in CREngine.
|
|
self.ui.document:gotoXPointer(last_xp)
|
|
end)
|
|
end
|
|
-- we read last_percent just for backward compatibility
|
|
if not last_xp then
|
|
local last_per = config:readSetting("last_percent")
|
|
if last_per then
|
|
table.insert(self.ui.postInitCallback, function()
|
|
self:gotoPercent(last_per)
|
|
-- we have to do a real pos change in self.ui.document._document
|
|
-- to update status information in CREngine.
|
|
self.ui.document:gotoPos(self.current_pos)
|
|
end)
|
|
end
|
|
end
|
|
if self.view.view_mode == "page" then
|
|
self.ui:handleEvent(Event:new("PageUpdate", self.ui.document:getCurrentPage()))
|
|
end
|
|
end
|
|
|
|
function ReaderRolling:onSaveSettings()
|
|
-- remove last_percent config since its deprecated
|
|
self.ui.doc_settings:saveSetting("last_percent", nil)
|
|
self.ui.doc_settings:saveSetting("last_xpointer", self.ui.document:getXPointer())
|
|
self.ui.doc_settings:saveSetting("percent_finished", self:getLastPercent())
|
|
end
|
|
|
|
function ReaderRolling:getLastPercent()
|
|
if self.view.view_mode == "page" then
|
|
return self.current_page / self.old_page
|
|
else
|
|
-- FIXME: the calculated percent is not accurate in "scroll" mode.
|
|
return self.ui.document:getPosFromXPointer(
|
|
self.ui.document:getXPointer()) / self.doc_height
|
|
end
|
|
end
|
|
|
|
function ReaderRolling:onTapForward()
|
|
self:onGotoViewRel(1)
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onTapBackward()
|
|
self:onGotoViewRel(-1)
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onSwipe(arg, ges)
|
|
if ges.direction == "west" then
|
|
self.ui.document:goForward()
|
|
self:onUpdateXPointer()
|
|
elseif ges.direction == "east" then
|
|
self.ui.document:goBack()
|
|
self:onUpdateXPointer()
|
|
end
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onPan(arg, ges)
|
|
if self.view.view_mode == "scroll" then
|
|
if ges.direction == "north" then
|
|
self:gotoPos(self.current_pos + ges.distance)
|
|
elseif ges.direction == "south" then
|
|
self:gotoPos(self.current_pos - ges.distance)
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onPosUpdate(new_pos)
|
|
self.current_pos = new_pos
|
|
self:updatePageLink()
|
|
self:updateBatteryState()
|
|
end
|
|
|
|
function ReaderRolling:onPageUpdate(new_page)
|
|
self.current_page = new_page
|
|
self:updatePageLink()
|
|
self:updateBatteryState()
|
|
end
|
|
|
|
function ReaderRolling:onResume()
|
|
self:updateBatteryState()
|
|
end
|
|
|
|
function ReaderRolling:onNotCharging()
|
|
self:updateBatteryState()
|
|
end
|
|
|
|
function ReaderRolling:onGotoPercent(percent)
|
|
DEBUG("goto document offset in percent:", percent)
|
|
self:gotoPercent(percent)
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onGotoViewRel(diff)
|
|
DEBUG("goto relative screen:", diff, ", in mode: ", self.view.view_mode)
|
|
if self.view.view_mode == "scroll" then
|
|
local pan_diff = diff * self.ui.dimen.h
|
|
if self.show_overlap_enable then
|
|
if pan_diff > self.overlap then
|
|
pan_diff = pan_diff - self.overlap
|
|
elseif pan_diff < -self.overlap then
|
|
pan_diff = pan_diff + self.overlap
|
|
end
|
|
end
|
|
self:gotoPos(self.current_pos + pan_diff)
|
|
elseif self.view.view_mode == "page" then
|
|
self:gotoPage(self.current_page + diff)
|
|
end
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onPanning(args, key)
|
|
--@TODO disable panning in page view_mode? 22.12 2012 (houqp)
|
|
local _, dy = unpack(args)
|
|
DEBUG("key =", key)
|
|
self:gotoPos(self.current_pos + dy * self.panning_steps.normal)
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onZoom()
|
|
--@TODO re-read doc_height info after font or lineheight changes 05.06 2012 (houqp)
|
|
self:updatePos()
|
|
end
|
|
|
|
--[[
|
|
remember to signal this event when the document has been zoomed,
|
|
font has been changed, or line height has been changed.
|
|
--]]
|
|
function ReaderRolling:onUpdatePos()
|
|
UIManager:scheduleIn(0.1, function () self:updatePos() end)
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:updatePos()
|
|
-- reread document height
|
|
self.ui.document:_readMetadata()
|
|
-- update self.current_pos if the height of document has been changed.
|
|
local new_height = self.ui.document.info.doc_height
|
|
local new_page = self.ui.document.info.number_of_pages
|
|
if self.old_doc_height ~= new_height or self.old_page ~= new_page then
|
|
self:gotoXPointer(self.ui.document:getXPointer())
|
|
self.old_doc_height = new_height
|
|
self.old_page = new_page
|
|
self.ui:handleEvent(Event:new("UpdateToc"))
|
|
end
|
|
UIManager.repaint_all = true
|
|
end
|
|
|
|
function ReaderRolling:onUpdateXPointer()
|
|
local xp = self.ui.document:getXPointer()
|
|
if self.view.view_mode == "page" then
|
|
self.ui:handleEvent(Event:new("PageUpdate", self.ui.document:getPageFromXPointer(xp)))
|
|
else
|
|
self.ui:handleEvent(Event:new("PosUpdate", self.ui.document:getPosFromXPointer(xp)))
|
|
end
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onChangeViewMode()
|
|
self.ui.document:_readMetadata()
|
|
self.old_doc_height = self.ui.document.info.doc_height
|
|
self.old_page = self.ui.document.info.number_of_pages
|
|
self.ui:handleEvent(Event:new("UpdateToc"))
|
|
self:gotoXPointer(self.ui.document:getXPointer())
|
|
if self.view.view_mode == "scroll" then
|
|
self.current_pos = self.ui.document:getCurrentPos()
|
|
else
|
|
self.current_page = self.ui.document:getCurrentPage()
|
|
end
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onRedrawCurrentView()
|
|
if self.view.view_mode == "page" then
|
|
self.ui:handleEvent(Event:new("PageUpdate", self.current_page))
|
|
else
|
|
self.ui:handleEvent(Event:new("PosUpdate", self.current_pos))
|
|
end
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:onSetDimensions()
|
|
-- update listening according to new screen dimen
|
|
if Device:isTouchDevice() then
|
|
self:initGesListener()
|
|
end
|
|
end
|
|
|
|
--[[
|
|
PosUpdate event is used to signal other widgets that pos has been changed.
|
|
--]]
|
|
function ReaderRolling:gotoPos(new_pos)
|
|
if new_pos == self.current_pos then return end
|
|
if new_pos < 0 then new_pos = 0 end
|
|
if new_pos > self.doc_height then new_pos = self.doc_height end
|
|
-- adjust dim_area according to new_pos
|
|
if self.view.view_mode ~= "page" and self.show_overlap_enable then
|
|
local panned_step = new_pos - self.current_pos
|
|
self.view.dim_area.x = 0
|
|
self.view.dim_area.h = self.ui.dimen.h - math.abs(panned_step)
|
|
self.view.dim_area.w = self.ui.dimen.w
|
|
if panned_step < 0 then
|
|
self.view.dim_area.y = self.ui.dimen.h - self.view.dim_area.h
|
|
elseif panned_step > 0 then
|
|
self.view.dim_area.y = 0
|
|
end
|
|
end
|
|
self.ui:handleEvent(Event:new("PosUpdate", new_pos))
|
|
end
|
|
|
|
function ReaderRolling:gotoPage(new_page)
|
|
self.ui.document:gotoPage(new_page)
|
|
self.ui:handleEvent(Event:new("PageUpdate", self.ui.document:getCurrentPage()))
|
|
end
|
|
|
|
function ReaderRolling:gotoXPointer(xpointer)
|
|
if self.view.view_mode == "page" then
|
|
self:gotoPage(self.ui.document:getPageFromXPointer(xpointer))
|
|
else
|
|
self:gotoPos(self.ui.document:getPosFromXPointer(xpointer))
|
|
end
|
|
end
|
|
|
|
function ReaderRolling:gotoPercent(new_percent)
|
|
self:gotoPos(new_percent * self.doc_height / 10000)
|
|
end
|
|
|
|
function ReaderRolling:onGotoPage(number)
|
|
self:gotoPage(number)
|
|
return true
|
|
end
|
|
|
|
function ReaderRolling:updatePageLink()
|
|
DEBUG("update page link")
|
|
local links = self.ui.document:getPageLinks()
|
|
self.view.links = links
|
|
end
|
|
|
|
function ReaderRolling:updateBatteryState()
|
|
DEBUG("update battery state")
|
|
if self.view.view_mode == "page" then
|
|
local powerd = Device:getPowerDevice()
|
|
local state = powerd:isCharging() and -1 or powerd:getCapacity()
|
|
if state then
|
|
self.ui.document:setBatteryState(state)
|
|
end
|
|
end
|
|
end
|
|
|
|
return ReaderRolling
|