mirror of
https://github.com/koreader/koreader.git
synced 2025-12-13 20:36:53 +01:00
cleanup: expand tab to 4 spaces
This commit is contained in:
34
defaults.lua
34
defaults.lua
@@ -69,26 +69,26 @@ DTAP_ZONE_BOOKMARK = {x = 7/8, y = 0, w = 1/8, h = 1/8}
|
||||
DTAP_ZONE_FLIPPING = {x = 0, y = 0, w = 1/8, h = 1/8}
|
||||
|
||||
-- koptreader config defaults
|
||||
DKOPTREADER_CONFIG_FONT_SIZE = 1.0 -- range from 0.1 to 3.0
|
||||
DKOPTREADER_CONFIG_TEXT_WRAP = 0 -- 1 = on, 0 = off
|
||||
DKOPTREADER_CONFIG_TRIM_PAGE = 1 -- 1 = auto, 0 = manual
|
||||
DKOPTREADER_CONFIG_DETECT_INDENT = 1 -- 1 = enable, 0 = disable
|
||||
DKOPTREADER_CONFIG_DEFECT_SIZE = 1.0 -- range from 0.0 to 3.0
|
||||
DKOPTREADER_CONFIG_PAGE_MARGIN = 0.10 -- range from 0.0 to 1.0
|
||||
DKOPTREADER_CONFIG_LINE_SPACING = 1.2 -- range from 0.5 to 2.0
|
||||
DKOPTREADER_CONFIG_RENDER_QUALITY = 1.0 -- range from 0.5 to 2.0
|
||||
DKOPTREADER_CONFIG_AUTO_STRAIGHTEN = 0 -- range from 0 to 10
|
||||
DKOPTREADER_CONFIG_JUSTIFICATION = 3 -- -1 = auto, 0 = left, 1 = center, 2 = right, 3 = full
|
||||
DKOPTREADER_CONFIG_MAX_COLUMNS = 2 -- range from 1 to 4
|
||||
DKOPTREADER_CONFIG_CONTRAST = 1.0 -- range from 0.2 to 2.0
|
||||
DKOPTREADER_CONFIG_FONT_SIZE = 1.0 -- range from 0.1 to 3.0
|
||||
DKOPTREADER_CONFIG_TEXT_WRAP = 0 -- 1 = on, 0 = off
|
||||
DKOPTREADER_CONFIG_TRIM_PAGE = 1 -- 1 = auto, 0 = manual
|
||||
DKOPTREADER_CONFIG_DETECT_INDENT = 1 -- 1 = enable, 0 = disable
|
||||
DKOPTREADER_CONFIG_DEFECT_SIZE = 1.0 -- range from 0.0 to 3.0
|
||||
DKOPTREADER_CONFIG_PAGE_MARGIN = 0.10 -- range from 0.0 to 1.0
|
||||
DKOPTREADER_CONFIG_LINE_SPACING = 1.2 -- range from 0.5 to 2.0
|
||||
DKOPTREADER_CONFIG_RENDER_QUALITY = 1.0 -- range from 0.5 to 2.0
|
||||
DKOPTREADER_CONFIG_AUTO_STRAIGHTEN = 0 -- range from 0 to 10
|
||||
DKOPTREADER_CONFIG_JUSTIFICATION = 3 -- -1 = auto, 0 = left, 1 = center, 2 = right, 3 = full
|
||||
DKOPTREADER_CONFIG_MAX_COLUMNS = 2 -- range from 1 to 4
|
||||
DKOPTREADER_CONFIG_CONTRAST = 1.0 -- range from 0.2 to 2.0
|
||||
|
||||
-- word spacing for reflow
|
||||
DKOPTREADER_CONFIG_WORD_SAPCINGS = {0.05, -1, 0.375} -- range from 0.05 to 0.5
|
||||
DKOPTREADER_CONFIG_DEFAULT_WORD_SAPCING = -1 -- range from 0.05 to 0.5
|
||||
DKOPTREADER_CONFIG_DEFAULT_WORD_SAPCING = -1 -- range from 0.05 to 0.5
|
||||
-- document languages for OCR
|
||||
DKOPTREADER_CONFIG_DOC_LANGS_TEXT = {"English", "Chinese"}
|
||||
DKOPTREADER_CONFIG_DOC_LANGS_CODE = {"eng", "chi_sim"} -- language code, make sure you have corresponding training data
|
||||
DKOPTREADER_CONFIG_DOC_DEFAULT_LANG_CODE = "eng" -- that have filenames starting with the language codes
|
||||
DKOPTREADER_CONFIG_DOC_LANGS_CODE = {"eng", "chi_sim"} -- language code, make sure you have corresponding training data
|
||||
DKOPTREADER_CONFIG_DOC_DEFAULT_LANG_CODE = "eng" -- that have filenames starting with the language codes
|
||||
|
||||
-- crereader font sizes
|
||||
-- feel free to add more entries in this list
|
||||
@@ -170,5 +170,5 @@ DDICT_FONT_SIZE = 20
|
||||
--DPICVIEWER_PAGE_MODE_ENABLE = false
|
||||
|
||||
|
||||
--DKOPTREADER_CONFIG_MULTI_THREADS = 1 -- 1 = on, 0 = off
|
||||
--DKOPTREADER_CONFIG_SCREEN_ROTATION = 0 -- 0, 90, 180, 270 degrees
|
||||
--DKOPTREADER_CONFIG_MULTI_THREADS = 1 -- 1 = on, 0 = off
|
||||
--DKOPTREADER_CONFIG_SCREEN_ROTATION = 0 -- 0, 90, 180, 270 degrees
|
||||
|
||||
@@ -17,175 +17,175 @@ local DEBUG = require("dbg")
|
||||
local _ = require("gettext")
|
||||
|
||||
local FileManager = InputContainer:extend{
|
||||
title = _("FileManager"),
|
||||
width = Screen:getWidth(),
|
||||
height = Screen:getHeight(),
|
||||
root_path = lfs.currentdir(),
|
||||
-- our own size
|
||||
dimen = Geom:new{ w = 400, h = 600 },
|
||||
onExit = function() end,
|
||||
title = _("FileManager"),
|
||||
width = Screen:getWidth(),
|
||||
height = Screen:getHeight(),
|
||||
root_path = lfs.currentdir(),
|
||||
-- our own size
|
||||
dimen = Geom:new{ w = 400, h = 600 },
|
||||
onExit = function() end,
|
||||
}
|
||||
|
||||
function FileManager:init()
|
||||
local exclude_dirs = {"%.sdr$"}
|
||||
local exclude_dirs = {"%.sdr$"}
|
||||
|
||||
self.show_parent = self.show_parent or self
|
||||
self.show_parent = self.show_parent or self
|
||||
|
||||
self.banner = VerticalGroup:new{
|
||||
TextWidget:new{
|
||||
face = Font:getFace("tfont", 24),
|
||||
text = self.title,
|
||||
},
|
||||
VerticalSpan:new{ width = Screen:scaleByDPI(10) }
|
||||
}
|
||||
|
||||
local g_show_hidden = G_reader_settings:readSetting("show_hidden")
|
||||
local show_hidden = g_show_hidden == nil and DSHOWHIDDENFILES or g_show_hidden
|
||||
local file_chooser = FileChooser:new{
|
||||
-- remeber to adjust the height when new item is added to the group
|
||||
path = self.root_path,
|
||||
show_parent = self.show_parent,
|
||||
show_hidden = show_hidden,
|
||||
height = Screen:getHeight() - self.banner:getSize().h,
|
||||
is_popout = false,
|
||||
is_borderless = true,
|
||||
has_close_button = true,
|
||||
dir_filter = function(dirname)
|
||||
for _, pattern in ipairs(exclude_dirs) do
|
||||
if dirname:match(pattern) then return end
|
||||
end
|
||||
return true
|
||||
end,
|
||||
file_filter = function(filename)
|
||||
if DocumentRegistry:getProvider(filename) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
}
|
||||
self.file_chooser = file_chooser
|
||||
self.banner = VerticalGroup:new{
|
||||
TextWidget:new{
|
||||
face = Font:getFace("tfont", 24),
|
||||
text = self.title,
|
||||
},
|
||||
VerticalSpan:new{ width = Screen:scaleByDPI(10) }
|
||||
}
|
||||
|
||||
local g_show_hidden = G_reader_settings:readSetting("show_hidden")
|
||||
local show_hidden = g_show_hidden == nil and DSHOWHIDDENFILES or g_show_hidden
|
||||
local file_chooser = FileChooser:new{
|
||||
-- remeber to adjust the height when new item is added to the group
|
||||
path = self.root_path,
|
||||
show_parent = self.show_parent,
|
||||
show_hidden = show_hidden,
|
||||
height = Screen:getHeight() - self.banner:getSize().h,
|
||||
is_popout = false,
|
||||
is_borderless = true,
|
||||
has_close_button = true,
|
||||
dir_filter = function(dirname)
|
||||
for _, pattern in ipairs(exclude_dirs) do
|
||||
if dirname:match(pattern) then return end
|
||||
end
|
||||
return true
|
||||
end,
|
||||
file_filter = function(filename)
|
||||
if DocumentRegistry:getProvider(filename) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
}
|
||||
self.file_chooser = file_chooser
|
||||
|
||||
function file_chooser:onFileSelect(file)
|
||||
showReaderUI(file)
|
||||
return true
|
||||
end
|
||||
|
||||
local copyFile = function(file) self:copyFile(file) end
|
||||
local pasteHere = function(file) self:pasteHere(file) end
|
||||
local cutFile = function(file) self:cutFile(file) end
|
||||
local deleteFile = function(file) self:deleteFile(file) end
|
||||
local fileManager = self
|
||||
|
||||
function file_chooser:onFileHold(file)
|
||||
--DEBUG("hold file", file)
|
||||
self.file_dialog = ButtonDialog:new{
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Copy"),
|
||||
callback = function()
|
||||
copyFile(file)
|
||||
UIManager:close(self.file_dialog)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Paste"),
|
||||
enabled = fileManager.clipboard and true or false,
|
||||
callback = function()
|
||||
pasteHere(file)
|
||||
self:refreshPath()
|
||||
UIManager:close(self.file_dialog)
|
||||
end,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
text = _("Cut"),
|
||||
callback = function()
|
||||
cutFile(file)
|
||||
UIManager:close(self.file_dialog)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Delete"),
|
||||
callback = function()
|
||||
local path = util.realpath(file)
|
||||
deleteFile(file)
|
||||
self:refreshPath()
|
||||
UIManager:close(self.file_dialog)
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
UIManager:show(self.file_dialog)
|
||||
return true
|
||||
end
|
||||
function file_chooser:onFileSelect(file)
|
||||
showReaderUI(file)
|
||||
return true
|
||||
end
|
||||
|
||||
local copyFile = function(file) self:copyFile(file) end
|
||||
local pasteHere = function(file) self:pasteHere(file) end
|
||||
local cutFile = function(file) self:cutFile(file) end
|
||||
local deleteFile = function(file) self:deleteFile(file) end
|
||||
local fileManager = self
|
||||
|
||||
function file_chooser:onFileHold(file)
|
||||
--DEBUG("hold file", file)
|
||||
self.file_dialog = ButtonDialog:new{
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Copy"),
|
||||
callback = function()
|
||||
copyFile(file)
|
||||
UIManager:close(self.file_dialog)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Paste"),
|
||||
enabled = fileManager.clipboard and true or false,
|
||||
callback = function()
|
||||
pasteHere(file)
|
||||
self:refreshPath()
|
||||
UIManager:close(self.file_dialog)
|
||||
end,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
text = _("Cut"),
|
||||
callback = function()
|
||||
cutFile(file)
|
||||
UIManager:close(self.file_dialog)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Delete"),
|
||||
callback = function()
|
||||
local path = util.realpath(file)
|
||||
deleteFile(file)
|
||||
self:refreshPath()
|
||||
UIManager:close(self.file_dialog)
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
UIManager:show(self.file_dialog)
|
||||
return true
|
||||
end
|
||||
|
||||
self.layout = VerticalGroup:new{
|
||||
self.banner,
|
||||
file_chooser,
|
||||
}
|
||||
self.layout = VerticalGroup:new{
|
||||
self.banner,
|
||||
file_chooser,
|
||||
}
|
||||
|
||||
local fm_ui = FrameContainer:new{
|
||||
padding = 0,
|
||||
bordersize = 0,
|
||||
background = 0,
|
||||
self.layout,
|
||||
}
|
||||
local fm_ui = FrameContainer:new{
|
||||
padding = 0,
|
||||
bordersize = 0,
|
||||
background = 0,
|
||||
self.layout,
|
||||
}
|
||||
|
||||
self[1] = fm_ui
|
||||
self[1] = fm_ui
|
||||
|
||||
self.menu = FileManagerMenu:new{
|
||||
ui = self
|
||||
}
|
||||
table.insert(self, self.menu)
|
||||
table.insert(self, FileManagerHistory:new{
|
||||
ui = self,
|
||||
menu = self.menu
|
||||
})
|
||||
self.menu = FileManagerMenu:new{
|
||||
ui = self
|
||||
}
|
||||
table.insert(self, self.menu)
|
||||
table.insert(self, FileManagerHistory:new{
|
||||
ui = self,
|
||||
menu = self.menu
|
||||
})
|
||||
|
||||
self:handleEvent(Event:new("SetDimensions", self.dimen))
|
||||
self:handleEvent(Event:new("SetDimensions", self.dimen))
|
||||
end
|
||||
|
||||
function FileManager:toggleHiddenFiles()
|
||||
self.file_chooser:toggleHiddenFiles()
|
||||
G_reader_settings:saveSetting("show_hidden", self.file_chooser.show_hidden)
|
||||
self.file_chooser:toggleHiddenFiles()
|
||||
G_reader_settings:saveSetting("show_hidden", self.file_chooser.show_hidden)
|
||||
end
|
||||
|
||||
function FileManager:onClose()
|
||||
UIManager:close(self)
|
||||
if self.onExit then
|
||||
self:onExit()
|
||||
end
|
||||
return true
|
||||
UIManager:close(self)
|
||||
if self.onExit then
|
||||
self:onExit()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function FileManager:copyFile(file)
|
||||
self.cutfile = false
|
||||
self.clipboard = file
|
||||
self.cutfile = false
|
||||
self.clipboard = file
|
||||
end
|
||||
|
||||
function FileManager:cutFile(file)
|
||||
self.cutfile = true
|
||||
self.clipboard = file
|
||||
self.cutfile = true
|
||||
self.clipboard = file
|
||||
end
|
||||
|
||||
function FileManager:pasteHere(file)
|
||||
if self.clipboard then
|
||||
file = util.realpath(file)
|
||||
local orig = util.realpath(self.clipboard)
|
||||
local dest = lfs.attributes(file, "mode") == "directory" and
|
||||
file or file:match("(.*/)")
|
||||
if self.cutfile then
|
||||
util.execute("/bin/mv", orig, dest)
|
||||
else
|
||||
util.execute("/bin/cp", "-r", orig, dest)
|
||||
end
|
||||
end
|
||||
if self.clipboard then
|
||||
file = util.realpath(file)
|
||||
local orig = util.realpath(self.clipboard)
|
||||
local dest = lfs.attributes(file, "mode") == "directory" and
|
||||
file or file:match("(.*/)")
|
||||
if self.cutfile then
|
||||
util.execute("/bin/mv", orig, dest)
|
||||
else
|
||||
util.execute("/bin/cp", "-r", orig, dest)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function FileManager:deleteFile(file)
|
||||
util.execute("/bin/rm", "-r", util.realpath(file))
|
||||
util.execute("/bin/rm", "-r", util.realpath(file))
|
||||
end
|
||||
|
||||
return FileManager
|
||||
|
||||
@@ -11,103 +11,103 @@ local _ = require("gettext")
|
||||
local history_dir = "./history/"
|
||||
|
||||
local FileManagerHistory = InputContainer:extend{
|
||||
hist_menu_title = _("History"),
|
||||
hist_menu_title = _("History"),
|
||||
}
|
||||
|
||||
function FileManagerHistory:init()
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function FileManagerHistory:onSetDimensions(dimen)
|
||||
self.dimen = dimen
|
||||
self.dimen = dimen
|
||||
end
|
||||
|
||||
function FileManagerHistory:onMenuHold(item)
|
||||
self.histfile_dialog = ButtonDialog:new{
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Delete"),
|
||||
callback = function()
|
||||
os.remove(history_dir..item.histfile)
|
||||
self._manager:updateItemTable()
|
||||
UIManager:close(self.histfile_dialog)
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
UIManager:show(self.histfile_dialog)
|
||||
return true
|
||||
self.histfile_dialog = ButtonDialog:new{
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Delete"),
|
||||
callback = function()
|
||||
os.remove(history_dir..item.histfile)
|
||||
self._manager:updateItemTable()
|
||||
UIManager:close(self.histfile_dialog)
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
UIManager:show(self.histfile_dialog)
|
||||
return true
|
||||
end
|
||||
|
||||
function FileManagerHistory:onShowHist()
|
||||
local menu_container = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
}
|
||||
local menu_container = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
}
|
||||
|
||||
self.hist_menu = Menu:new{
|
||||
ui = self.ui,
|
||||
width = Screen:getWidth()-50,
|
||||
height = Screen:getHeight()-50,
|
||||
show_parent = menu_container,
|
||||
onMenuHold = self.onMenuHold,
|
||||
_manager = self,
|
||||
}
|
||||
self:updateItemTable()
|
||||
self.hist_menu = Menu:new{
|
||||
ui = self.ui,
|
||||
width = Screen:getWidth()-50,
|
||||
height = Screen:getHeight()-50,
|
||||
show_parent = menu_container,
|
||||
onMenuHold = self.onMenuHold,
|
||||
_manager = self,
|
||||
}
|
||||
self:updateItemTable()
|
||||
|
||||
table.insert(menu_container, self.hist_menu)
|
||||
table.insert(menu_container, self.hist_menu)
|
||||
|
||||
self.hist_menu.close_callback = function()
|
||||
UIManager:close(menu_container)
|
||||
end
|
||||
self.hist_menu.close_callback = function()
|
||||
UIManager:close(menu_container)
|
||||
end
|
||||
|
||||
UIManager:show(menu_container)
|
||||
return true
|
||||
UIManager:show(menu_container)
|
||||
return true
|
||||
end
|
||||
|
||||
function FileManagerHistory:addToMainMenu(tab_item_table)
|
||||
-- insert table to main reader menu
|
||||
table.insert(tab_item_table.main, {
|
||||
text = self.hist_menu_title,
|
||||
callback = function()
|
||||
self:onShowHist()
|
||||
end,
|
||||
})
|
||||
-- insert table to main reader menu
|
||||
table.insert(tab_item_table.main, {
|
||||
text = self.hist_menu_title,
|
||||
callback = function()
|
||||
self:onShowHist()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
function FileManagerHistory:updateItemTable()
|
||||
function readHistDir(re)
|
||||
local sorted_files = {}
|
||||
for f in lfs.dir(history_dir) do
|
||||
local path = history_dir..f
|
||||
if lfs.attributes(path, "mode") == "file" then
|
||||
table.insert(sorted_files, {file = f, date = lfs.attributes(path, "modification")})
|
||||
end
|
||||
end
|
||||
table.sort(sorted_files, function(v1,v2) return v1.date > v2.date end)
|
||||
for _, v in pairs(sorted_files) do
|
||||
table.insert(re, {
|
||||
dir = DocSettings:getPathFromHistory(v.file),
|
||||
name = DocSettings:getNameFromHistory(v.file),
|
||||
histfile = v.file,
|
||||
})
|
||||
end
|
||||
end
|
||||
function readHistDir(re)
|
||||
local sorted_files = {}
|
||||
for f in lfs.dir(history_dir) do
|
||||
local path = history_dir..f
|
||||
if lfs.attributes(path, "mode") == "file" then
|
||||
table.insert(sorted_files, {file = f, date = lfs.attributes(path, "modification")})
|
||||
end
|
||||
end
|
||||
table.sort(sorted_files, function(v1,v2) return v1.date > v2.date end)
|
||||
for _, v in pairs(sorted_files) do
|
||||
table.insert(re, {
|
||||
dir = DocSettings:getPathFromHistory(v.file),
|
||||
name = DocSettings:getNameFromHistory(v.file),
|
||||
histfile = v.file,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
self.hist = {}
|
||||
local last_files = {}
|
||||
readHistDir(last_files)
|
||||
for _,v in pairs(last_files) do
|
||||
table.insert(self.hist, {
|
||||
text = v.name,
|
||||
histfile = v.histfile,
|
||||
callback = function()
|
||||
showReaderUI(v.dir .. "/" .. v.name)
|
||||
end
|
||||
})
|
||||
end
|
||||
self.hist_menu:swithItemTable(self.hist_menu_title, self.hist)
|
||||
self.hist = {}
|
||||
local last_files = {}
|
||||
readHistDir(last_files)
|
||||
for _,v in pairs(last_files) do
|
||||
table.insert(self.hist, {
|
||||
text = v.name,
|
||||
histfile = v.histfile,
|
||||
callback = function()
|
||||
showReaderUI(v.dir .. "/" .. v.name)
|
||||
end
|
||||
})
|
||||
end
|
||||
self.hist_menu:swithItemTable(self.hist_menu_title, self.hist)
|
||||
end
|
||||
|
||||
return FileManagerHistory
|
||||
|
||||
@@ -12,143 +12,143 @@ local Language = require("ui/language")
|
||||
local _ = require("gettext")
|
||||
|
||||
local FileManagerMenu = InputContainer:extend{
|
||||
tab_item_table = nil,
|
||||
registered_widgets = {},
|
||||
tab_item_table = nil,
|
||||
registered_widgets = {},
|
||||
}
|
||||
|
||||
function FileManagerMenu:init()
|
||||
self.tab_item_table = {
|
||||
main = {
|
||||
icon = "resources/icons/appbar.pokeball.png",
|
||||
},
|
||||
home = {
|
||||
icon = "resources/icons/appbar.home.png",
|
||||
callback = function()
|
||||
UIManager:close(self.menu_container)
|
||||
self.ui:onClose()
|
||||
end,
|
||||
},
|
||||
}
|
||||
self.registered_widgets = {}
|
||||
self.tab_item_table = {
|
||||
main = {
|
||||
icon = "resources/icons/appbar.pokeball.png",
|
||||
},
|
||||
home = {
|
||||
icon = "resources/icons/appbar.home.png",
|
||||
callback = function()
|
||||
UIManager:close(self.menu_container)
|
||||
self.ui:onClose()
|
||||
end,
|
||||
},
|
||||
}
|
||||
self.registered_widgets = {}
|
||||
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ShowMenu = { { "Menu" }, doc = _("show menu") },
|
||||
}
|
||||
end
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ShowMenu = { { "Menu" }, doc = _("show menu") },
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function FileManagerMenu:initGesListener()
|
||||
self.ges_events = {
|
||||
TapShowMenu = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = Screen:getWidth()*3/4,
|
||||
h = Screen:getHeight()/4,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
self.ges_events = {
|
||||
TapShowMenu = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = Screen:getWidth()*3/4,
|
||||
h = Screen:getHeight()/4,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
function FileManagerMenu:setUpdateItemTable()
|
||||
for _, widget in pairs(self.registered_widgets) do
|
||||
widget:addToMainMenu(self.tab_item_table)
|
||||
end
|
||||
for _, widget in pairs(self.registered_widgets) do
|
||||
widget:addToMainMenu(self.tab_item_table)
|
||||
end
|
||||
|
||||
table.insert(self.tab_item_table.main, {
|
||||
text = _("Toggle hidden files"),
|
||||
callback = function()
|
||||
self.ui:toggleHiddenFiles()
|
||||
end
|
||||
})
|
||||
table.insert(self.tab_item_table.main, {
|
||||
text = _("Toggle hidden files"),
|
||||
callback = function()
|
||||
self.ui:toggleHiddenFiles()
|
||||
end
|
||||
})
|
||||
|
||||
if Device:hasFrontlight() then
|
||||
ReaderFrontLight:addToMainMenu(self.tab_item_table)
|
||||
end
|
||||
if Device:hasFrontlight() then
|
||||
ReaderFrontLight:addToMainMenu(self.tab_item_table)
|
||||
end
|
||||
|
||||
table.insert(self.tab_item_table.main, {
|
||||
text = _("Help"),
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Please report bugs to https://github.com/koreader/ koreader/issues, Click at the bottom of the page for more options"),
|
||||
})
|
||||
end
|
||||
})
|
||||
table.insert(self.tab_item_table.main, {
|
||||
text = _("Version"),
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = io.open("git-rev", "r"):read(),
|
||||
})
|
||||
end
|
||||
})
|
||||
table.insert(self.tab_item_table.main, Language:getLangMenuTable())
|
||||
table.insert(self.tab_item_table.main, {
|
||||
text = _("Help"),
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Please report bugs to https://github.com/koreader/ koreader/issues, Click at the bottom of the page for more options"),
|
||||
})
|
||||
end
|
||||
})
|
||||
table.insert(self.tab_item_table.main, {
|
||||
text = _("Version"),
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = io.open("git-rev", "r"):read(),
|
||||
})
|
||||
end
|
||||
})
|
||||
table.insert(self.tab_item_table.main, Language:getLangMenuTable())
|
||||
end
|
||||
|
||||
function FileManagerMenu:onShowMenu()
|
||||
if #self.tab_item_table.main == 0 then
|
||||
self:setUpdateItemTable()
|
||||
end
|
||||
if #self.tab_item_table.main == 0 then
|
||||
self:setUpdateItemTable()
|
||||
end
|
||||
|
||||
local menu_container = CenterContainer:new{
|
||||
ignore = "height",
|
||||
dimen = Screen:getSize(),
|
||||
}
|
||||
local menu_container = CenterContainer:new{
|
||||
ignore = "height",
|
||||
dimen = Screen:getSize(),
|
||||
}
|
||||
|
||||
local main_menu = nil
|
||||
if Device:isTouchDevice() then
|
||||
main_menu = TouchMenu:new{
|
||||
width = Screen:getWidth(),
|
||||
tab_item_table = {
|
||||
self.tab_item_table.main,
|
||||
self.tab_item_table.home,
|
||||
},
|
||||
show_parent = menu_container,
|
||||
}
|
||||
else
|
||||
main_menu = Menu:new{
|
||||
title = _("File manager menu"),
|
||||
item_table = {},
|
||||
width = Screen:getWidth() - 100,
|
||||
}
|
||||
local main_menu = nil
|
||||
if Device:isTouchDevice() then
|
||||
main_menu = TouchMenu:new{
|
||||
width = Screen:getWidth(),
|
||||
tab_item_table = {
|
||||
self.tab_item_table.main,
|
||||
self.tab_item_table.home,
|
||||
},
|
||||
show_parent = menu_container,
|
||||
}
|
||||
else
|
||||
main_menu = Menu:new{
|
||||
title = _("File manager menu"),
|
||||
item_table = {},
|
||||
width = Screen:getWidth() - 100,
|
||||
}
|
||||
|
||||
for _,item_table in pairs(self.tab_item_table) do
|
||||
for k,v in ipairs(item_table) do
|
||||
table.insert(main_menu.item_table, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
for _,item_table in pairs(self.tab_item_table) do
|
||||
for k,v in ipairs(item_table) do
|
||||
table.insert(main_menu.item_table, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
main_menu.close_callback = function ()
|
||||
UIManager:close(menu_container)
|
||||
end
|
||||
main_menu.close_callback = function ()
|
||||
UIManager:close(menu_container)
|
||||
end
|
||||
|
||||
menu_container[1] = main_menu
|
||||
-- maintain a reference to menu_container
|
||||
self.menu_container = menu_container
|
||||
UIManager:show(menu_container)
|
||||
menu_container[1] = main_menu
|
||||
-- maintain a reference to menu_container
|
||||
self.menu_container = menu_container
|
||||
UIManager:show(menu_container)
|
||||
|
||||
return true
|
||||
return true
|
||||
end
|
||||
|
||||
function FileManagerMenu:onTapShowMenu()
|
||||
self:onShowMenu()
|
||||
return true
|
||||
self:onShowMenu()
|
||||
return true
|
||||
end
|
||||
|
||||
function FileManagerMenu:onSetDimensions(dimen)
|
||||
-- update listening according to new screen dimen
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
-- update listening according to new screen dimen
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
end
|
||||
|
||||
function FileManagerMenu:registerToMainMenu(widget)
|
||||
table.insert(self.registered_widgets, widget)
|
||||
table.insert(self.registered_widgets, widget)
|
||||
end
|
||||
|
||||
return FileManagerMenu
|
||||
|
||||
@@ -2,98 +2,98 @@
|
||||
A global LRU cache
|
||||
]]--
|
||||
local function calcFreeMem()
|
||||
local meminfo = io.open("/proc/meminfo", "r")
|
||||
local freemem = 0
|
||||
if meminfo then
|
||||
for line in meminfo:lines() do
|
||||
local free, buffer, cached, n
|
||||
free, n = line:gsub("^MemFree:%s-(%d+) kB", "%1")
|
||||
if n ~= 0 then freemem = freemem + tonumber(free)*1024 end
|
||||
buffer, n = line:gsub("^Buffers:%s-(%d+) kB", "%1")
|
||||
if n ~= 0 then freemem = freemem + tonumber(buffer)*1024 end
|
||||
cached, n = line:gsub("^Cached:%s-(%d+) kB", "%1")
|
||||
if n ~= 0 then freemem = freemem + tonumber(cached)*1024 end
|
||||
end
|
||||
meminfo:close()
|
||||
end
|
||||
return freemem
|
||||
local meminfo = io.open("/proc/meminfo", "r")
|
||||
local freemem = 0
|
||||
if meminfo then
|
||||
for line in meminfo:lines() do
|
||||
local free, buffer, cached, n
|
||||
free, n = line:gsub("^MemFree:%s-(%d+) kB", "%1")
|
||||
if n ~= 0 then freemem = freemem + tonumber(free)*1024 end
|
||||
buffer, n = line:gsub("^Buffers:%s-(%d+) kB", "%1")
|
||||
if n ~= 0 then freemem = freemem + tonumber(buffer)*1024 end
|
||||
cached, n = line:gsub("^Cached:%s-(%d+) kB", "%1")
|
||||
if n ~= 0 then freemem = freemem + tonumber(cached)*1024 end
|
||||
end
|
||||
meminfo:close()
|
||||
end
|
||||
return freemem
|
||||
end
|
||||
|
||||
local function calcCacheMemSize()
|
||||
local min = DGLOBAL_CACHE_SIZE_MINIMUM
|
||||
local max = DGLOBAL_CACHE_SIZE_MAXIMUM
|
||||
local calc = calcFreeMem()*(DGLOBAL_CACHE_FREE_PROPORTION or 0)
|
||||
return math.min(max, math.max(min, calc))
|
||||
local min = DGLOBAL_CACHE_SIZE_MINIMUM
|
||||
local max = DGLOBAL_CACHE_SIZE_MAXIMUM
|
||||
local calc = calcFreeMem()*(DGLOBAL_CACHE_FREE_PROPORTION or 0)
|
||||
return math.min(max, math.max(min, calc))
|
||||
end
|
||||
|
||||
local Cache = {
|
||||
-- cache configuration:
|
||||
max_memsize = calcCacheMemSize(),
|
||||
-- cache state:
|
||||
current_memsize = 0,
|
||||
-- associative cache
|
||||
cache = {},
|
||||
-- this will hold the LRU order of the cache
|
||||
cache_order = {}
|
||||
-- cache configuration:
|
||||
max_memsize = calcCacheMemSize(),
|
||||
-- cache state:
|
||||
current_memsize = 0,
|
||||
-- associative cache
|
||||
cache = {},
|
||||
-- this will hold the LRU order of the cache
|
||||
cache_order = {}
|
||||
}
|
||||
|
||||
function Cache:new(o)
|
||||
o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
function Cache:insert(key, object)
|
||||
-- guarantee that we have enough memory in cache
|
||||
if(object.size > self.max_memsize) then
|
||||
-- we're not allowed to claim this much at all
|
||||
error("too much memory claimed")
|
||||
end
|
||||
-- delete objects that least recently used
|
||||
-- (they are at the end of the cache_order array)
|
||||
while self.current_memsize + object.size > self.max_memsize do
|
||||
local removed_key = table.remove(self.cache_order)
|
||||
self.current_memsize = self.current_memsize - self.cache[removed_key].size
|
||||
self.cache[removed_key]:onFree()
|
||||
self.cache[removed_key] = nil
|
||||
end
|
||||
-- insert new object in front of the LRU order
|
||||
table.insert(self.cache_order, 1, key)
|
||||
self.cache[key] = object
|
||||
self.current_memsize = self.current_memsize + object.size
|
||||
-- guarantee that we have enough memory in cache
|
||||
if(object.size > self.max_memsize) then
|
||||
-- we're not allowed to claim this much at all
|
||||
error("too much memory claimed")
|
||||
end
|
||||
-- delete objects that least recently used
|
||||
-- (they are at the end of the cache_order array)
|
||||
while self.current_memsize + object.size > self.max_memsize do
|
||||
local removed_key = table.remove(self.cache_order)
|
||||
self.current_memsize = self.current_memsize - self.cache[removed_key].size
|
||||
self.cache[removed_key]:onFree()
|
||||
self.cache[removed_key] = nil
|
||||
end
|
||||
-- insert new object in front of the LRU order
|
||||
table.insert(self.cache_order, 1, key)
|
||||
self.cache[key] = object
|
||||
self.current_memsize = self.current_memsize + object.size
|
||||
end
|
||||
|
||||
function Cache:check(key)
|
||||
if self.cache[key] then
|
||||
if self.cache_order[1] ~= key then
|
||||
-- put key in front of the LRU list
|
||||
for k, v in ipairs(self.cache_order) do
|
||||
if v == key then
|
||||
table.remove(self.cache_order, k)
|
||||
end
|
||||
end
|
||||
table.insert(self.cache_order, 1, key)
|
||||
end
|
||||
return self.cache[key]
|
||||
end
|
||||
if self.cache[key] then
|
||||
if self.cache_order[1] ~= key then
|
||||
-- put key in front of the LRU list
|
||||
for k, v in ipairs(self.cache_order) do
|
||||
if v == key then
|
||||
table.remove(self.cache_order, k)
|
||||
end
|
||||
end
|
||||
table.insert(self.cache_order, 1, key)
|
||||
end
|
||||
return self.cache[key]
|
||||
end
|
||||
end
|
||||
|
||||
function Cache:willAccept(size)
|
||||
-- we only allow single objects to fill 75% of the cache
|
||||
if size*4 < self.max_memsize*3 then
|
||||
return true
|
||||
end
|
||||
-- we only allow single objects to fill 75% of the cache
|
||||
if size*4 < self.max_memsize*3 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- blank the cache
|
||||
function Cache:clear()
|
||||
for k, _ in pairs(self.cache) do
|
||||
self.cache[k]:onFree()
|
||||
end
|
||||
self.cache = {}
|
||||
self.cache_order = {}
|
||||
self.current_memsize = 0
|
||||
for k, _ in pairs(self.cache) do
|
||||
self.cache[k]:onFree()
|
||||
end
|
||||
self.cache = {}
|
||||
self.cache_order = {}
|
||||
self.current_memsize = 0
|
||||
end
|
||||
|
||||
return Cache
|
||||
|
||||
@@ -3,14 +3,14 @@ Inheritable abstraction for cache items
|
||||
--]]
|
||||
|
||||
local CacheItem = {
|
||||
size = 64, -- some reasonable default for simple Lua values / small tables
|
||||
size = 64, -- some reasonable default for simple Lua values / small tables
|
||||
}
|
||||
|
||||
function CacheItem:new(o)
|
||||
o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
function CacheItem:onFree()
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
local DocSettings = require("docsettings") -- for dump method
|
||||
|
||||
local Dbg = {
|
||||
is_on = false,
|
||||
ev_log = nil,
|
||||
is_on = false,
|
||||
ev_log = nil,
|
||||
}
|
||||
|
||||
local Dbg_mt = {}
|
||||
|
||||
local function LvDEBUG(lv, ...)
|
||||
local line = ""
|
||||
for i,v in ipairs({...}) do
|
||||
if type(v) == "table" then
|
||||
line = line .. " " .. DocSettings:dump(v, lv)
|
||||
else
|
||||
line = line .. " " .. tostring(v)
|
||||
end
|
||||
end
|
||||
print("#"..line)
|
||||
local line = ""
|
||||
for i,v in ipairs({...}) do
|
||||
if type(v) == "table" then
|
||||
line = line .. " " .. DocSettings:dump(v, lv)
|
||||
else
|
||||
line = line .. " " .. tostring(v)
|
||||
end
|
||||
end
|
||||
print("#"..line)
|
||||
end
|
||||
|
||||
function Dbg_mt.__call(dbg, ...)
|
||||
if dbg.is_on then LvDEBUG(math.huge, ...) end
|
||||
if dbg.is_on then LvDEBUG(math.huge, ...) end
|
||||
end
|
||||
|
||||
function Dbg:turnOn()
|
||||
self.is_on = true
|
||||
self.is_on = true
|
||||
|
||||
-- create or clear ev log file
|
||||
os.execute("echo > ev.log")
|
||||
self.ev_log = io.open("ev.log", "w")
|
||||
-- create or clear ev log file
|
||||
os.execute("echo > ev.log")
|
||||
self.ev_log = io.open("ev.log", "w")
|
||||
end
|
||||
|
||||
function Dbg:logEv(ev)
|
||||
local log = ev.type.."|"..ev.code.."|"
|
||||
..ev.value.."|"..ev.time.sec.."|"..ev.time.usec.."\n"
|
||||
self.ev_log:write(log)
|
||||
self.ev_log:flush()
|
||||
local log = ev.type.."|"..ev.code.."|"
|
||||
..ev.value.."|"..ev.time.sec.."|"..ev.time.usec.."\n"
|
||||
self.ev_log:write(log)
|
||||
self.ev_log:flush()
|
||||
end
|
||||
|
||||
function Dbg:traceback()
|
||||
LvDEBUG(math.huge, debug.traceback())
|
||||
LvDEBUG(math.huge, debug.traceback())
|
||||
end
|
||||
|
||||
setmetatable(Dbg, Dbg_mt)
|
||||
|
||||
@@ -2,133 +2,133 @@ local DocSettings = {}
|
||||
-- lfs
|
||||
|
||||
function DocSettings:getHistoryPath(fullpath)
|
||||
local i = #fullpath - 1
|
||||
-- search for last slash
|
||||
while i > 0 do
|
||||
if fullpath:sub(i,i) == "/" then
|
||||
break
|
||||
end
|
||||
i = i - 1
|
||||
end
|
||||
-- construct path to configuration file in history dir
|
||||
local filename = fullpath:sub(i+1, -1)
|
||||
local basename = fullpath:sub(1, i)
|
||||
return "./history/["..basename:gsub("/","#").."] "..filename..".lua"
|
||||
local i = #fullpath - 1
|
||||
-- search for last slash
|
||||
while i > 0 do
|
||||
if fullpath:sub(i,i) == "/" then
|
||||
break
|
||||
end
|
||||
i = i - 1
|
||||
end
|
||||
-- construct path to configuration file in history dir
|
||||
local filename = fullpath:sub(i+1, -1)
|
||||
local basename = fullpath:sub(1, i)
|
||||
return "./history/["..basename:gsub("/","#").."] "..filename..".lua"
|
||||
end
|
||||
|
||||
function DocSettings:getPathFromHistory(hist_name)
|
||||
-- 1. select everything included in brackets
|
||||
local s = string.match(hist_name,"%b[]")
|
||||
-- 2. crop the bracket-sign from both sides
|
||||
-- 3. and finally replace decorative signs '#' to dir-char '/'
|
||||
return string.gsub(string.sub(s,2,-3),"#","/")
|
||||
-- 1. select everything included in brackets
|
||||
local s = string.match(hist_name,"%b[]")
|
||||
-- 2. crop the bracket-sign from both sides
|
||||
-- 3. and finally replace decorative signs '#' to dir-char '/'
|
||||
return string.gsub(string.sub(s,2,-3),"#","/")
|
||||
end
|
||||
|
||||
function DocSettings:getNameFromHistory(hist_name)
|
||||
-- at first, search for path length
|
||||
local s = string.len(string.match(hist_name,"%b[]"))
|
||||
-- and return the rest of string without 4 last characters (".lua")
|
||||
return string.sub(hist_name, s+2, -5)
|
||||
-- at first, search for path length
|
||||
local s = string.len(string.match(hist_name,"%b[]"))
|
||||
-- and return the rest of string without 4 last characters (".lua")
|
||||
return string.sub(hist_name, s+2, -5)
|
||||
end
|
||||
|
||||
function DocSettings:open(docfile)
|
||||
local conf_path = nil
|
||||
if docfile == ".reader" then
|
||||
-- we handle reader setting as special case
|
||||
conf_path = "settings.reader.lua"
|
||||
else
|
||||
if lfs.attributes("./history","mode") ~= "directory" then
|
||||
lfs.mkdir("history")
|
||||
end
|
||||
conf_path = self:getHistoryPath(docfile)
|
||||
end
|
||||
-- construct settings obj
|
||||
local new = { file = conf_path, data = {} }
|
||||
local ok, stored = pcall(dofile, new.file)
|
||||
if not ok then
|
||||
-- try legacy conf path, for backward compatibility. this also
|
||||
-- takes care of reader legacy setting
|
||||
ok, stored = pcall(dofile, docfile..".kpdfview.lua")
|
||||
end
|
||||
if ok then
|
||||
new.data = stored
|
||||
end
|
||||
return setmetatable(new, { __index = DocSettings})
|
||||
local conf_path = nil
|
||||
if docfile == ".reader" then
|
||||
-- we handle reader setting as special case
|
||||
conf_path = "settings.reader.lua"
|
||||
else
|
||||
if lfs.attributes("./history","mode") ~= "directory" then
|
||||
lfs.mkdir("history")
|
||||
end
|
||||
conf_path = self:getHistoryPath(docfile)
|
||||
end
|
||||
-- construct settings obj
|
||||
local new = { file = conf_path, data = {} }
|
||||
local ok, stored = pcall(dofile, new.file)
|
||||
if not ok then
|
||||
-- try legacy conf path, for backward compatibility. this also
|
||||
-- takes care of reader legacy setting
|
||||
ok, stored = pcall(dofile, docfile..".kpdfview.lua")
|
||||
end
|
||||
if ok then
|
||||
new.data = stored
|
||||
end
|
||||
return setmetatable(new, { __index = DocSettings})
|
||||
end
|
||||
|
||||
function DocSettings:readSetting(key)
|
||||
return self.data[key]
|
||||
return self.data[key]
|
||||
end
|
||||
|
||||
function DocSettings:saveSetting(key, value)
|
||||
self.data[key] = value
|
||||
self.data[key] = value
|
||||
end
|
||||
|
||||
function DocSettings:delSetting(key)
|
||||
self.data[key] = nil
|
||||
self.data[key] = nil
|
||||
end
|
||||
|
||||
function DocSettings:dump(data, max_lv)
|
||||
local out = {}
|
||||
self:_serialize(data, out, 0, max_lv)
|
||||
return table.concat(out)
|
||||
local out = {}
|
||||
self:_serialize(data, out, 0, max_lv)
|
||||
return table.concat(out)
|
||||
end
|
||||
|
||||
-- simple serialization function, won't do uservalues, functions, loops
|
||||
function DocSettings:_serialize(what, outt, indent, max_lv)
|
||||
if not max_lv then
|
||||
max_lv = math.huge
|
||||
end
|
||||
if not max_lv then
|
||||
max_lv = math.huge
|
||||
end
|
||||
|
||||
if indent > max_lv then
|
||||
return
|
||||
end
|
||||
if indent > max_lv then
|
||||
return
|
||||
end
|
||||
|
||||
if type(what) == "table" then
|
||||
local didrun = false
|
||||
table.insert(outt, "{")
|
||||
for k, v in pairs(what) do
|
||||
if didrun then
|
||||
table.insert(outt, ",")
|
||||
end
|
||||
table.insert(outt, "\n")
|
||||
table.insert(outt, string.rep("\t", indent+1))
|
||||
table.insert(outt, "[")
|
||||
self:_serialize(k, outt, indent+1, max_lv)
|
||||
table.insert(outt, "] = ")
|
||||
self:_serialize(v, outt, indent+1, max_lv)
|
||||
didrun = true
|
||||
end
|
||||
if didrun then
|
||||
table.insert(outt, "\n")
|
||||
table.insert(outt, string.rep("\t", indent))
|
||||
end
|
||||
table.insert(outt, "}")
|
||||
elseif type(what) == "string" then
|
||||
table.insert(outt, string.format("%q", what))
|
||||
elseif type(what) == "number" or type(what) == "boolean" then
|
||||
table.insert(outt, tostring(what))
|
||||
end
|
||||
if type(what) == "table" then
|
||||
local didrun = false
|
||||
table.insert(outt, "{")
|
||||
for k, v in pairs(what) do
|
||||
if didrun then
|
||||
table.insert(outt, ",")
|
||||
end
|
||||
table.insert(outt, "\n")
|
||||
table.insert(outt, string.rep("\t", indent+1))
|
||||
table.insert(outt, "[")
|
||||
self:_serialize(k, outt, indent+1, max_lv)
|
||||
table.insert(outt, "] = ")
|
||||
self:_serialize(v, outt, indent+1, max_lv)
|
||||
didrun = true
|
||||
end
|
||||
if didrun then
|
||||
table.insert(outt, "\n")
|
||||
table.insert(outt, string.rep("\t", indent))
|
||||
end
|
||||
table.insert(outt, "}")
|
||||
elseif type(what) == "string" then
|
||||
table.insert(outt, string.format("%q", what))
|
||||
elseif type(what) == "number" or type(what) == "boolean" then
|
||||
table.insert(outt, tostring(what))
|
||||
end
|
||||
end
|
||||
|
||||
function DocSettings:flush()
|
||||
-- write a serialized version of the data table
|
||||
if not self.file then
|
||||
return
|
||||
end
|
||||
local f_out = io.open(self.file, "w")
|
||||
if f_out ~= nil then
|
||||
os.setlocale('C', 'numeric')
|
||||
local out = {"-- we can read Lua syntax here!\nreturn "}
|
||||
self:_serialize(self.data, out, 0)
|
||||
table.insert(out, "\n")
|
||||
f_out:write(table.concat(out))
|
||||
f_out:close()
|
||||
end
|
||||
-- write a serialized version of the data table
|
||||
if not self.file then
|
||||
return
|
||||
end
|
||||
local f_out = io.open(self.file, "w")
|
||||
if f_out ~= nil then
|
||||
os.setlocale('C', 'numeric')
|
||||
local out = {"-- we can read Lua syntax here!\nreturn "}
|
||||
self:_serialize(self.data, out, 0)
|
||||
table.insert(out, "\n")
|
||||
f_out:write(table.concat(out))
|
||||
f_out:close()
|
||||
end
|
||||
end
|
||||
|
||||
function DocSettings:close()
|
||||
self:flush()
|
||||
self:flush()
|
||||
end
|
||||
|
||||
return DocSettings
|
||||
|
||||
@@ -10,140 +10,140 @@ local DEBUG = require("dbg")
|
||||
-- TBD: DrawContext
|
||||
|
||||
local CreDocument = Document:new{
|
||||
-- this is defined in kpvcrlib/crengine/crengine/include/lvdocview.h
|
||||
SCROLL_VIEW_MODE = 0,
|
||||
PAGE_VIEW_MODE = 1,
|
||||
-- this is defined in kpvcrlib/crengine/crengine/include/lvdocview.h
|
||||
SCROLL_VIEW_MODE = 0,
|
||||
PAGE_VIEW_MODE = 1,
|
||||
|
||||
_document = false,
|
||||
engine_initilized = false,
|
||||
_document = false,
|
||||
engine_initilized = false,
|
||||
|
||||
line_space_percent = 100,
|
||||
default_font = G_reader_settings:readSetting("cre_font") or "FreeSerif",
|
||||
header_font = G_reader_settings:readSetting("header_font") or "FreeSans",
|
||||
fallback_font = G_reader_settings:readSetting("fallback_font") or "Droid Sans Fallback",
|
||||
default_css = "./data/cr3.css",
|
||||
options = CreOptions,
|
||||
line_space_percent = 100,
|
||||
default_font = G_reader_settings:readSetting("cre_font") or "FreeSerif",
|
||||
header_font = G_reader_settings:readSetting("header_font") or "FreeSans",
|
||||
fallback_font = G_reader_settings:readSetting("fallback_font") or "Droid Sans Fallback",
|
||||
default_css = "./data/cr3.css",
|
||||
options = CreOptions,
|
||||
}
|
||||
|
||||
-- NuPogodi, 20.05.12: inspect the zipfile content
|
||||
function CreDocument.zipContentExt(self, fname)
|
||||
local outfile = "./data/zip_content"
|
||||
local s = ""
|
||||
os.execute("unzip ".."-l \""..fname.."\" > "..outfile)
|
||||
local i = 1
|
||||
if io.open(outfile,"r") then
|
||||
for lines in io.lines(outfile) do
|
||||
if i == 4 then s = lines break else i = i + 1 end
|
||||
end
|
||||
end
|
||||
-- return the extention
|
||||
return string.lower(string.match(s, ".+%.([^.]+)"))
|
||||
local outfile = "./data/zip_content"
|
||||
local s = ""
|
||||
os.execute("unzip ".."-l \""..fname.."\" > "..outfile)
|
||||
local i = 1
|
||||
if io.open(outfile,"r") then
|
||||
for lines in io.lines(outfile) do
|
||||
if i == 4 then s = lines break else i = i + 1 end
|
||||
end
|
||||
end
|
||||
-- return the extention
|
||||
return string.lower(string.match(s, ".+%.([^.]+)"))
|
||||
end
|
||||
|
||||
function CreDocument:engineInit()
|
||||
if not engine_initilized then
|
||||
-- initialize cache
|
||||
cre.initCache(1024*1024*64)
|
||||
if not engine_initilized then
|
||||
-- initialize cache
|
||||
cre.initCache(1024*1024*64)
|
||||
|
||||
-- we need to initialize the CRE font list
|
||||
local fonts = Font:getFontList()
|
||||
for _k, _v in ipairs(fonts) do
|
||||
if _v ~= "Dingbats.cff" and _v ~= "StandardSymL.cff" then
|
||||
local ok, err = pcall(cre.registerFont, Font.fontdir..'/'.._v)
|
||||
if not ok then
|
||||
DEBUG(err)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- we need to initialize the CRE font list
|
||||
local fonts = Font:getFontList()
|
||||
for _k, _v in ipairs(fonts) do
|
||||
if _v ~= "Dingbats.cff" and _v ~= "StandardSymL.cff" then
|
||||
local ok, err = pcall(cre.registerFont, Font.fontdir..'/'.._v)
|
||||
if not ok then
|
||||
DEBUG(err)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
engine_initilized = true
|
||||
end
|
||||
engine_initilized = true
|
||||
end
|
||||
end
|
||||
|
||||
function CreDocument:init()
|
||||
require "libs/libkoreader-cre"
|
||||
self:engineInit()
|
||||
self.configurable:loadDefaults(self.options)
|
||||
require "libs/libkoreader-cre"
|
||||
self:engineInit()
|
||||
self.configurable:loadDefaults(self.options)
|
||||
|
||||
local ok
|
||||
local file_type = string.lower(string.match(self.file, ".+%.([^.]+)"))
|
||||
if file_type == "zip" then
|
||||
-- NuPogodi, 20.05.12: read the content of zip-file
|
||||
-- and return extention of the 1st file
|
||||
file_type = self:zipContentExt(self.file)
|
||||
end
|
||||
-- these two format use the same css file
|
||||
if file_type == "html" then
|
||||
file_type = "htm"
|
||||
end
|
||||
-- if native css-file doesn't exist, one needs to use default cr3.css
|
||||
if not io.open("./data/"..file_type..".css") then
|
||||
file_type = "cr3"
|
||||
end
|
||||
self.default_css = "./data/"..file_type..".css"
|
||||
local ok
|
||||
local file_type = string.lower(string.match(self.file, ".+%.([^.]+)"))
|
||||
if file_type == "zip" then
|
||||
-- NuPogodi, 20.05.12: read the content of zip-file
|
||||
-- and return extention of the 1st file
|
||||
file_type = self:zipContentExt(self.file)
|
||||
end
|
||||
-- these two format use the same css file
|
||||
if file_type == "html" then
|
||||
file_type = "htm"
|
||||
end
|
||||
-- if native css-file doesn't exist, one needs to use default cr3.css
|
||||
if not io.open("./data/"..file_type..".css") then
|
||||
file_type = "cr3"
|
||||
end
|
||||
self.default_css = "./data/"..file_type..".css"
|
||||
|
||||
-- @TODO check the default view_mode to a global user configurable
|
||||
-- variable 22.12 2012 (houqp)
|
||||
ok, self._document = pcall(cre.newDocView,
|
||||
Screen:getWidth(), Screen:getHeight(), self.PAGE_VIEW_MODE
|
||||
)
|
||||
if not ok then
|
||||
self.error_message = self.doc -- will contain error message
|
||||
return
|
||||
end
|
||||
|
||||
-- adjust font sizes according to screen dpi
|
||||
self._document:adjustFontSizes(Screen:getDPI())
|
||||
|
||||
-- set fallback font face
|
||||
self._document:setStringProperty("crengine.font.fallback.face", self.fallback_font)
|
||||
|
||||
self.is_open = true
|
||||
self.info.has_pages = false
|
||||
self:_readMetadata()
|
||||
self.info.configurable = true
|
||||
-- @TODO check the default view_mode to a global user configurable
|
||||
-- variable 22.12 2012 (houqp)
|
||||
ok, self._document = pcall(cre.newDocView,
|
||||
Screen:getWidth(), Screen:getHeight(), self.PAGE_VIEW_MODE
|
||||
)
|
||||
if not ok then
|
||||
self.error_message = self.doc -- will contain error message
|
||||
return
|
||||
end
|
||||
|
||||
-- adjust font sizes according to screen dpi
|
||||
self._document:adjustFontSizes(Screen:getDPI())
|
||||
|
||||
-- set fallback font face
|
||||
self._document:setStringProperty("crengine.font.fallback.face", self.fallback_font)
|
||||
|
||||
self.is_open = true
|
||||
self.info.has_pages = false
|
||||
self:_readMetadata()
|
||||
self.info.configurable = true
|
||||
end
|
||||
|
||||
function CreDocument:loadDocument()
|
||||
self._document:loadDocument(self.file)
|
||||
if not self.info.has_pages then
|
||||
self.info.doc_height = self._document:getFullHeight()
|
||||
end
|
||||
if Device:getModel() ~= "KindleDXG" then
|
||||
self:setVisiblePageCount(1)
|
||||
end
|
||||
self._document:loadDocument(self.file)
|
||||
if not self.info.has_pages then
|
||||
self.info.doc_height = self._document:getFullHeight()
|
||||
end
|
||||
if Device:getModel() ~= "KindleDXG" then
|
||||
self:setVisiblePageCount(1)
|
||||
end
|
||||
end
|
||||
|
||||
function CreDocument:close()
|
||||
self._document:saveDefaults()
|
||||
Document.close(self)
|
||||
self._document:saveDefaults()
|
||||
Document.close(self)
|
||||
end
|
||||
|
||||
function CreDocument:getPageCount()
|
||||
return self._document:getPages()
|
||||
return self._document:getPages()
|
||||
end
|
||||
|
||||
function CreDocument:getWordFromPosition(pos)
|
||||
local word_box = self._document:getWordFromPosition(pos.x, pos.y)
|
||||
local text_range = self._document:getTextFromPositions(pos.x, pos.y, pos.x, pos.y)
|
||||
if word_box.word then
|
||||
return {
|
||||
word = text_range.text == "" and word_box.word or text_range.text,
|
||||
page = self._document:getCurrentPage(),
|
||||
sbox = Geom:new{
|
||||
x = word_box.x0, y = word_box.y0,
|
||||
w = word_box.x1 - word_box.x0,
|
||||
h = word_box.y1 - word_box.y0,
|
||||
}
|
||||
}
|
||||
end
|
||||
local word_box = self._document:getWordFromPosition(pos.x, pos.y)
|
||||
local text_range = self._document:getTextFromPositions(pos.x, pos.y, pos.x, pos.y)
|
||||
if word_box.word then
|
||||
return {
|
||||
word = text_range.text == "" and word_box.word or text_range.text,
|
||||
page = self._document:getCurrentPage(),
|
||||
sbox = Geom:new{
|
||||
x = word_box.x0, y = word_box.y0,
|
||||
w = word_box.x1 - word_box.x0,
|
||||
h = word_box.y1 - word_box.y0,
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function CreDocument:getTextFromPositions(pos0, pos1)
|
||||
local text_range = self._document:getTextFromPositions(pos0.x, pos0.y, pos1.x, pos1.y)
|
||||
DEBUG("CreDocument: get text range", text_range)
|
||||
local line_boxes = self:getScreenBoxesFromPositions(text_range.pos0, text_range.pos1)
|
||||
return {
|
||||
local text_range = self._document:getTextFromPositions(pos0.x, pos0.y, pos1.x, pos1.y)
|
||||
DEBUG("CreDocument: get text range", text_range)
|
||||
local line_boxes = self:getScreenBoxesFromPositions(text_range.pos0, text_range.pos1)
|
||||
return {
|
||||
text = text_range.text,
|
||||
pos0 = text_range.pos0,
|
||||
pos1 = text_range.pos1,
|
||||
@@ -152,38 +152,38 @@ function CreDocument:getTextFromPositions(pos0, pos1)
|
||||
end
|
||||
|
||||
function CreDocument:getScreenBoxesFromPositions(pos0, pos1)
|
||||
local line_boxes = {}
|
||||
if pos0 and pos1 then
|
||||
local word_boxes = self._document:getWordBoxesFromPositions(pos0, pos1)
|
||||
--DEBUG("word boxes", word_boxes)
|
||||
for i = 1, #word_boxes do
|
||||
local line_box = word_boxes[i]
|
||||
table.insert(line_boxes, Geom:new{
|
||||
x = line_box.x0, y = line_box.y0,
|
||||
w = line_box.x1 - line_box.x0,
|
||||
h = line_box.y1 - line_box.y0,
|
||||
})
|
||||
end
|
||||
--DEBUG("line boxes", line_boxes)
|
||||
end
|
||||
return line_boxes
|
||||
local line_boxes = {}
|
||||
if pos0 and pos1 then
|
||||
local word_boxes = self._document:getWordBoxesFromPositions(pos0, pos1)
|
||||
--DEBUG("word boxes", word_boxes)
|
||||
for i = 1, #word_boxes do
|
||||
local line_box = word_boxes[i]
|
||||
table.insert(line_boxes, Geom:new{
|
||||
x = line_box.x0, y = line_box.y0,
|
||||
w = line_box.x1 - line_box.x0,
|
||||
h = line_box.y1 - line_box.y0,
|
||||
})
|
||||
end
|
||||
--DEBUG("line boxes", line_boxes)
|
||||
end
|
||||
return line_boxes
|
||||
end
|
||||
|
||||
function CreDocument:drawCurrentView(target, x, y, rect, pos)
|
||||
tile_bb = Blitbuffer.new(rect.w, rect.h)
|
||||
self._document:drawCurrentPage(tile_bb)
|
||||
target:blitFrom(tile_bb, x, y, 0, 0, rect.w, rect.h)
|
||||
tile_bb:free()
|
||||
tile_bb = Blitbuffer.new(rect.w, rect.h)
|
||||
self._document:drawCurrentPage(tile_bb)
|
||||
target:blitFrom(tile_bb, x, y, 0, 0, rect.w, rect.h)
|
||||
tile_bb:free()
|
||||
end
|
||||
|
||||
function CreDocument:drawCurrentViewByPos(target, x, y, rect, pos)
|
||||
self._document:gotoPos(pos)
|
||||
self:drawCurrentView(target, x, y, rect)
|
||||
self._document:gotoPos(pos)
|
||||
self:drawCurrentView(target, x, y, rect)
|
||||
end
|
||||
|
||||
function CreDocument:drawCurrentViewByPage(target, x, y, rect, page)
|
||||
self._document:gotoPage(page)
|
||||
self:drawCurrentView(target, x, y, rect)
|
||||
self._document:gotoPage(page)
|
||||
self:drawCurrentView(target, x, y, rect)
|
||||
end
|
||||
|
||||
function CreDocument:hintPage(pageno, zoom, rotation)
|
||||
@@ -196,182 +196,182 @@ function CreDocument:renderPage(pageno, rect, zoom, rotation)
|
||||
end
|
||||
|
||||
function CreDocument:gotoXPointer(xpointer)
|
||||
DEBUG("CreDocument: goto xpointer", xpointer)
|
||||
self._document:gotoXPointer(xpointer)
|
||||
DEBUG("CreDocument: goto xpointer", xpointer)
|
||||
self._document:gotoXPointer(xpointer)
|
||||
end
|
||||
|
||||
function CreDocument:getXPointer()
|
||||
return self._document:getXPointer()
|
||||
return self._document:getXPointer()
|
||||
end
|
||||
|
||||
function CreDocument:getPosFromXPointer(xp)
|
||||
return self._document:getPosFromXPointer(xp)
|
||||
return self._document:getPosFromXPointer(xp)
|
||||
end
|
||||
|
||||
function CreDocument:getPageFromXPointer(xp)
|
||||
return self._document:getPageFromXPointer(xp)
|
||||
return self._document:getPageFromXPointer(xp)
|
||||
end
|
||||
|
||||
function CreDocument:getFontFace()
|
||||
return self._document:getFontFace()
|
||||
return self._document:getFontFace()
|
||||
end
|
||||
|
||||
function CreDocument:getCurrentPos()
|
||||
return self._document:getCurrentPos()
|
||||
return self._document:getCurrentPos()
|
||||
end
|
||||
|
||||
function CreDocument:getPageLinks()
|
||||
return self._document:getPageLinks()
|
||||
return self._document:getPageLinks()
|
||||
end
|
||||
|
||||
function CreDocument:getLinkFromPosition(pos)
|
||||
return self._document:getLinkFromPosition(pos.x, pos.y)
|
||||
return self._document:getLinkFromPosition(pos.x, pos.y)
|
||||
end
|
||||
|
||||
function Document:gotoPos(pos)
|
||||
DEBUG("CreDocument: goto position", pos)
|
||||
self._document:gotoPos(pos)
|
||||
DEBUG("CreDocument: goto position", pos)
|
||||
self._document:gotoPos(pos)
|
||||
end
|
||||
|
||||
function CreDocument:gotoPage(page)
|
||||
DEBUG("CreDocument: goto page", page)
|
||||
self._document:gotoPage(page)
|
||||
DEBUG("CreDocument: goto page", page)
|
||||
self._document:gotoPage(page)
|
||||
end
|
||||
|
||||
function CreDocument:gotoLink(link)
|
||||
DEBUG("CreDocument: goto link", link)
|
||||
self._document:gotoLink(link)
|
||||
DEBUG("CreDocument: goto link", link)
|
||||
self._document:gotoLink(link)
|
||||
end
|
||||
|
||||
function CreDocument:goBack()
|
||||
DEBUG("CreDocument: go back")
|
||||
self._document:goBack()
|
||||
DEBUG("CreDocument: go back")
|
||||
self._document:goBack()
|
||||
end
|
||||
|
||||
function CreDocument:goForward(link)
|
||||
DEBUG("CreDocument: go forward")
|
||||
self._document:goForward()
|
||||
DEBUG("CreDocument: go forward")
|
||||
self._document:goForward()
|
||||
end
|
||||
|
||||
function CreDocument:getCurrentPage()
|
||||
return self._document:getCurrentPage()
|
||||
return self._document:getCurrentPage()
|
||||
end
|
||||
|
||||
function CreDocument:setFontFace(new_font_face)
|
||||
if new_font_face then
|
||||
DEBUG("CreDocument: set font face", new_font_face)
|
||||
self._document:setFontFace(new_font_face)
|
||||
end
|
||||
if new_font_face then
|
||||
DEBUG("CreDocument: set font face", new_font_face)
|
||||
self._document:setFontFace(new_font_face)
|
||||
end
|
||||
end
|
||||
|
||||
function CreDocument:clearSelection()
|
||||
self._document:clearSelection()
|
||||
self._document:clearSelection()
|
||||
end
|
||||
|
||||
function CreDocument:getFontSize()
|
||||
return self._document:getFontSize()
|
||||
return self._document:getFontSize()
|
||||
end
|
||||
|
||||
function CreDocument:setFontSize(new_font_size)
|
||||
if new_font_size then
|
||||
DEBUG("CreDocument: set font size", new_font_size)
|
||||
self._document:setFontSize(new_font_size)
|
||||
end
|
||||
if new_font_size then
|
||||
DEBUG("CreDocument: set font size", new_font_size)
|
||||
self._document:setFontSize(new_font_size)
|
||||
end
|
||||
end
|
||||
|
||||
function CreDocument:setViewMode(new_mode)
|
||||
if new_mode then
|
||||
DEBUG("CreDocument: set view mode", new_mode)
|
||||
if new_mode == "scroll" then
|
||||
self._document:setViewMode(self.SCROLL_VIEW_MODE)
|
||||
else
|
||||
self._document:setViewMode(self.PAGE_VIEW_MODE)
|
||||
end
|
||||
end
|
||||
if new_mode then
|
||||
DEBUG("CreDocument: set view mode", new_mode)
|
||||
if new_mode == "scroll" then
|
||||
self._document:setViewMode(self.SCROLL_VIEW_MODE)
|
||||
else
|
||||
self._document:setViewMode(self.PAGE_VIEW_MODE)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CreDocument:setHeaderFont(new_font)
|
||||
if new_font then
|
||||
DEBUG("CreDocument: set header font", new_font)
|
||||
self._document:setHeaderFont(new_font)
|
||||
end
|
||||
if new_font then
|
||||
DEBUG("CreDocument: set header font", new_font)
|
||||
self._document:setHeaderFont(new_font)
|
||||
end
|
||||
end
|
||||
|
||||
function CreDocument:zoomFont(delta)
|
||||
DEBUG("CreDocument: zoom font", delta)
|
||||
self._document:zoomFont(delta)
|
||||
DEBUG("CreDocument: zoom font", delta)
|
||||
self._document:zoomFont(delta)
|
||||
end
|
||||
|
||||
function CreDocument:setInterlineSpacePercent(percent)
|
||||
DEBUG("CreDocument: set interline space", percent)
|
||||
self._document:setDefaultInterlineSpace(percent)
|
||||
DEBUG("CreDocument: set interline space", percent)
|
||||
self._document:setDefaultInterlineSpace(percent)
|
||||
end
|
||||
|
||||
function CreDocument:toggleFontBolder()
|
||||
DEBUG("CreDocument: toggle font bolder")
|
||||
self._document:toggleFontBolder()
|
||||
DEBUG("CreDocument: toggle font bolder")
|
||||
self._document:toggleFontBolder()
|
||||
end
|
||||
|
||||
function CreDocument:setGammaIndex(index)
|
||||
DEBUG("CreDocument: set gamma index", index)
|
||||
cre.setGammaIndex(index)
|
||||
DEBUG("CreDocument: set gamma index", index)
|
||||
cre.setGammaIndex(index)
|
||||
end
|
||||
|
||||
function CreDocument:setStyleSheet(new_css)
|
||||
DEBUG("CreDocument: set style sheet", new_css)
|
||||
self._document:setStyleSheet(new_css)
|
||||
DEBUG("CreDocument: set style sheet", new_css)
|
||||
self._document:setStyleSheet(new_css)
|
||||
end
|
||||
|
||||
function CreDocument:setEmbeddedStyleSheet(toggle)
|
||||
DEBUG("CreDocument: set embedded style sheet", toggle)
|
||||
self._document:setEmbeddedStyleSheet(toggle)
|
||||
DEBUG("CreDocument: set embedded style sheet", toggle)
|
||||
self._document:setEmbeddedStyleSheet(toggle)
|
||||
end
|
||||
|
||||
function CreDocument:setPageMargins(left, top, right, bottom)
|
||||
DEBUG("CreDocument: set page margins", left, top, right, bottom)
|
||||
self._document:setPageMargins(left, top, right, bottom)
|
||||
DEBUG("CreDocument: set page margins", left, top, right, bottom)
|
||||
self._document:setPageMargins(left, top, right, bottom)
|
||||
end
|
||||
|
||||
function CreDocument:setFloatingPunctuation(enabled)
|
||||
DEBUG("CreDocument: set floating punctuation", enabled)
|
||||
self._document:setIntProperty("crengine.style.floating.punctuation.enabled", enabled)
|
||||
DEBUG("CreDocument: set floating punctuation", enabled)
|
||||
self._document:setIntProperty("crengine.style.floating.punctuation.enabled", enabled)
|
||||
end
|
||||
|
||||
function CreDocument:setVisiblePageCount(new_count)
|
||||
DEBUG("CreDocument: set visible page count", new_count)
|
||||
self._document:setVisiblePageCount(new_count)
|
||||
DEBUG("CreDocument: set visible page count", new_count)
|
||||
self._document:setVisiblePageCount(new_count)
|
||||
end
|
||||
|
||||
function CreDocument:setBatteryState(state)
|
||||
DEBUG("CreDocument: set battery state", state)
|
||||
self._document:setBatteryState(state)
|
||||
DEBUG("CreDocument: set battery state", state)
|
||||
self._document:setBatteryState(state)
|
||||
end
|
||||
|
||||
function CreDocument:isXPointerInCurrentPage(xp)
|
||||
DEBUG("CreDocument: check in page", xp)
|
||||
return self._document:isXPointerInCurrentPage(xp)
|
||||
DEBUG("CreDocument: check in page", xp)
|
||||
return self._document:isXPointerInCurrentPage(xp)
|
||||
end
|
||||
|
||||
function CreDocument:setStatusLineProp(prop)
|
||||
DEBUG("CreDocument: set status line property", prop)
|
||||
self._document:setStringProperty("window.status.line", prop)
|
||||
DEBUG("CreDocument: set status line property", prop)
|
||||
self._document:setStringProperty("window.status.line", prop)
|
||||
end
|
||||
|
||||
function CreDocument:register(registry)
|
||||
registry:addProvider("txt", "application/txt", self)
|
||||
registry:addProvider("epub", "application/epub", self)
|
||||
registry:addProvider("fb2", "application/fb2", self)
|
||||
registry:addProvider("html", "application/html", self)
|
||||
registry:addProvider("htm", "application/htm", self)
|
||||
registry:addProvider("zip", "application/zip", self)
|
||||
registry:addProvider("rtf", "application/rtf", self)
|
||||
registry:addProvider("mobi", "application/mobi", self)
|
||||
registry:addProvider("prc", "application/prc", self)
|
||||
registry:addProvider("azw", "application/azw", self)
|
||||
registry:addProvider("chm", "application/chm", self)
|
||||
registry:addProvider("pdb", "application/pdb", self)
|
||||
registry:addProvider("doc", "application/doc", self)
|
||||
registry:addProvider("tcr", "application/tcr", self)
|
||||
registry:addProvider("txt", "application/txt", self)
|
||||
registry:addProvider("epub", "application/epub", self)
|
||||
registry:addProvider("fb2", "application/fb2", self)
|
||||
registry:addProvider("html", "application/html", self)
|
||||
registry:addProvider("htm", "application/htm", self)
|
||||
registry:addProvider("zip", "application/zip", self)
|
||||
registry:addProvider("rtf", "application/rtf", self)
|
||||
registry:addProvider("mobi", "application/mobi", self)
|
||||
registry:addProvider("prc", "application/prc", self)
|
||||
registry:addProvider("azw", "application/azw", self)
|
||||
registry:addProvider("chm", "application/chm", self)
|
||||
registry:addProvider("pdb", "application/pdb", self)
|
||||
registry:addProvider("doc", "application/doc", self)
|
||||
registry:addProvider("tcr", "application/tcr", self)
|
||||
end
|
||||
|
||||
return CreDocument
|
||||
|
||||
@@ -7,113 +7,113 @@ local Configurable = require("ui/reader/configurable")
|
||||
local DrawContext = require("ffi/drawcontext")
|
||||
|
||||
local DjvuDocument = Document:new{
|
||||
_document = false,
|
||||
-- libdjvulibre manages its own additional cache, default value is hard written in c module.
|
||||
djvulibre_cache_size = nil,
|
||||
dc_null = DrawContext.new(),
|
||||
options = KoptOptions,
|
||||
koptinterface = nil,
|
||||
_document = false,
|
||||
-- libdjvulibre manages its own additional cache, default value is hard written in c module.
|
||||
djvulibre_cache_size = nil,
|
||||
dc_null = DrawContext.new(),
|
||||
options = KoptOptions,
|
||||
koptinterface = nil,
|
||||
}
|
||||
|
||||
-- check DjVu magic string to validate
|
||||
local function validDjvuFile(filename)
|
||||
f = io.open(filename, "r")
|
||||
if not f then return false end
|
||||
local magic = f:read(8)
|
||||
f:close()
|
||||
if not magic or magic ~= "AT&TFORM" then return false end
|
||||
return true
|
||||
f = io.open(filename, "r")
|
||||
if not f then return false end
|
||||
local magic = f:read(8)
|
||||
f:close()
|
||||
if not magic or magic ~= "AT&TFORM" then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
function DjvuDocument:init()
|
||||
local djvu = require("libs/libkoreader-djvu")
|
||||
self.koptinterface = require("document/koptinterface")
|
||||
self.configurable:loadDefaults(self.options)
|
||||
if not validDjvuFile(self.file) then
|
||||
self.error_message = "Not a valid DjVu file"
|
||||
return
|
||||
end
|
||||
local djvu = require("libs/libkoreader-djvu")
|
||||
self.koptinterface = require("document/koptinterface")
|
||||
self.configurable:loadDefaults(self.options)
|
||||
if not validDjvuFile(self.file) then
|
||||
self.error_message = "Not a valid DjVu file"
|
||||
return
|
||||
end
|
||||
|
||||
local ok
|
||||
ok, self._document = pcall(djvu.openDocument, self.file, self.djvulibre_cache_size)
|
||||
if not ok then
|
||||
self.error_message = self.doc -- will contain error message
|
||||
return
|
||||
end
|
||||
self.is_open = true
|
||||
self.info.has_pages = true
|
||||
self.info.configurable = true
|
||||
self:_readMetadata()
|
||||
local ok
|
||||
ok, self._document = pcall(djvu.openDocument, self.file, self.djvulibre_cache_size)
|
||||
if not ok then
|
||||
self.error_message = self.doc -- will contain error message
|
||||
return
|
||||
end
|
||||
self.is_open = true
|
||||
self.info.has_pages = true
|
||||
self.info.configurable = true
|
||||
self:_readMetadata()
|
||||
end
|
||||
|
||||
function DjvuDocument:invertTextYAxel(pageno, text_table)
|
||||
local _, height = self.doc:getOriginalPageSize(pageno)
|
||||
for _,text in pairs(text_table) do
|
||||
for _,line in ipairs(text) do
|
||||
line.y0, line.y1 = (height - line.y1), (height - line.y0)
|
||||
end
|
||||
end
|
||||
return text_table
|
||||
local _, height = self.doc:getOriginalPageSize(pageno)
|
||||
for _,text in pairs(text_table) do
|
||||
for _,line in ipairs(text) do
|
||||
line.y0, line.y1 = (height - line.y1), (height - line.y0)
|
||||
end
|
||||
end
|
||||
return text_table
|
||||
end
|
||||
|
||||
function DjvuDocument:getPageTextBoxes(pageno)
|
||||
return self._document:getPageText(pageno)
|
||||
return self._document:getPageText(pageno)
|
||||
end
|
||||
|
||||
function DjvuDocument:getWordFromPosition(spos)
|
||||
return self.koptinterface:getWordFromPosition(self, spos)
|
||||
return self.koptinterface:getWordFromPosition(self, spos)
|
||||
end
|
||||
|
||||
function DjvuDocument:getTextFromPositions(spos0, spos1)
|
||||
return self.koptinterface:getTextFromPositions(self, spos0, spos1)
|
||||
return self.koptinterface:getTextFromPositions(self, spos0, spos1)
|
||||
end
|
||||
|
||||
function DjvuDocument:getPageBoxesFromPositions(pageno, ppos0, ppos1)
|
||||
return self.koptinterface:getPageBoxesFromPositions(self, pageno, ppos0, ppos1)
|
||||
return self.koptinterface:getPageBoxesFromPositions(self, pageno, ppos0, ppos1)
|
||||
end
|
||||
|
||||
function DjvuDocument:getOCRWord(pageno, wbox)
|
||||
return self.koptinterface:getOCRWord(self, pageno, wbox)
|
||||
return self.koptinterface:getOCRWord(self, pageno, wbox)
|
||||
end
|
||||
|
||||
function DjvuDocument:getOCRText(pageno, tboxes)
|
||||
return self.koptinterface:getOCRText(self, pageno, tboxes)
|
||||
return self.koptinterface:getOCRText(self, pageno, tboxes)
|
||||
end
|
||||
|
||||
function DjvuDocument:getPageRegions(pageno)
|
||||
return self.koptinterface:getPageRegions(self, pageno)
|
||||
return self.koptinterface:getPageRegions(self, pageno)
|
||||
end
|
||||
|
||||
function DjvuDocument:getUsedBBox(pageno)
|
||||
-- djvu does not support usedbbox, so fake it.
|
||||
local used = {}
|
||||
local native_dim = self:getNativePageDimensions(pageno)
|
||||
used.x0, used.y0, used.x1, used.y1 = 0, 0, native_dim.w, native_dim.h
|
||||
return used
|
||||
-- djvu does not support usedbbox, so fake it.
|
||||
local used = {}
|
||||
local native_dim = self:getNativePageDimensions(pageno)
|
||||
used.x0, used.y0, used.x1, used.y1 = 0, 0, native_dim.w, native_dim.h
|
||||
return used
|
||||
end
|
||||
|
||||
function DjvuDocument:getPageBBox(pageno)
|
||||
return self.koptinterface:getPageBBox(self, pageno)
|
||||
return self.koptinterface:getPageBBox(self, pageno)
|
||||
end
|
||||
|
||||
function DjvuDocument:getPageDimensions(pageno, zoom, rotation)
|
||||
return self.koptinterface:getPageDimensions(self, pageno, zoom, rotation)
|
||||
return self.koptinterface:getPageDimensions(self, pageno, zoom, rotation)
|
||||
end
|
||||
|
||||
function DjvuDocument:renderPage(pageno, rect, zoom, rotation, gamma, render_mode)
|
||||
return self.koptinterface:renderPage(self, pageno, rect, zoom, rotation, gamma, render_mode)
|
||||
return self.koptinterface:renderPage(self, pageno, rect, zoom, rotation, gamma, render_mode)
|
||||
end
|
||||
|
||||
function DjvuDocument:hintPage(pageno, zoom, rotation, gamma, render_mode)
|
||||
return self.koptinterface:hintPage(self, pageno, zoom, rotation, gamma, render_mode)
|
||||
return self.koptinterface:hintPage(self, pageno, zoom, rotation, gamma, render_mode)
|
||||
end
|
||||
|
||||
function DjvuDocument:drawPage(target, x, y, rect, pageno, zoom, rotation, gamma, render_mode)
|
||||
return self.koptinterface:drawPage(self, target, x, y, rect, pageno, zoom, rotation, gamma, render_mode)
|
||||
return self.koptinterface:drawPage(self, target, x, y, rect, pageno, zoom, rotation, gamma, render_mode)
|
||||
end
|
||||
|
||||
function DjvuDocument:register(registry)
|
||||
registry:addProvider("djvu", "application/djvu", self)
|
||||
registry:addProvider("djvu", "application/djvu", self)
|
||||
end
|
||||
|
||||
return DjvuDocument
|
||||
|
||||
@@ -11,55 +11,55 @@ local DEBUG = require("dbg")
|
||||
This is an abstract interface to a document
|
||||
]]--
|
||||
local Document = {
|
||||
-- file name
|
||||
file = nil,
|
||||
-- file name
|
||||
file = nil,
|
||||
|
||||
info = {
|
||||
-- whether the document is pageable
|
||||
has_pages = false,
|
||||
-- whether words can be provided
|
||||
has_words = false,
|
||||
-- whether hyperlinks can be provided
|
||||
has_hyperlinks = false,
|
||||
-- whether (native to format) annotations can be provided
|
||||
has_annotations = false,
|
||||
info = {
|
||||
-- whether the document is pageable
|
||||
has_pages = false,
|
||||
-- whether words can be provided
|
||||
has_words = false,
|
||||
-- whether hyperlinks can be provided
|
||||
has_hyperlinks = false,
|
||||
-- whether (native to format) annotations can be provided
|
||||
has_annotations = false,
|
||||
|
||||
-- whether pages can be rotated
|
||||
is_rotatable = false,
|
||||
-- whether pages can be rotated
|
||||
is_rotatable = false,
|
||||
|
||||
number_of_pages = 0,
|
||||
-- if not pageable, length of the document in pixels
|
||||
doc_height = 0,
|
||||
number_of_pages = 0,
|
||||
-- if not pageable, length of the document in pixels
|
||||
doc_height = 0,
|
||||
|
||||
-- other metadata
|
||||
title = "",
|
||||
author = "",
|
||||
date = ""
|
||||
},
|
||||
|
||||
links = {},
|
||||
-- other metadata
|
||||
title = "",
|
||||
author = "",
|
||||
date = ""
|
||||
},
|
||||
|
||||
links = {},
|
||||
|
||||
GAMMA_NO_GAMMA = 1.0,
|
||||
GAMMA_NO_GAMMA = 1.0,
|
||||
|
||||
-- override bbox from orignal page's getUsedBBox
|
||||
bbox = {},
|
||||
-- override bbox from orignal page's getUsedBBox
|
||||
bbox = {},
|
||||
|
||||
-- flag to show whether the document was opened successfully
|
||||
is_open = false,
|
||||
error_message = nil,
|
||||
-- flag to show whether the document was opened successfully
|
||||
is_open = false,
|
||||
error_message = nil,
|
||||
|
||||
-- flag to show that the document needs to be unlocked by a password
|
||||
is_locked = false,
|
||||
-- flag to show that the document needs to be unlocked by a password
|
||||
is_locked = false,
|
||||
|
||||
configurable = Configurable,
|
||||
configurable = Configurable,
|
||||
}
|
||||
|
||||
function Document:new(o)
|
||||
local o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
if o.init then o:init() end
|
||||
return o
|
||||
local o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
if o.init then o:init() end
|
||||
return o
|
||||
end
|
||||
|
||||
-- override this method to open a document
|
||||
@@ -68,195 +68,195 @@ end
|
||||
|
||||
-- this might be overridden by a document implementation
|
||||
function Document:unlock(password)
|
||||
-- return true instead when the password provided unlocked the document
|
||||
return false
|
||||
-- return true instead when the password provided unlocked the document
|
||||
return false
|
||||
end
|
||||
|
||||
-- this might be overridden by a document implementation
|
||||
function Document:close()
|
||||
if self.is_open then
|
||||
self.is_open = false
|
||||
self._document:close()
|
||||
end
|
||||
if self.is_open then
|
||||
self.is_open = false
|
||||
self._document:close()
|
||||
end
|
||||
end
|
||||
|
||||
-- this might be overridden by a document implementation
|
||||
function Document:getNativePageDimensions(pageno)
|
||||
local hash = "pgdim|"..self.file.."|"..pageno
|
||||
local cached = Cache:check(hash)
|
||||
if cached then
|
||||
return cached[1]
|
||||
end
|
||||
local page = self._document:openPage(pageno)
|
||||
local page_size_w, page_size_h = page:getSize(self.dc_null)
|
||||
local page_size = Geom:new{ w = page_size_w, h = page_size_h }
|
||||
Cache:insert(hash, CacheItem:new{ page_size })
|
||||
page:close()
|
||||
return page_size
|
||||
local hash = "pgdim|"..self.file.."|"..pageno
|
||||
local cached = Cache:check(hash)
|
||||
if cached then
|
||||
return cached[1]
|
||||
end
|
||||
local page = self._document:openPage(pageno)
|
||||
local page_size_w, page_size_h = page:getSize(self.dc_null)
|
||||
local page_size = Geom:new{ w = page_size_w, h = page_size_h }
|
||||
Cache:insert(hash, CacheItem:new{ page_size })
|
||||
page:close()
|
||||
return page_size
|
||||
end
|
||||
|
||||
function Document:_readMetadata()
|
||||
self.info.number_of_pages = self._document:getPages()
|
||||
return true
|
||||
self.info.number_of_pages = self._document:getPages()
|
||||
return true
|
||||
end
|
||||
|
||||
function Document:getPageCount()
|
||||
return self.info.number_of_pages
|
||||
return self.info.number_of_pages
|
||||
end
|
||||
|
||||
-- calculates page dimensions
|
||||
function Document:getPageDimensions(pageno, zoom, rotation)
|
||||
local native_dimen = self:getNativePageDimensions(pageno):copy()
|
||||
if rotation == 90 or rotation == 270 then
|
||||
-- switch orientation
|
||||
native_dimen.w, native_dimen.h = native_dimen.h, native_dimen.w
|
||||
end
|
||||
native_dimen:scaleBy(zoom)
|
||||
--DEBUG("dimen for pageno", pageno, "zoom", zoom, "rotation", rotation, "is", native_dimen)
|
||||
return native_dimen
|
||||
local native_dimen = self:getNativePageDimensions(pageno):copy()
|
||||
if rotation == 90 or rotation == 270 then
|
||||
-- switch orientation
|
||||
native_dimen.w, native_dimen.h = native_dimen.h, native_dimen.w
|
||||
end
|
||||
native_dimen:scaleBy(zoom)
|
||||
--DEBUG("dimen for pageno", pageno, "zoom", zoom, "rotation", rotation, "is", native_dimen)
|
||||
return native_dimen
|
||||
end
|
||||
|
||||
function Document:getPageBBox(pageno)
|
||||
local bbox = self.bbox[pageno] -- exact
|
||||
if bbox ~= nil then
|
||||
--DEBUG("bbox from", pageno)
|
||||
return bbox
|
||||
else
|
||||
local oddEven = Math.oddEven(pageno)
|
||||
bbox = self.bbox[oddEven] -- odd/even
|
||||
end
|
||||
if bbox ~= nil then -- last used up to this page
|
||||
--DEBUG("bbox from", oddEven)
|
||||
return bbox
|
||||
else
|
||||
for i = 0,pageno do
|
||||
bbox = self.bbox[ pageno - i ]
|
||||
if bbox ~= nil then
|
||||
--DEBUG("bbox from", pageno - i)
|
||||
return bbox
|
||||
end
|
||||
end
|
||||
end
|
||||
if bbox == nil then -- fallback bbox
|
||||
bbox = self:getUsedBBox(pageno)
|
||||
--DEBUG("bbox from ORIGINAL page")
|
||||
end
|
||||
--DEBUG("final bbox", bbox)
|
||||
return bbox
|
||||
local bbox = self.bbox[pageno] -- exact
|
||||
if bbox ~= nil then
|
||||
--DEBUG("bbox from", pageno)
|
||||
return bbox
|
||||
else
|
||||
local oddEven = Math.oddEven(pageno)
|
||||
bbox = self.bbox[oddEven] -- odd/even
|
||||
end
|
||||
if bbox ~= nil then -- last used up to this page
|
||||
--DEBUG("bbox from", oddEven)
|
||||
return bbox
|
||||
else
|
||||
for i = 0,pageno do
|
||||
bbox = self.bbox[ pageno - i ]
|
||||
if bbox ~= nil then
|
||||
--DEBUG("bbox from", pageno - i)
|
||||
return bbox
|
||||
end
|
||||
end
|
||||
end
|
||||
if bbox == nil then -- fallback bbox
|
||||
bbox = self:getUsedBBox(pageno)
|
||||
--DEBUG("bbox from ORIGINAL page")
|
||||
end
|
||||
--DEBUG("final bbox", bbox)
|
||||
return bbox
|
||||
end
|
||||
|
||||
--[[
|
||||
This method returns pagesize if bbox is corrupted
|
||||
--]]
|
||||
function Document:getUsedBBoxDimensions(pageno, zoom, rotation)
|
||||
local bbox = self:getPageBBox(pageno)
|
||||
-- clipping page bbox
|
||||
if bbox.x0 < 0 then bbox.x0 = 0 end
|
||||
if bbox.y0 < 0 then bbox.y0 = 0 end
|
||||
if bbox.x1 < 0 then bbox.x1 = 0 end
|
||||
if bbox.y1 < 0 then bbox.y1 = 0 end
|
||||
local ubbox_dimen = nil
|
||||
if (bbox.x0 > bbox.x1) or (bbox.y0 > bbox.y1) then
|
||||
-- if document's bbox info is corrupted, we use the page size
|
||||
ubbox_dimen = self:getPageDimensions(pageno, zoom, rotation)
|
||||
else
|
||||
ubbox_dimen = Geom:new{
|
||||
x = bbox.x0,
|
||||
y = bbox.y0,
|
||||
w = bbox.x1 - bbox.x0,
|
||||
h = bbox.y1 - bbox.y0,
|
||||
}
|
||||
if zoom ~= 1 then
|
||||
ubbox_dimen:transformByScale(zoom)
|
||||
end
|
||||
end
|
||||
return ubbox_dimen
|
||||
local bbox = self:getPageBBox(pageno)
|
||||
-- clipping page bbox
|
||||
if bbox.x0 < 0 then bbox.x0 = 0 end
|
||||
if bbox.y0 < 0 then bbox.y0 = 0 end
|
||||
if bbox.x1 < 0 then bbox.x1 = 0 end
|
||||
if bbox.y1 < 0 then bbox.y1 = 0 end
|
||||
local ubbox_dimen = nil
|
||||
if (bbox.x0 > bbox.x1) or (bbox.y0 > bbox.y1) then
|
||||
-- if document's bbox info is corrupted, we use the page size
|
||||
ubbox_dimen = self:getPageDimensions(pageno, zoom, rotation)
|
||||
else
|
||||
ubbox_dimen = Geom:new{
|
||||
x = bbox.x0,
|
||||
y = bbox.y0,
|
||||
w = bbox.x1 - bbox.x0,
|
||||
h = bbox.y1 - bbox.y0,
|
||||
}
|
||||
if zoom ~= 1 then
|
||||
ubbox_dimen:transformByScale(zoom)
|
||||
end
|
||||
end
|
||||
return ubbox_dimen
|
||||
end
|
||||
|
||||
function Document:getToc()
|
||||
return self._document:getToc()
|
||||
return self._document:getToc()
|
||||
end
|
||||
|
||||
function Document:getPageLinks(pageno)
|
||||
return nil
|
||||
return nil
|
||||
end
|
||||
|
||||
function Document:getLinkFromPosition(pageno, pos)
|
||||
return nil
|
||||
return nil
|
||||
end
|
||||
|
||||
function Document:getTextBoxes(pageno)
|
||||
return nil
|
||||
return nil
|
||||
end
|
||||
|
||||
function Document:getOCRWord(pageno, rect)
|
||||
return nil
|
||||
return nil
|
||||
end
|
||||
|
||||
function Document:renderPage(pageno, rect, zoom, rotation, gamma, render_mode)
|
||||
local hash = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode
|
||||
local page_size = self:getPageDimensions(pageno, zoom, rotation)
|
||||
-- this will be the size we actually render
|
||||
local size = page_size
|
||||
-- we prefer to render the full page, if it fits into cache
|
||||
if not Cache:willAccept(size.w * size.h / 2) then
|
||||
-- whole page won't fit into cache
|
||||
DEBUG("rendering only part of the page")
|
||||
-- TODO: figure out how to better segment the page
|
||||
if not rect then
|
||||
DEBUG("aborting, since we do not have a specification for that part")
|
||||
-- required part not given, so abort
|
||||
return
|
||||
end
|
||||
-- only render required part
|
||||
hash = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode.."|"..tostring(rect)
|
||||
size = rect
|
||||
end
|
||||
local hash = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode
|
||||
local page_size = self:getPageDimensions(pageno, zoom, rotation)
|
||||
-- this will be the size we actually render
|
||||
local size = page_size
|
||||
-- we prefer to render the full page, if it fits into cache
|
||||
if not Cache:willAccept(size.w * size.h / 2) then
|
||||
-- whole page won't fit into cache
|
||||
DEBUG("rendering only part of the page")
|
||||
-- TODO: figure out how to better segment the page
|
||||
if not rect then
|
||||
DEBUG("aborting, since we do not have a specification for that part")
|
||||
-- required part not given, so abort
|
||||
return
|
||||
end
|
||||
-- only render required part
|
||||
hash = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode.."|"..tostring(rect)
|
||||
size = rect
|
||||
end
|
||||
|
||||
-- prepare cache item with contained blitbuffer
|
||||
local tile = TileCacheItem:new{
|
||||
size = size.w * size.h / 2 + 64, -- estimation
|
||||
excerpt = size,
|
||||
pageno = pageno,
|
||||
bb = Blitbuffer.new(size.w, size.h)
|
||||
}
|
||||
-- prepare cache item with contained blitbuffer
|
||||
local tile = TileCacheItem:new{
|
||||
size = size.w * size.h / 2 + 64, -- estimation
|
||||
excerpt = size,
|
||||
pageno = pageno,
|
||||
bb = Blitbuffer.new(size.w, size.h)
|
||||
}
|
||||
|
||||
-- create a draw context
|
||||
local dc = DrawContext.new()
|
||||
-- create a draw context
|
||||
local dc = DrawContext.new()
|
||||
|
||||
dc:setRotate(rotation)
|
||||
-- correction of rotation
|
||||
if rotation == 90 then
|
||||
dc:setOffset(page_size.w, 0)
|
||||
elseif rotation == 180 then
|
||||
dc:setOffset(page_size.w, page_size.h)
|
||||
elseif rotation == 270 then
|
||||
dc:setOffset(0, page_size.h)
|
||||
end
|
||||
dc:setZoom(zoom)
|
||||
dc:setRotate(rotation)
|
||||
-- correction of rotation
|
||||
if rotation == 90 then
|
||||
dc:setOffset(page_size.w, 0)
|
||||
elseif rotation == 180 then
|
||||
dc:setOffset(page_size.w, page_size.h)
|
||||
elseif rotation == 270 then
|
||||
dc:setOffset(0, page_size.h)
|
||||
end
|
||||
dc:setZoom(zoom)
|
||||
|
||||
if gamma ~= self.GAMMA_NO_GAMMA then
|
||||
--DEBUG("gamma correction: ", gamma)
|
||||
dc:setGamma(gamma)
|
||||
end
|
||||
if gamma ~= self.GAMMA_NO_GAMMA then
|
||||
--DEBUG("gamma correction: ", gamma)
|
||||
dc:setGamma(gamma)
|
||||
end
|
||||
|
||||
-- render
|
||||
local page = self._document:openPage(pageno)
|
||||
page:draw(dc, tile.bb, size.x, size.y, render_mode)
|
||||
page:close()
|
||||
Cache:insert(hash, tile)
|
||||
-- render
|
||||
local page = self._document:openPage(pageno)
|
||||
page:draw(dc, tile.bb, size.x, size.y, render_mode)
|
||||
page:close()
|
||||
Cache:insert(hash, tile)
|
||||
|
||||
return tile
|
||||
return tile
|
||||
end
|
||||
|
||||
-- a hint for the cache engine to paint a full page to the cache
|
||||
-- TODO: this should trigger a background operation
|
||||
function Document:hintPage(pageno, zoom, rotation, gamma, render_mode)
|
||||
local hash_full_page = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode
|
||||
if not Cache:check(hash_full_page) then
|
||||
DEBUG("hinting page", pageno)
|
||||
self:renderPage(pageno, nil, zoom, rotation, gamma, render_mode)
|
||||
end
|
||||
local hash_full_page = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode
|
||||
if not Cache:check(hash_full_page) then
|
||||
DEBUG("hinting page", pageno)
|
||||
self:renderPage(pageno, nil, zoom, rotation, gamma, render_mode)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -268,59 +268,59 @@ Draw page content to blitbuffer.
|
||||
@rect: visible_area inside document page
|
||||
--]]
|
||||
function Document:drawPage(target, x, y, rect, pageno, zoom, rotation, gamma, render_mode)
|
||||
local hash_full_page = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode
|
||||
local hash_excerpt = hash_full_page.."|"..tostring(rect)
|
||||
local tile = Cache:check(hash_full_page)
|
||||
if not tile then
|
||||
tile = Cache:check(hash_excerpt)
|
||||
if not tile then
|
||||
DEBUG("rendering")
|
||||
tile = self:renderPage(pageno, rect, zoom, rotation, gamma, render_mode)
|
||||
end
|
||||
end
|
||||
DEBUG("now painting", tile, rect)
|
||||
target:blitFrom(tile.bb,
|
||||
x, y,
|
||||
rect.x - tile.excerpt.x,
|
||||
rect.y - tile.excerpt.y,
|
||||
rect.w, rect.h)
|
||||
local hash_full_page = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode
|
||||
local hash_excerpt = hash_full_page.."|"..tostring(rect)
|
||||
local tile = Cache:check(hash_full_page)
|
||||
if not tile then
|
||||
tile = Cache:check(hash_excerpt)
|
||||
if not tile then
|
||||
DEBUG("rendering")
|
||||
tile = self:renderPage(pageno, rect, zoom, rotation, gamma, render_mode)
|
||||
end
|
||||
end
|
||||
DEBUG("now painting", tile, rect)
|
||||
target:blitFrom(tile.bb,
|
||||
x, y,
|
||||
rect.x - tile.excerpt.x,
|
||||
rect.y - tile.excerpt.y,
|
||||
rect.w, rect.h)
|
||||
end
|
||||
|
||||
function Document:getPageText(pageno)
|
||||
-- is this worth caching? not done yet.
|
||||
local page = self._document:openPage(pageno)
|
||||
local text = page:getPageText()
|
||||
page:close()
|
||||
return text
|
||||
-- is this worth caching? not done yet.
|
||||
local page = self._document:openPage(pageno)
|
||||
local text = page:getPageText()
|
||||
page:close()
|
||||
return text
|
||||
end
|
||||
|
||||
function Document:saveHighlight(pageno, item)
|
||||
return nil
|
||||
return nil
|
||||
end
|
||||
|
||||
--[[
|
||||
helper functions
|
||||
--]]
|
||||
function Document:logMemoryUsage(pageno)
|
||||
local status_file = io.open("/proc/self/status", "r")
|
||||
local log_file = io.open("mem_usage_log.txt", "a+")
|
||||
local data = -1
|
||||
if status_file then
|
||||
for line in status_file:lines() do
|
||||
local s, n
|
||||
s, n = line:gsub("VmData:%s-(%d+) kB", "%1")
|
||||
if n ~= 0 then data = tonumber(s) end
|
||||
if data ~= -1 then break end
|
||||
end
|
||||
status_file:close()
|
||||
end
|
||||
if log_file then
|
||||
if log_file:seek("end") == 0 then -- write the header only once
|
||||
log_file:write("PAGE\tMEM\n")
|
||||
end
|
||||
log_file:write(string.format("%s\t%s\n", pageno, data))
|
||||
log_file:close()
|
||||
end
|
||||
local status_file = io.open("/proc/self/status", "r")
|
||||
local log_file = io.open("mem_usage_log.txt", "a+")
|
||||
local data = -1
|
||||
if status_file then
|
||||
for line in status_file:lines() do
|
||||
local s, n
|
||||
s, n = line:gsub("VmData:%s-(%d+) kB", "%1")
|
||||
if n ~= 0 then data = tonumber(s) end
|
||||
if data ~= -1 then break end
|
||||
end
|
||||
status_file:close()
|
||||
end
|
||||
if log_file then
|
||||
if log_file:seek("end") == 0 then -- write the header only once
|
||||
log_file:write("PAGE\tMEM\n")
|
||||
end
|
||||
log_file:write(string.format("%s\t%s\n", pageno, data))
|
||||
log_file:close()
|
||||
end
|
||||
end
|
||||
|
||||
return Document
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
This is a registry for document providers
|
||||
]]--
|
||||
local DocumentRegistry = {
|
||||
providers = { }
|
||||
providers = { }
|
||||
}
|
||||
|
||||
function DocumentRegistry:addProvider(extension, mimetype, provider)
|
||||
table.insert(self.providers, { extension = extension, mimetype = mimetype, provider = provider })
|
||||
table.insert(self.providers, { extension = extension, mimetype = mimetype, provider = provider })
|
||||
end
|
||||
|
||||
function DocumentRegistry:getProvider(file)
|
||||
-- TODO: some implementation based on mime types?
|
||||
local extension = string.lower(string.match(file, ".+%.([^.]+)") or "")
|
||||
for _, provider in ipairs(self.providers) do
|
||||
if extension == provider.extension then
|
||||
return provider.provider
|
||||
end
|
||||
end
|
||||
-- TODO: some implementation based on mime types?
|
||||
local extension = string.lower(string.match(file, ".+%.([^.]+)") or "")
|
||||
for _, provider in ipairs(self.providers) do
|
||||
if extension == provider.extension then
|
||||
return provider.provider
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function DocumentRegistry:openDocument(file)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,211 +8,211 @@ local ffi = require("ffi")
|
||||
ffi.cdef[[
|
||||
typedef struct fz_point_s fz_point;
|
||||
struct fz_point_s {
|
||||
float x, y;
|
||||
float x, y;
|
||||
};
|
||||
typedef enum {
|
||||
FZ_ANNOT_TEXT,
|
||||
FZ_ANNOT_LINK,
|
||||
FZ_ANNOT_FREETEXT,
|
||||
FZ_ANNOT_LINE,
|
||||
FZ_ANNOT_SQUARE,
|
||||
FZ_ANNOT_CIRCLE,
|
||||
FZ_ANNOT_POLYGON,
|
||||
FZ_ANNOT_POLYLINE,
|
||||
FZ_ANNOT_HIGHLIGHT,
|
||||
FZ_ANNOT_UNDERLINE,
|
||||
FZ_ANNOT_SQUIGGLY,
|
||||
FZ_ANNOT_STRIKEOUT,
|
||||
FZ_ANNOT_STAMP,
|
||||
FZ_ANNOT_CARET,
|
||||
FZ_ANNOT_INK,
|
||||
FZ_ANNOT_POPUP,
|
||||
FZ_ANNOT_FILEATTACHMENT,
|
||||
FZ_ANNOT_SOUND,
|
||||
FZ_ANNOT_MOVIE,
|
||||
FZ_ANNOT_WIDGET,
|
||||
FZ_ANNOT_SCREEN,
|
||||
FZ_ANNOT_PRINTERMARK,
|
||||
FZ_ANNOT_TRAPNET,
|
||||
FZ_ANNOT_WATERMARK,
|
||||
FZ_ANNOT_3D
|
||||
FZ_ANNOT_TEXT,
|
||||
FZ_ANNOT_LINK,
|
||||
FZ_ANNOT_FREETEXT,
|
||||
FZ_ANNOT_LINE,
|
||||
FZ_ANNOT_SQUARE,
|
||||
FZ_ANNOT_CIRCLE,
|
||||
FZ_ANNOT_POLYGON,
|
||||
FZ_ANNOT_POLYLINE,
|
||||
FZ_ANNOT_HIGHLIGHT,
|
||||
FZ_ANNOT_UNDERLINE,
|
||||
FZ_ANNOT_SQUIGGLY,
|
||||
FZ_ANNOT_STRIKEOUT,
|
||||
FZ_ANNOT_STAMP,
|
||||
FZ_ANNOT_CARET,
|
||||
FZ_ANNOT_INK,
|
||||
FZ_ANNOT_POPUP,
|
||||
FZ_ANNOT_FILEATTACHMENT,
|
||||
FZ_ANNOT_SOUND,
|
||||
FZ_ANNOT_MOVIE,
|
||||
FZ_ANNOT_WIDGET,
|
||||
FZ_ANNOT_SCREEN,
|
||||
FZ_ANNOT_PRINTERMARK,
|
||||
FZ_ANNOT_TRAPNET,
|
||||
FZ_ANNOT_WATERMARK,
|
||||
FZ_ANNOT_3D
|
||||
} fz_annot_type;
|
||||
]]
|
||||
|
||||
local PdfDocument = Document:new{
|
||||
_document = false,
|
||||
-- muPDF manages its own additional cache
|
||||
mupdf_cache_size = 5 * 1024 * 1024,
|
||||
dc_null = DrawContext.new(),
|
||||
options = KoptOptions,
|
||||
koptinterface = nil,
|
||||
annot_revision = 0,
|
||||
_document = false,
|
||||
-- muPDF manages its own additional cache
|
||||
mupdf_cache_size = 5 * 1024 * 1024,
|
||||
dc_null = DrawContext.new(),
|
||||
options = KoptOptions,
|
||||
koptinterface = nil,
|
||||
annot_revision = 0,
|
||||
}
|
||||
|
||||
function PdfDocument:init()
|
||||
local pdf = require("libs/libkoreader-pdf")
|
||||
self.koptinterface = require("document/koptinterface")
|
||||
self.configurable:loadDefaults(self.options)
|
||||
local ok
|
||||
ok, self._document = pcall(pdf.openDocument, self.file, self.mupdf_cache_size)
|
||||
if not ok then
|
||||
self.error_message = self.doc -- will contain error message
|
||||
return
|
||||
end
|
||||
self.is_open = true
|
||||
self.info.has_pages = true
|
||||
self.info.configurable = true
|
||||
if self._document:needsPassword() then
|
||||
self.is_locked = true
|
||||
else
|
||||
self:_readMetadata()
|
||||
end
|
||||
local pdf = require("libs/libkoreader-pdf")
|
||||
self.koptinterface = require("document/koptinterface")
|
||||
self.configurable:loadDefaults(self.options)
|
||||
local ok
|
||||
ok, self._document = pcall(pdf.openDocument, self.file, self.mupdf_cache_size)
|
||||
if not ok then
|
||||
self.error_message = self.doc -- will contain error message
|
||||
return
|
||||
end
|
||||
self.is_open = true
|
||||
self.info.has_pages = true
|
||||
self.info.configurable = true
|
||||
if self._document:needsPassword() then
|
||||
self.is_locked = true
|
||||
else
|
||||
self:_readMetadata()
|
||||
end
|
||||
end
|
||||
|
||||
function PdfDocument:unlock(password)
|
||||
if not self._document:authenticatePassword(password) then
|
||||
self._document:close()
|
||||
return false, "wrong password"
|
||||
end
|
||||
self.is_locked = false
|
||||
return self:_readMetadata()
|
||||
if not self._document:authenticatePassword(password) then
|
||||
self._document:close()
|
||||
return false, "wrong password"
|
||||
end
|
||||
self.is_locked = false
|
||||
return self:_readMetadata()
|
||||
end
|
||||
|
||||
function PdfDocument:getPageTextBoxes(pageno)
|
||||
local page = self._document:openPage(pageno)
|
||||
local text = page:getPageText()
|
||||
page:close()
|
||||
return text
|
||||
local page = self._document:openPage(pageno)
|
||||
local text = page:getPageText()
|
||||
page:close()
|
||||
return text
|
||||
end
|
||||
|
||||
function PdfDocument:getWordFromPosition(spos)
|
||||
return self.koptinterface:getWordFromPosition(self, spos)
|
||||
return self.koptinterface:getWordFromPosition(self, spos)
|
||||
end
|
||||
|
||||
function PdfDocument:getTextFromPositions(spos0, spos1)
|
||||
return self.koptinterface:getTextFromPositions(self, spos0, spos1)
|
||||
return self.koptinterface:getTextFromPositions(self, spos0, spos1)
|
||||
end
|
||||
|
||||
function PdfDocument:getPageBoxesFromPositions(pageno, ppos0, ppos1)
|
||||
return self.koptinterface:getPageBoxesFromPositions(self, pageno, ppos0, ppos1)
|
||||
return self.koptinterface:getPageBoxesFromPositions(self, pageno, ppos0, ppos1)
|
||||
end
|
||||
|
||||
function PdfDocument:getOCRWord(pageno, wbox)
|
||||
return self.koptinterface:getOCRWord(self, pageno, wbox)
|
||||
return self.koptinterface:getOCRWord(self, pageno, wbox)
|
||||
end
|
||||
|
||||
function PdfDocument:getOCRText(pageno, tboxes)
|
||||
return self.koptinterface:getOCRText(self, pageno, tboxes)
|
||||
return self.koptinterface:getOCRText(self, pageno, tboxes)
|
||||
end
|
||||
|
||||
function PdfDocument:getPageRegions(pageno)
|
||||
return self.koptinterface:getPageRegions(self, pageno)
|
||||
return self.koptinterface:getPageRegions(self, pageno)
|
||||
end
|
||||
|
||||
function PdfDocument:getUsedBBox(pageno)
|
||||
local hash = "pgubbox|"..self.file.."|"..pageno
|
||||
local cached = Cache:check(hash)
|
||||
if cached then
|
||||
return cached.ubbox
|
||||
end
|
||||
local page = self._document:openPage(pageno)
|
||||
local used = {}
|
||||
used.x0, used.y0, used.x1, used.y1 = page:getUsedBBox()
|
||||
local pwidth, pheight = page:getSize(self.dc_null)
|
||||
-- clamp to page BBox
|
||||
if used.x0 < 0 then used.x0 = 0 end
|
||||
if used.x1 > pwidth then used.x1 = pwidth end
|
||||
if used.y0 < 0 then used.y0 = 0 end
|
||||
if used.y1 > pheight then used.y1 = pheight end
|
||||
--@TODO give size for cacheitem? 02.12 2012 (houqp)
|
||||
Cache:insert(hash, CacheItem:new{
|
||||
ubbox = used,
|
||||
})
|
||||
page:close()
|
||||
return used
|
||||
local hash = "pgubbox|"..self.file.."|"..pageno
|
||||
local cached = Cache:check(hash)
|
||||
if cached then
|
||||
return cached.ubbox
|
||||
end
|
||||
local page = self._document:openPage(pageno)
|
||||
local used = {}
|
||||
used.x0, used.y0, used.x1, used.y1 = page:getUsedBBox()
|
||||
local pwidth, pheight = page:getSize(self.dc_null)
|
||||
-- clamp to page BBox
|
||||
if used.x0 < 0 then used.x0 = 0 end
|
||||
if used.x1 > pwidth then used.x1 = pwidth end
|
||||
if used.y0 < 0 then used.y0 = 0 end
|
||||
if used.y1 > pheight then used.y1 = pheight end
|
||||
--@TODO give size for cacheitem? 02.12 2012 (houqp)
|
||||
Cache:insert(hash, CacheItem:new{
|
||||
ubbox = used,
|
||||
})
|
||||
page:close()
|
||||
return used
|
||||
end
|
||||
|
||||
function PdfDocument:getPageLinks(pageno)
|
||||
local hash = "pglinks|"..self.file.."|"..pageno
|
||||
local cached = Cache:check(hash)
|
||||
if cached then
|
||||
return cached.links
|
||||
end
|
||||
local page = self._document:openPage(pageno)
|
||||
local links = page:getPageLinks()
|
||||
Cache:insert(hash, CacheItem:new{
|
||||
links = links,
|
||||
})
|
||||
page:close()
|
||||
return links
|
||||
local hash = "pglinks|"..self.file.."|"..pageno
|
||||
local cached = Cache:check(hash)
|
||||
if cached then
|
||||
return cached.links
|
||||
end
|
||||
local page = self._document:openPage(pageno)
|
||||
local links = page:getPageLinks()
|
||||
Cache:insert(hash, CacheItem:new{
|
||||
links = links,
|
||||
})
|
||||
page:close()
|
||||
return links
|
||||
end
|
||||
|
||||
function PdfDocument:saveHighlight(pageno, item)
|
||||
self.annot_revision = self.annot_revision + 1
|
||||
local n = #item.pboxes
|
||||
local quadpoints = ffi.new("fz_point[?]", 4*n)
|
||||
for i=1, n do
|
||||
quadpoints[4*i-4].x = item.pboxes[i].x + item.pboxes[i].w
|
||||
quadpoints[4*i-4].y = item.pboxes[i].y + item.pboxes[i].h
|
||||
quadpoints[4*i-3].x = item.pboxes[i].x
|
||||
quadpoints[4*i-3].y = item.pboxes[i].y + item.pboxes[i].h
|
||||
quadpoints[4*i-2].x = item.pboxes[i].x
|
||||
quadpoints[4*i-2].y = item.pboxes[i].y
|
||||
quadpoints[4*i-1].x = item.pboxes[i].x + item.pboxes[i].w
|
||||
quadpoints[4*i-1].y = item.pboxes[i].y
|
||||
end
|
||||
local page = self._document:openPage(pageno)
|
||||
local annot_type = ffi.C.FZ_ANNOT_HIGHLIGHT
|
||||
if item.drawer == "lighten" then
|
||||
annot_type = ffi.C.FZ_ANNOT_HIGHLIGHT
|
||||
elseif item.drawer == "underscore" then
|
||||
annot_type = ffi.C.FZ_ANNOT_UNDERLINE
|
||||
elseif item.drawer == "strikeout" then
|
||||
annot_type = ffi.C.FZ_ANNOT_STRIKEOUT
|
||||
end
|
||||
page:addMarkupAnnotation(quadpoints, 4*n, annot_type)
|
||||
page:close()
|
||||
self.annot_revision = self.annot_revision + 1
|
||||
local n = #item.pboxes
|
||||
local quadpoints = ffi.new("fz_point[?]", 4*n)
|
||||
for i=1, n do
|
||||
quadpoints[4*i-4].x = item.pboxes[i].x + item.pboxes[i].w
|
||||
quadpoints[4*i-4].y = item.pboxes[i].y + item.pboxes[i].h
|
||||
quadpoints[4*i-3].x = item.pboxes[i].x
|
||||
quadpoints[4*i-3].y = item.pboxes[i].y + item.pboxes[i].h
|
||||
quadpoints[4*i-2].x = item.pboxes[i].x
|
||||
quadpoints[4*i-2].y = item.pboxes[i].y
|
||||
quadpoints[4*i-1].x = item.pboxes[i].x + item.pboxes[i].w
|
||||
quadpoints[4*i-1].y = item.pboxes[i].y
|
||||
end
|
||||
local page = self._document:openPage(pageno)
|
||||
local annot_type = ffi.C.FZ_ANNOT_HIGHLIGHT
|
||||
if item.drawer == "lighten" then
|
||||
annot_type = ffi.C.FZ_ANNOT_HIGHLIGHT
|
||||
elseif item.drawer == "underscore" then
|
||||
annot_type = ffi.C.FZ_ANNOT_UNDERLINE
|
||||
elseif item.drawer == "strikeout" then
|
||||
annot_type = ffi.C.FZ_ANNOT_STRIKEOUT
|
||||
end
|
||||
page:addMarkupAnnotation(quadpoints, 4*n, annot_type)
|
||||
page:close()
|
||||
end
|
||||
|
||||
function PdfDocument:writeDocument()
|
||||
self._document:writeDocument(self.file)
|
||||
self._document:writeDocument(self.file)
|
||||
end
|
||||
|
||||
function PdfDocument:close()
|
||||
if self.annot_revision ~= 0 then
|
||||
self:writeDocument()
|
||||
end
|
||||
Document.close(self)
|
||||
if self.annot_revision ~= 0 then
|
||||
self:writeDocument()
|
||||
end
|
||||
Document.close(self)
|
||||
end
|
||||
|
||||
function PdfDocument:getLinkFromPosition(pageno, pos)
|
||||
return self.koptinterface:getLinkFromPosition(self, pageno, pos)
|
||||
return self.koptinterface:getLinkFromPosition(self, pageno, pos)
|
||||
end
|
||||
|
||||
function PdfDocument:getPageBBox(pageno)
|
||||
return self.koptinterface:getPageBBox(self, pageno)
|
||||
return self.koptinterface:getPageBBox(self, pageno)
|
||||
end
|
||||
|
||||
function PdfDocument:getPageDimensions(pageno, zoom, rotation)
|
||||
return self.koptinterface:getPageDimensions(self, pageno, zoom, rotation)
|
||||
return self.koptinterface:getPageDimensions(self, pageno, zoom, rotation)
|
||||
end
|
||||
|
||||
function PdfDocument:renderPage(pageno, rect, zoom, rotation, gamma, render_mode)
|
||||
return self.koptinterface:renderPage(self, pageno, rect, zoom, rotation, gamma, render_mode)
|
||||
return self.koptinterface:renderPage(self, pageno, rect, zoom, rotation, gamma, render_mode)
|
||||
end
|
||||
|
||||
function PdfDocument:hintPage(pageno, zoom, rotation, gamma, render_mode)
|
||||
return self.koptinterface:hintPage(self, pageno, zoom, rotation, gamma, render_mode)
|
||||
return self.koptinterface:hintPage(self, pageno, zoom, rotation, gamma, render_mode)
|
||||
end
|
||||
|
||||
function PdfDocument:drawPage(target, x, y, rect, pageno, zoom, rotation, gamma, render_mode)
|
||||
return self.koptinterface:drawPage(self, target, x, y, rect, pageno, zoom, rotation, gamma, render_mode)
|
||||
return self.koptinterface:drawPage(self, target, x, y, rect, pageno, zoom, rotation, gamma, render_mode)
|
||||
end
|
||||
|
||||
function PdfDocument:register(registry)
|
||||
registry:addProvider("pdf", "application/pdf", self)
|
||||
registry:addProvider("cbz", "application/cbz", self)
|
||||
registry:addProvider("xps", "application/xps", self)
|
||||
registry:addProvider("pdf", "application/pdf", self)
|
||||
registry:addProvider("cbz", "application/cbz", self)
|
||||
registry:addProvider("xps", "application/xps", self)
|
||||
end
|
||||
|
||||
return PdfDocument
|
||||
|
||||
@@ -2,31 +2,31 @@ local Document = require("document/document")
|
||||
local DrawContext = require("ffi/drawcontext")
|
||||
|
||||
local PicDocument = Document:new{
|
||||
_document = false,
|
||||
dc_null = DrawContext.new()
|
||||
_document = false,
|
||||
dc_null = DrawContext.new()
|
||||
}
|
||||
|
||||
function PicDocument:init()
|
||||
require "libs/libkoreader-pic"
|
||||
ok, self._document = pcall(pic.openDocument, self.file)
|
||||
if not ok then
|
||||
self.error_message = "failed to open jpeg image"
|
||||
return
|
||||
end
|
||||
require "libs/libkoreader-pic"
|
||||
ok, self._document = pcall(pic.openDocument, self.file)
|
||||
if not ok then
|
||||
self.error_message = "failed to open jpeg image"
|
||||
return
|
||||
end
|
||||
|
||||
self.info.has_pages = true
|
||||
self.info.configurable = false
|
||||
self.info.has_pages = true
|
||||
self.info.configurable = false
|
||||
|
||||
self:readMetadata()
|
||||
self:readMetadata()
|
||||
end
|
||||
|
||||
function PicDocument:readMetadata()
|
||||
self.info.number_of_pages = 1
|
||||
self.info.number_of_pages = 1
|
||||
end
|
||||
|
||||
function PicDocument:register(registry)
|
||||
registry:addProvider("jpeg", "application/jpeg", self)
|
||||
registry:addProvider("jpg", "application/jpeg", self)
|
||||
registry:addProvider("jpeg", "application/jpeg", self)
|
||||
registry:addProvider("jpg", "application/jpeg", self)
|
||||
end
|
||||
|
||||
return PicDocument
|
||||
|
||||
@@ -4,10 +4,10 @@ local DEBUG = require("dbg")
|
||||
local TileCacheItem = CacheItem:new{}
|
||||
|
||||
function TileCacheItem:onFree()
|
||||
if self.bb.free then
|
||||
DEBUG("free blitbuffer", self.bb)
|
||||
self.bb:free()
|
||||
end
|
||||
if self.bb.free then
|
||||
DEBUG("free blitbuffer", self.bb)
|
||||
self.bb:free()
|
||||
end
|
||||
end
|
||||
|
||||
return TileCacheItem
|
||||
|
||||
@@ -4,11 +4,11 @@ local GetText = {}
|
||||
local GetText_mt = {}
|
||||
|
||||
function GetText_mt.__call(gettext, string)
|
||||
return lua_gettext.translate(string)
|
||||
return lua_gettext.translate(string)
|
||||
end
|
||||
|
||||
function GetText.changeLang(new_lang)
|
||||
lua_gettext.change_lang(new_lang)
|
||||
lua_gettext.change_lang(new_lang)
|
||||
end
|
||||
|
||||
setmetatable(GetText, GetText_mt)
|
||||
|
||||
@@ -5,42 +5,42 @@ Simple math helper function
|
||||
local Math = {}
|
||||
|
||||
function Math.roundAwayFromZero(num)
|
||||
if num > 0 then
|
||||
return math.ceil(num)
|
||||
else
|
||||
return math.floor(num)
|
||||
end
|
||||
if num > 0 then
|
||||
return math.ceil(num)
|
||||
else
|
||||
return math.floor(num)
|
||||
end
|
||||
end
|
||||
|
||||
function Math.round(num)
|
||||
return math.floor(num + 0.5)
|
||||
return math.floor(num + 0.5)
|
||||
end
|
||||
|
||||
function Math.oddEven(number)
|
||||
if number % 2 == 1 then
|
||||
return "odd"
|
||||
else
|
||||
return "even"
|
||||
end
|
||||
if number % 2 == 1 then
|
||||
return "odd"
|
||||
else
|
||||
return "even"
|
||||
end
|
||||
end
|
||||
|
||||
local function tmin_max(tab, func, op)
|
||||
if #tab == 0 then return nil, nil end
|
||||
local index, value = 1, tab[1]
|
||||
if #tab == 0 then return nil, nil end
|
||||
local index, value = 1, tab[1]
|
||||
for i = 2, #tab do
|
||||
if func then
|
||||
if func(value, tab[i]) then
|
||||
index, value = i, tab[i]
|
||||
end
|
||||
elseif op == "min" then
|
||||
if value > tab[i] then
|
||||
index, value = i, tab[i]
|
||||
end
|
||||
elseif op == "max" then
|
||||
if value < tab[i] then
|
||||
index, value = i, tab[i]
|
||||
end
|
||||
end
|
||||
if func then
|
||||
if func(value, tab[i]) then
|
||||
index, value = i, tab[i]
|
||||
end
|
||||
elseif op == "min" then
|
||||
if value > tab[i] then
|
||||
index, value = i, tab[i]
|
||||
end
|
||||
elseif op == "max" then
|
||||
if value < tab[i] then
|
||||
index, value = i, tab[i]
|
||||
end
|
||||
end
|
||||
end
|
||||
return index, value
|
||||
end
|
||||
@@ -50,7 +50,7 @@ Return the minimum element of a table.
|
||||
The optional argument func specifies a one-argument ordering function.
|
||||
]]--
|
||||
function Math.tmin(tab, func)
|
||||
return tmin_max(tab, func, "min")
|
||||
return tmin_max(tab, func, "min")
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -58,7 +58,7 @@ Return the maximum element of a table.
|
||||
The optional argument func specifies a one-argument ordering function.
|
||||
]]--
|
||||
function Math.tmax(tab, func)
|
||||
return tmin_max(tab, func, "max")
|
||||
return tmin_max(tab, func, "max")
|
||||
end
|
||||
|
||||
return Math
|
||||
|
||||
@@ -5,144 +5,144 @@ local _ = require("gettext")
|
||||
|
||||
-- add multiply operator to Aa dict
|
||||
local Aa = setmetatable({"Aa"}, {
|
||||
__mul = function(t, mul)
|
||||
local new = {}
|
||||
for i = 1, mul do
|
||||
for _, v in ipairs(t) do table.insert(new, v) end
|
||||
end
|
||||
return new
|
||||
end
|
||||
__mul = function(t, mul)
|
||||
local new = {}
|
||||
for i = 1, mul do
|
||||
for _, v in ipairs(t) do table.insert(new, v) end
|
||||
end
|
||||
return new
|
||||
end
|
||||
})
|
||||
|
||||
local CreOptions = {
|
||||
prefix = 'copt',
|
||||
{
|
||||
icon = "resources/icons/appbar.transform.rotate.right.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "screen_mode",
|
||||
name_text = S.SCREEN_MODE,
|
||||
toggle = {S.PORTRAIT, S.LANDSCAPE},
|
||||
alternate = false,
|
||||
args = {"portrait", "landscape"},
|
||||
default_arg = "portrait",
|
||||
current_func = function() return Screen:getScreenMode() end,
|
||||
event = "ChangeScreenMode",
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.column.two.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "line_spacing",
|
||||
name_text = S.LINE_SPACING,
|
||||
toggle = {S.DECREASE, S.INCREASE},
|
||||
alternate = false,
|
||||
args = {"decrease", "increase"},
|
||||
default_arg = "decrease",
|
||||
event = "ChangeLineSpace",
|
||||
},
|
||||
{
|
||||
name = "page_margins",
|
||||
name_text = S.PAGE_MARGIN,
|
||||
toggle = {S.SMALL, S.MEDIUM, S.LARGE},
|
||||
values = {
|
||||
DCREREADER_CONFIG_MARGIN_SIZES_SMALL,
|
||||
DCREREADER_CONFIG_MARGIN_SIZES_MEDIUM,
|
||||
DCREREADER_CONFIG_MARGIN_SIZES_LARGE,
|
||||
},
|
||||
default_value = DCREREADER_CONFIG_MARGIN_SIZES_MEDIUM,
|
||||
args = {
|
||||
DCREREADER_CONFIG_MARGIN_SIZES_SMALL,
|
||||
DCREREADER_CONFIG_MARGIN_SIZES_MEDIUM,
|
||||
DCREREADER_CONFIG_MARGIN_SIZES_LARGE,
|
||||
},
|
||||
event = "SetPageMargins",
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.text.size.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "font_size",
|
||||
item_text = Aa * #DCREREADER_CONFIG_FONT_SIZES,
|
||||
item_align_center = 1.0,
|
||||
spacing = 15,
|
||||
item_font_size = DCREREADER_CONFIG_FONT_SIZES,
|
||||
values = DCREREADER_CONFIG_FONT_SIZES,
|
||||
default_value = DCREREADER_CONFIG_DEFAULT_FONT_SIZE,
|
||||
args = DCREREADER_CONFIG_FONT_SIZES,
|
||||
event = "SetFontSize",
|
||||
},
|
||||
{
|
||||
name = "font_fine_tune",
|
||||
name_text = S.FONTSIZE_FINE_TUNING,
|
||||
toggle = {S.DECREASE, S.INCREASE},
|
||||
event = "ChangeSize",
|
||||
args = {"decrease", "increase"},
|
||||
alternate = false,
|
||||
height = 60,
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.grade.b.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "font_weight",
|
||||
name_text = S.FONT_WEIGHT,
|
||||
toggle = {S.TOGGLE_BOLD},
|
||||
default_arg = nil,
|
||||
event = "ToggleFontBolder",
|
||||
},
|
||||
{
|
||||
name = "font_gamma",
|
||||
name_text = S.CONTRAST,
|
||||
toggle = {S.DECREASE, S.INCREASE},
|
||||
alternate = false,
|
||||
args = {"decrease", "increase"},
|
||||
default_arg = "increase",
|
||||
event = "ChangeFontGamma",
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.settings.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "view_mode",
|
||||
name_text = S.VIEW_MODE,
|
||||
toggle = {S.VIEW_SCROLL, S.VIEW_PAGE},
|
||||
values = {1, 0},
|
||||
default_value = 0,
|
||||
args = {"scroll", "page"},
|
||||
default_arg = "page",
|
||||
event = "SetViewMode",
|
||||
},
|
||||
{
|
||||
name = "status_line",
|
||||
name_text = S.PROGRESS_BAR,
|
||||
toggle = {S.FULL, S.MINI},
|
||||
values = {0, 1},
|
||||
default_value = DCREREADER_PROGRESS_BAR,
|
||||
args = {0, 1},
|
||||
default_arg = DCREREADER_PROGRESS_BAR,
|
||||
event = "SetStatusLine",
|
||||
},
|
||||
{
|
||||
name = "embedded_css",
|
||||
name_text = S.EMBEDDED_STYLE,
|
||||
toggle = {S.ON, S.OFF},
|
||||
values = {1, 0},
|
||||
default_value = 1,
|
||||
args = {true, false},
|
||||
default_arg = nil,
|
||||
event = "ToggleEmbeddedStyleSheet",
|
||||
},
|
||||
},
|
||||
},
|
||||
prefix = 'copt',
|
||||
{
|
||||
icon = "resources/icons/appbar.transform.rotate.right.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "screen_mode",
|
||||
name_text = S.SCREEN_MODE,
|
||||
toggle = {S.PORTRAIT, S.LANDSCAPE},
|
||||
alternate = false,
|
||||
args = {"portrait", "landscape"},
|
||||
default_arg = "portrait",
|
||||
current_func = function() return Screen:getScreenMode() end,
|
||||
event = "ChangeScreenMode",
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.column.two.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "line_spacing",
|
||||
name_text = S.LINE_SPACING,
|
||||
toggle = {S.DECREASE, S.INCREASE},
|
||||
alternate = false,
|
||||
args = {"decrease", "increase"},
|
||||
default_arg = "decrease",
|
||||
event = "ChangeLineSpace",
|
||||
},
|
||||
{
|
||||
name = "page_margins",
|
||||
name_text = S.PAGE_MARGIN,
|
||||
toggle = {S.SMALL, S.MEDIUM, S.LARGE},
|
||||
values = {
|
||||
DCREREADER_CONFIG_MARGIN_SIZES_SMALL,
|
||||
DCREREADER_CONFIG_MARGIN_SIZES_MEDIUM,
|
||||
DCREREADER_CONFIG_MARGIN_SIZES_LARGE,
|
||||
},
|
||||
default_value = DCREREADER_CONFIG_MARGIN_SIZES_MEDIUM,
|
||||
args = {
|
||||
DCREREADER_CONFIG_MARGIN_SIZES_SMALL,
|
||||
DCREREADER_CONFIG_MARGIN_SIZES_MEDIUM,
|
||||
DCREREADER_CONFIG_MARGIN_SIZES_LARGE,
|
||||
},
|
||||
event = "SetPageMargins",
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.text.size.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "font_size",
|
||||
item_text = Aa * #DCREREADER_CONFIG_FONT_SIZES,
|
||||
item_align_center = 1.0,
|
||||
spacing = 15,
|
||||
item_font_size = DCREREADER_CONFIG_FONT_SIZES,
|
||||
values = DCREREADER_CONFIG_FONT_SIZES,
|
||||
default_value = DCREREADER_CONFIG_DEFAULT_FONT_SIZE,
|
||||
args = DCREREADER_CONFIG_FONT_SIZES,
|
||||
event = "SetFontSize",
|
||||
},
|
||||
{
|
||||
name = "font_fine_tune",
|
||||
name_text = S.FONTSIZE_FINE_TUNING,
|
||||
toggle = {S.DECREASE, S.INCREASE},
|
||||
event = "ChangeSize",
|
||||
args = {"decrease", "increase"},
|
||||
alternate = false,
|
||||
height = 60,
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.grade.b.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "font_weight",
|
||||
name_text = S.FONT_WEIGHT,
|
||||
toggle = {S.TOGGLE_BOLD},
|
||||
default_arg = nil,
|
||||
event = "ToggleFontBolder",
|
||||
},
|
||||
{
|
||||
name = "font_gamma",
|
||||
name_text = S.CONTRAST,
|
||||
toggle = {S.DECREASE, S.INCREASE},
|
||||
alternate = false,
|
||||
args = {"decrease", "increase"},
|
||||
default_arg = "increase",
|
||||
event = "ChangeFontGamma",
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.settings.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "view_mode",
|
||||
name_text = S.VIEW_MODE,
|
||||
toggle = {S.VIEW_SCROLL, S.VIEW_PAGE},
|
||||
values = {1, 0},
|
||||
default_value = 0,
|
||||
args = {"scroll", "page"},
|
||||
default_arg = "page",
|
||||
event = "SetViewMode",
|
||||
},
|
||||
{
|
||||
name = "status_line",
|
||||
name_text = S.PROGRESS_BAR,
|
||||
toggle = {S.FULL, S.MINI},
|
||||
values = {0, 1},
|
||||
default_value = DCREREADER_PROGRESS_BAR,
|
||||
args = {0, 1},
|
||||
default_arg = DCREREADER_PROGRESS_BAR,
|
||||
event = "SetStatusLine",
|
||||
},
|
||||
{
|
||||
name = "embedded_css",
|
||||
name_text = S.EMBEDDED_STYLE,
|
||||
toggle = {S.ON, S.OFF},
|
||||
values = {1, 0},
|
||||
default_value = 1,
|
||||
args = {true, false},
|
||||
default_arg = nil,
|
||||
event = "ToggleEmbeddedStyleSheet",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return CreOptions
|
||||
|
||||
@@ -4,222 +4,222 @@ local S = require("ui/data/strings")
|
||||
local _ = require("gettext")
|
||||
|
||||
local KoptOptions = {
|
||||
prefix = 'kopt',
|
||||
{
|
||||
icon = "resources/icons/appbar.transform.rotate.right.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "screen_mode",
|
||||
name_text = S.SCREEN_MODE,
|
||||
toggle = {S.PORTRAIT, S.LANDSCAPE},
|
||||
alternate = false,
|
||||
args = {"portrait", "landscape"},
|
||||
default_arg = "portrait",
|
||||
current_func = function() return Screen:getScreenMode() end,
|
||||
event = "SetScreenMode",
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.crop.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "trim_page",
|
||||
name_text = S.PAGE_CROP,
|
||||
width = 225,
|
||||
toggle = {S.MANUAL, S.AUTO, S.SEMIAUTO},
|
||||
alternate = false,
|
||||
values = {0, 1, 2},
|
||||
default_value = DKOPTREADER_CONFIG_TRIM_PAGE,
|
||||
event = "PageCrop",
|
||||
args = {"manual", "auto", "semi-auto"},
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.column.two.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "page_scroll",
|
||||
name_text = S.SCROLL_MODE,
|
||||
toggle = {S.ON, S.OFF},
|
||||
values = {1, 0},
|
||||
default_value = DSCROLL_MODE,
|
||||
event = "ToggleScrollMode",
|
||||
args = {true, false},
|
||||
},
|
||||
{
|
||||
name = "full_screen",
|
||||
name_text = S.PROGRESS_BAR,
|
||||
toggle = {S.OFF, S.ON},
|
||||
values = {1, 0},
|
||||
default_value = DFULL_SCREEN,
|
||||
event = "SetFullScreen",
|
||||
args = {true, false},
|
||||
},
|
||||
{
|
||||
name = "page_margin",
|
||||
name_text = S.PAGE_MARGIN,
|
||||
toggle = {S.SMALL, S.MEDIUM, S.LARGE},
|
||||
values = {0.05, 0.10, 0.15},
|
||||
default_value = DKOPTREADER_CONFIG_PAGE_MARGIN,
|
||||
event = "MarginUpdate",
|
||||
},
|
||||
{
|
||||
name = "line_spacing",
|
||||
name_text = S.LINE_SPACING,
|
||||
toggle = {S.SMALL, S.MEDIUM, S.LARGE},
|
||||
values = {1.0, 1.2, 1.4},
|
||||
default_value = DKOPTREADER_CONFIG_LINE_SPACING,
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.text.size.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "font_size",
|
||||
item_text = {"Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa"},
|
||||
item_align_center = 1.0,
|
||||
spacing = 15,
|
||||
height = 60,
|
||||
item_font_size = {22,24,28,32,34,36,38,42,46,50},
|
||||
values = {0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.6, 2.0, 4.0},
|
||||
default_value = DKOPTREADER_CONFIG_FONT_SIZE,
|
||||
event = "FontSizeUpdate",
|
||||
},
|
||||
{
|
||||
name = "font_fine_tune",
|
||||
name_text = S.FONTSIZE_FINE_TUNING,
|
||||
toggle = {S.DECREASE, S.INCREASE},
|
||||
values = {-0.05, 0.05},
|
||||
default_value = 0.05,
|
||||
event = "FineTuningFontSize",
|
||||
args = {-0.05, 0.05},
|
||||
alternate = false,
|
||||
height = 60,
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.grade.b.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "contrast",
|
||||
name_text = S.CONTRAST,
|
||||
name_align_right = 0.2,
|
||||
item_text = {S.LIGHTEST , S.LIGHTER, S.DEFAULT, S.DARKER, S.DARKEST},
|
||||
item_font_size = 18,
|
||||
item_align_center = 0.8,
|
||||
values = {2.0, 1.5, 1.0, 0.5, 0.2},
|
||||
default_value = DKOPTREADER_CONFIG_CONTRAST,
|
||||
event = "GammaUpdate",
|
||||
args = {0.5, 0.8, 1.0, 2.0, 4.0},
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.settings.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "text_wrap",
|
||||
name_text = _("Reflow"),
|
||||
toggle = {S.ON, S.OFF},
|
||||
values = {1, 0},
|
||||
default_value = DKOPTREADER_CONFIG_TEXT_WRAP,
|
||||
events = {
|
||||
{
|
||||
event = "RedrawCurrentPage",
|
||||
},
|
||||
{
|
||||
event = "RestoreZoomMode",
|
||||
},
|
||||
{
|
||||
event = "InitScrollPageStates",
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
name="doc_language",
|
||||
name_text = S.DOC_LANG,
|
||||
toggle = DKOPTREADER_CONFIG_DOC_LANGS_TEXT,
|
||||
values = DKOPTREADER_CONFIG_DOC_LANGS_CODE,
|
||||
default_value = DKOPTREADER_CONFIG_DOC_DEFAULT_LANG_CODE,
|
||||
event = "DocLangUpdate",
|
||||
args = DKOPTREADER_CONFIG_DOC_LANGS_CODE,
|
||||
},
|
||||
{
|
||||
name = "word_spacing",
|
||||
name_text = S.WORD_GAP,
|
||||
toggle = {S.SMALL, S.AUTO, S.LARGE},
|
||||
values = DKOPTREADER_CONFIG_WORD_SAPCINGS,
|
||||
default_value = DKOPTREADER_CONFIG_DEFAULT_WORD_SAPCING,
|
||||
},
|
||||
{
|
||||
name = "writing_direction",
|
||||
name_text = S.WRITING_DIR,
|
||||
toggle = {S.LTR, S.RTL, S.TBRTL},
|
||||
values = {0, 1, 2},
|
||||
default_value = 0,
|
||||
},
|
||||
{
|
||||
name = "quality",
|
||||
name_text = S.RENDER_QUALITY,
|
||||
toggle = {S.LOW, S.DEFAULT, S.HIGH},
|
||||
values={0.5, 1.0, 1.5},
|
||||
default_value = DKOPTREADER_CONFIG_RENDER_QUALITY,
|
||||
},
|
||||
{
|
||||
name = "max_columns",
|
||||
name_text = S.COLUMNS,
|
||||
item_icons = {
|
||||
"resources/icons/appbar.column.one.png",
|
||||
"resources/icons/appbar.column.two.png",
|
||||
"resources/icons/appbar.column.three.png",
|
||||
},
|
||||
values = {1,2,3},
|
||||
default_value = DKOPTREADER_CONFIG_MAX_COLUMNS,
|
||||
},
|
||||
{
|
||||
name = "justification",
|
||||
name_text = S.TEXT_ALIGN,
|
||||
item_icons = {
|
||||
"resources/icons/appbar.align.auto.png",
|
||||
"resources/icons/appbar.align.left.png",
|
||||
"resources/icons/appbar.align.center.png",
|
||||
"resources/icons/appbar.align.right.png",
|
||||
"resources/icons/appbar.align.justify.png",
|
||||
},
|
||||
values = {-1,0,1,2,3},
|
||||
default_value = DKOPTREADER_CONFIG_JUSTIFICATION,
|
||||
},
|
||||
{
|
||||
name = "defect_size",
|
||||
name_text = S.DEFECT_SIZE,
|
||||
toggle = {S.SMALL, S.MEDIUM, S.LARGE},
|
||||
values = {1.0, 3.0, 5.0},
|
||||
default_value = DKOPTREADER_CONFIG_DEFECT_SIZE,
|
||||
event = "DefectSizeUpdate",
|
||||
show = false,
|
||||
},
|
||||
{
|
||||
name = "auto_straighten",
|
||||
name_text = S.AUTO_STRAIGHTEN,
|
||||
toggle = {S.ZERO_DEG, S.FIVE_DEG, S.TEN_DEG},
|
||||
values = {0, 5, 10},
|
||||
default_value = DKOPTREADER_CONFIG_AUTO_STRAIGHTEN,
|
||||
show = false,
|
||||
},
|
||||
{
|
||||
name = "detect_indent",
|
||||
name_text = S.INDENTATION,
|
||||
toggle = {S.ON, S.OFF},
|
||||
values = {1, 0},
|
||||
default_value = DKOPTREADER_CONFIG_DETECT_INDENT,
|
||||
show = false,
|
||||
},
|
||||
}
|
||||
},
|
||||
prefix = 'kopt',
|
||||
{
|
||||
icon = "resources/icons/appbar.transform.rotate.right.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "screen_mode",
|
||||
name_text = S.SCREEN_MODE,
|
||||
toggle = {S.PORTRAIT, S.LANDSCAPE},
|
||||
alternate = false,
|
||||
args = {"portrait", "landscape"},
|
||||
default_arg = "portrait",
|
||||
current_func = function() return Screen:getScreenMode() end,
|
||||
event = "SetScreenMode",
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.crop.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "trim_page",
|
||||
name_text = S.PAGE_CROP,
|
||||
width = 225,
|
||||
toggle = {S.MANUAL, S.AUTO, S.SEMIAUTO},
|
||||
alternate = false,
|
||||
values = {0, 1, 2},
|
||||
default_value = DKOPTREADER_CONFIG_TRIM_PAGE,
|
||||
event = "PageCrop",
|
||||
args = {"manual", "auto", "semi-auto"},
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.column.two.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "page_scroll",
|
||||
name_text = S.SCROLL_MODE,
|
||||
toggle = {S.ON, S.OFF},
|
||||
values = {1, 0},
|
||||
default_value = DSCROLL_MODE,
|
||||
event = "ToggleScrollMode",
|
||||
args = {true, false},
|
||||
},
|
||||
{
|
||||
name = "full_screen",
|
||||
name_text = S.PROGRESS_BAR,
|
||||
toggle = {S.OFF, S.ON},
|
||||
values = {1, 0},
|
||||
default_value = DFULL_SCREEN,
|
||||
event = "SetFullScreen",
|
||||
args = {true, false},
|
||||
},
|
||||
{
|
||||
name = "page_margin",
|
||||
name_text = S.PAGE_MARGIN,
|
||||
toggle = {S.SMALL, S.MEDIUM, S.LARGE},
|
||||
values = {0.05, 0.10, 0.15},
|
||||
default_value = DKOPTREADER_CONFIG_PAGE_MARGIN,
|
||||
event = "MarginUpdate",
|
||||
},
|
||||
{
|
||||
name = "line_spacing",
|
||||
name_text = S.LINE_SPACING,
|
||||
toggle = {S.SMALL, S.MEDIUM, S.LARGE},
|
||||
values = {1.0, 1.2, 1.4},
|
||||
default_value = DKOPTREADER_CONFIG_LINE_SPACING,
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.text.size.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "font_size",
|
||||
item_text = {"Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa"},
|
||||
item_align_center = 1.0,
|
||||
spacing = 15,
|
||||
height = 60,
|
||||
item_font_size = {22,24,28,32,34,36,38,42,46,50},
|
||||
values = {0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.6, 2.0, 4.0},
|
||||
default_value = DKOPTREADER_CONFIG_FONT_SIZE,
|
||||
event = "FontSizeUpdate",
|
||||
},
|
||||
{
|
||||
name = "font_fine_tune",
|
||||
name_text = S.FONTSIZE_FINE_TUNING,
|
||||
toggle = {S.DECREASE, S.INCREASE},
|
||||
values = {-0.05, 0.05},
|
||||
default_value = 0.05,
|
||||
event = "FineTuningFontSize",
|
||||
args = {-0.05, 0.05},
|
||||
alternate = false,
|
||||
height = 60,
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.grade.b.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "contrast",
|
||||
name_text = S.CONTRAST,
|
||||
name_align_right = 0.2,
|
||||
item_text = {S.LIGHTEST , S.LIGHTER, S.DEFAULT, S.DARKER, S.DARKEST},
|
||||
item_font_size = 18,
|
||||
item_align_center = 0.8,
|
||||
values = {2.0, 1.5, 1.0, 0.5, 0.2},
|
||||
default_value = DKOPTREADER_CONFIG_CONTRAST,
|
||||
event = "GammaUpdate",
|
||||
args = {0.5, 0.8, 1.0, 2.0, 4.0},
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
icon = "resources/icons/appbar.settings.large.png",
|
||||
options = {
|
||||
{
|
||||
name = "text_wrap",
|
||||
name_text = _("Reflow"),
|
||||
toggle = {S.ON, S.OFF},
|
||||
values = {1, 0},
|
||||
default_value = DKOPTREADER_CONFIG_TEXT_WRAP,
|
||||
events = {
|
||||
{
|
||||
event = "RedrawCurrentPage",
|
||||
},
|
||||
{
|
||||
event = "RestoreZoomMode",
|
||||
},
|
||||
{
|
||||
event = "InitScrollPageStates",
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
name="doc_language",
|
||||
name_text = S.DOC_LANG,
|
||||
toggle = DKOPTREADER_CONFIG_DOC_LANGS_TEXT,
|
||||
values = DKOPTREADER_CONFIG_DOC_LANGS_CODE,
|
||||
default_value = DKOPTREADER_CONFIG_DOC_DEFAULT_LANG_CODE,
|
||||
event = "DocLangUpdate",
|
||||
args = DKOPTREADER_CONFIG_DOC_LANGS_CODE,
|
||||
},
|
||||
{
|
||||
name = "word_spacing",
|
||||
name_text = S.WORD_GAP,
|
||||
toggle = {S.SMALL, S.AUTO, S.LARGE},
|
||||
values = DKOPTREADER_CONFIG_WORD_SAPCINGS,
|
||||
default_value = DKOPTREADER_CONFIG_DEFAULT_WORD_SAPCING,
|
||||
},
|
||||
{
|
||||
name = "writing_direction",
|
||||
name_text = S.WRITING_DIR,
|
||||
toggle = {S.LTR, S.RTL, S.TBRTL},
|
||||
values = {0, 1, 2},
|
||||
default_value = 0,
|
||||
},
|
||||
{
|
||||
name = "quality",
|
||||
name_text = S.RENDER_QUALITY,
|
||||
toggle = {S.LOW, S.DEFAULT, S.HIGH},
|
||||
values={0.5, 1.0, 1.5},
|
||||
default_value = DKOPTREADER_CONFIG_RENDER_QUALITY,
|
||||
},
|
||||
{
|
||||
name = "max_columns",
|
||||
name_text = S.COLUMNS,
|
||||
item_icons = {
|
||||
"resources/icons/appbar.column.one.png",
|
||||
"resources/icons/appbar.column.two.png",
|
||||
"resources/icons/appbar.column.three.png",
|
||||
},
|
||||
values = {1,2,3},
|
||||
default_value = DKOPTREADER_CONFIG_MAX_COLUMNS,
|
||||
},
|
||||
{
|
||||
name = "justification",
|
||||
name_text = S.TEXT_ALIGN,
|
||||
item_icons = {
|
||||
"resources/icons/appbar.align.auto.png",
|
||||
"resources/icons/appbar.align.left.png",
|
||||
"resources/icons/appbar.align.center.png",
|
||||
"resources/icons/appbar.align.right.png",
|
||||
"resources/icons/appbar.align.justify.png",
|
||||
},
|
||||
values = {-1,0,1,2,3},
|
||||
default_value = DKOPTREADER_CONFIG_JUSTIFICATION,
|
||||
},
|
||||
{
|
||||
name = "defect_size",
|
||||
name_text = S.DEFECT_SIZE,
|
||||
toggle = {S.SMALL, S.MEDIUM, S.LARGE},
|
||||
values = {1.0, 3.0, 5.0},
|
||||
default_value = DKOPTREADER_CONFIG_DEFECT_SIZE,
|
||||
event = "DefectSizeUpdate",
|
||||
show = false,
|
||||
},
|
||||
{
|
||||
name = "auto_straighten",
|
||||
name_text = S.AUTO_STRAIGHTEN,
|
||||
toggle = {S.ZERO_DEG, S.FIVE_DEG, S.TEN_DEG},
|
||||
values = {0, 5, 10},
|
||||
default_value = DKOPTREADER_CONFIG_AUTO_STRAIGHTEN,
|
||||
show = false,
|
||||
},
|
||||
{
|
||||
name = "detect_indent",
|
||||
name_text = S.INDENTATION,
|
||||
toggle = {S.ON, S.OFF},
|
||||
values = {1, 0},
|
||||
default_value = DKOPTREADER_CONFIG_DETECT_INDENT,
|
||||
show = false,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return KoptOptions
|
||||
|
||||
@@ -6,229 +6,229 @@ local Screen = require("ui/device/screen")
|
||||
-- lfs
|
||||
|
||||
local Device = {
|
||||
screen_saver_mode = false,
|
||||
charging_mode = false,
|
||||
survive_screen_saver = false,
|
||||
touch_dev = nil,
|
||||
model = nil,
|
||||
firmware_rev = nil,
|
||||
powerd = nil,
|
||||
has_no_keyboard = nil,
|
||||
is_touch_device = nil,
|
||||
has_front_light = nil,
|
||||
screen = Screen
|
||||
screen_saver_mode = false,
|
||||
charging_mode = false,
|
||||
survive_screen_saver = false,
|
||||
touch_dev = nil,
|
||||
model = nil,
|
||||
firmware_rev = nil,
|
||||
powerd = nil,
|
||||
has_no_keyboard = nil,
|
||||
is_touch_device = nil,
|
||||
has_front_light = nil,
|
||||
screen = Screen
|
||||
}
|
||||
|
||||
Screen.device = Device
|
||||
|
||||
function Set (list)
|
||||
local set = {}
|
||||
for _, l in ipairs(list) do set[l] = true end
|
||||
return set
|
||||
local set = {}
|
||||
for _, l in ipairs(list) do set[l] = true end
|
||||
return set
|
||||
end
|
||||
|
||||
function Device:getModel()
|
||||
if self.model then return self.model end
|
||||
if util.isEmulated() then
|
||||
self.model = "Emulator"
|
||||
return self.model
|
||||
end
|
||||
self.model = nil
|
||||
local kindle_sn = io.open("/proc/usid", "r")
|
||||
if kindle_sn then
|
||||
local kindle_devcode = string.sub(kindle_sn:read(),3,4)
|
||||
kindle_sn:close()
|
||||
-- NOTE: Update me when new models come out :)
|
||||
local k2_set = Set { "02", "03" }
|
||||
local dx_set = Set { "04", "05" }
|
||||
local dxg_set = Set { "09" }
|
||||
local k3_set = Set { "08", "06", "0A" }
|
||||
local k4_set = Set { "0E", "23" }
|
||||
local touch_set = Set { "0F", "11", "10", "12" }
|
||||
local pw_set = Set { "24", "1B", "1D", "1F", "1C", "20" }
|
||||
local pw2_set = Set { "D4", "5A", "D5", "D7", "D8", "F2" }
|
||||
if self.model then return self.model end
|
||||
if util.isEmulated() then
|
||||
self.model = "Emulator"
|
||||
return self.model
|
||||
end
|
||||
self.model = nil
|
||||
local kindle_sn = io.open("/proc/usid", "r")
|
||||
if kindle_sn then
|
||||
local kindle_devcode = string.sub(kindle_sn:read(),3,4)
|
||||
kindle_sn:close()
|
||||
-- NOTE: Update me when new models come out :)
|
||||
local k2_set = Set { "02", "03" }
|
||||
local dx_set = Set { "04", "05" }
|
||||
local dxg_set = Set { "09" }
|
||||
local k3_set = Set { "08", "06", "0A" }
|
||||
local k4_set = Set { "0E", "23" }
|
||||
local touch_set = Set { "0F", "11", "10", "12" }
|
||||
local pw_set = Set { "24", "1B", "1D", "1F", "1C", "20" }
|
||||
local pw2_set = Set { "D4", "5A", "D5", "D7", "D8", "F2" }
|
||||
|
||||
if k2_set[kindle_devcode] then
|
||||
self.model = "Kindle2"
|
||||
elseif dx_set[kindle_devcode] then
|
||||
self.model = "Kindle2"
|
||||
elseif dxg_set[kindle_devcode] then
|
||||
self.model = "Kindle2"
|
||||
elseif k3_set[kindle_devcode] then
|
||||
self.model = "Kindle3"
|
||||
elseif k4_set[kindle_devcode] then
|
||||
self.model = "Kindle4"
|
||||
elseif touch_set[kindle_devcode] then
|
||||
self.model = "KindleTouch"
|
||||
elseif pw_set[kindle_devcode] then
|
||||
self.model = "KindlePaperWhite"
|
||||
elseif pw2_set[kindle_devcode] then
|
||||
self.model = "KindlePaperWhite2"
|
||||
end
|
||||
else
|
||||
local kg_test_fd = lfs.attributes("/bin/kobo_config.sh")
|
||||
if kg_test_fd then
|
||||
local std_out = io.popen("/bin/kobo_config.sh", "r")
|
||||
local codename = std_out:read()
|
||||
self.model = "Kobo_" .. codename
|
||||
local version_file = io.open("/mnt/onboard/.kobo/version", "r")
|
||||
self.firmware_rev = string.sub(version_file:read(),24,28)
|
||||
version_file:close()
|
||||
end
|
||||
end
|
||||
return self.model
|
||||
if k2_set[kindle_devcode] then
|
||||
self.model = "Kindle2"
|
||||
elseif dx_set[kindle_devcode] then
|
||||
self.model = "Kindle2"
|
||||
elseif dxg_set[kindle_devcode] then
|
||||
self.model = "Kindle2"
|
||||
elseif k3_set[kindle_devcode] then
|
||||
self.model = "Kindle3"
|
||||
elseif k4_set[kindle_devcode] then
|
||||
self.model = "Kindle4"
|
||||
elseif touch_set[kindle_devcode] then
|
||||
self.model = "KindleTouch"
|
||||
elseif pw_set[kindle_devcode] then
|
||||
self.model = "KindlePaperWhite"
|
||||
elseif pw2_set[kindle_devcode] then
|
||||
self.model = "KindlePaperWhite2"
|
||||
end
|
||||
else
|
||||
local kg_test_fd = lfs.attributes("/bin/kobo_config.sh")
|
||||
if kg_test_fd then
|
||||
local std_out = io.popen("/bin/kobo_config.sh", "r")
|
||||
local codename = std_out:read()
|
||||
self.model = "Kobo_" .. codename
|
||||
local version_file = io.open("/mnt/onboard/.kobo/version", "r")
|
||||
self.firmware_rev = string.sub(version_file:read(),24,28)
|
||||
version_file:close()
|
||||
end
|
||||
end
|
||||
return self.model
|
||||
end
|
||||
|
||||
function Device:getFirmVer()
|
||||
if not self.model then self:getModel() end
|
||||
return self.firmware_rev
|
||||
if not self.model then self:getModel() end
|
||||
return self.firmware_rev
|
||||
end
|
||||
|
||||
function Device:isKindle4()
|
||||
return (self:getModel() == "Kindle4")
|
||||
return (self:getModel() == "Kindle4")
|
||||
end
|
||||
|
||||
function Device:isKindle3()
|
||||
return (self:getModel() == "Kindle3")
|
||||
return (self:getModel() == "Kindle3")
|
||||
end
|
||||
|
||||
function Device:isKindle2()
|
||||
return (self:getModel() == "Kindle2")
|
||||
return (self:getModel() == "Kindle2")
|
||||
end
|
||||
|
||||
function Device:isKobo()
|
||||
return string.find(self:getModel(),"Kobo_") == 1
|
||||
return string.find(self:getModel(),"Kobo_") == 1
|
||||
end
|
||||
|
||||
function Device:hasNoKeyboard()
|
||||
if self.has_no_keyboard ~= nil then return self.has_no_keyboard end
|
||||
local model = self:getModel()
|
||||
self.has_no_keyboard = (model == "KindlePaperWhite") or (model == "KindlePaperWhite2")
|
||||
or (model == "KindleTouch") or self:isKobo()
|
||||
return self.has_no_keyboard
|
||||
if self.has_no_keyboard ~= nil then return self.has_no_keyboard end
|
||||
local model = self:getModel()
|
||||
self.has_no_keyboard = (model == "KindlePaperWhite") or (model == "KindlePaperWhite2")
|
||||
or (model == "KindleTouch") or self:isKobo()
|
||||
return self.has_no_keyboard
|
||||
end
|
||||
|
||||
function Device:hasKeyboard()
|
||||
return not self:hasNoKeyboard()
|
||||
return not self:hasNoKeyboard()
|
||||
end
|
||||
|
||||
function Device:isTouchDevice()
|
||||
if self.is_touch_device ~= nil then return self.is_touch_device end
|
||||
local model = self:getModel()
|
||||
self.is_touch_device = (model == "KindlePaperWhite") or (model == "KindlePaperWhite2")
|
||||
or (model == "KindleTouch") or self:isKobo() or util.isEmulated()
|
||||
return self.is_touch_device
|
||||
if self.is_touch_device ~= nil then return self.is_touch_device end
|
||||
local model = self:getModel()
|
||||
self.is_touch_device = (model == "KindlePaperWhite") or (model == "KindlePaperWhite2")
|
||||
or (model == "KindleTouch") or self:isKobo() or util.isEmulated()
|
||||
return self.is_touch_device
|
||||
end
|
||||
|
||||
function Device:hasFrontlight()
|
||||
if self.has_front_light ~= nil then return self.has_front_light end
|
||||
local model = self:getModel()
|
||||
self.has_front_light = (model == "KindlePaperWhite") or (model == "KindlePaperWhite2")
|
||||
or (model == "Kobo_dragon") or (model == "Kobo_kraken") or (model == "Kobo_phoenix")
|
||||
or util.isEmulated()
|
||||
return self.has_front_light
|
||||
if self.has_front_light ~= nil then return self.has_front_light end
|
||||
local model = self:getModel()
|
||||
self.has_front_light = (model == "KindlePaperWhite") or (model == "KindlePaperWhite2")
|
||||
or (model == "Kobo_dragon") or (model == "Kobo_kraken") or (model == "Kobo_phoenix")
|
||||
or util.isEmulated()
|
||||
return self.has_front_light
|
||||
end
|
||||
|
||||
function Device:setTouchInputDev(dev)
|
||||
self.touch_dev = dev
|
||||
self.touch_dev = dev
|
||||
end
|
||||
|
||||
function Device:getTouchInputDev()
|
||||
return self.touch_dev
|
||||
return self.touch_dev
|
||||
end
|
||||
|
||||
function Device:intoScreenSaver()
|
||||
--os.execute("echo 'screensaver in' >> /mnt/us/event_test.txt")
|
||||
if self.charging_mode == false and self.screen_saver_mode == false then
|
||||
self.screen:saveCurrentBB()
|
||||
--UIManager:show(InfoMessage:new{
|
||||
--text = "Going into screensaver... ",
|
||||
--timeout = 2,
|
||||
--})
|
||||
--util.sleep(1)
|
||||
--os.execute("killall -cont cvm")
|
||||
self.screen_saver_mode = true
|
||||
end
|
||||
--os.execute("echo 'screensaver in' >> /mnt/us/event_test.txt")
|
||||
if self.charging_mode == false and self.screen_saver_mode == false then
|
||||
self.screen:saveCurrentBB()
|
||||
--UIManager:show(InfoMessage:new{
|
||||
--text = "Going into screensaver... ",
|
||||
--timeout = 2,
|
||||
--})
|
||||
--util.sleep(1)
|
||||
--os.execute("killall -cont cvm")
|
||||
self.screen_saver_mode = true
|
||||
end
|
||||
end
|
||||
|
||||
function Device:outofScreenSaver()
|
||||
--os.execute("echo 'screensaver out' >> /mnt/us/event_test.txt")
|
||||
if self.screen_saver_mode == true and self.charging_mode == false then
|
||||
-- wait for native system update screen before we recover saved
|
||||
-- Blitbuffer.
|
||||
util.usleep(1500000)
|
||||
--os.execute("killall -stop cvm")
|
||||
self.screen:restoreFromSavedBB()
|
||||
self.screen:refresh(0)
|
||||
self.survive_screen_saver = true
|
||||
end
|
||||
self.screen_saver_mode = false
|
||||
--os.execute("echo 'screensaver out' >> /mnt/us/event_test.txt")
|
||||
if self.screen_saver_mode == true and self.charging_mode == false then
|
||||
-- wait for native system update screen before we recover saved
|
||||
-- Blitbuffer.
|
||||
util.usleep(1500000)
|
||||
--os.execute("killall -stop cvm")
|
||||
self.screen:restoreFromSavedBB()
|
||||
self.screen:refresh(0)
|
||||
self.survive_screen_saver = true
|
||||
end
|
||||
self.screen_saver_mode = false
|
||||
end
|
||||
|
||||
function Device:prepareSuspend() -- currently only used for kobo devices
|
||||
local powerd = self:getPowerDevice()
|
||||
if powerd ~= nil then
|
||||
powerd.fl:sleep()
|
||||
end
|
||||
self.screen:refresh(0)
|
||||
self.screen_saver_mode = true
|
||||
local powerd = self:getPowerDevice()
|
||||
if powerd ~= nil then
|
||||
powerd.fl:sleep()
|
||||
end
|
||||
self.screen:refresh(0)
|
||||
self.screen_saver_mode = true
|
||||
end
|
||||
|
||||
function Device:Suspend() -- currently only used for kobo devices
|
||||
os.execute("./kobo_suspend.sh")
|
||||
os.execute("./kobo_suspend.sh")
|
||||
end
|
||||
|
||||
function Device:Resume() -- currently only used for kobo devices
|
||||
os.execute("echo 0 > /sys/power/state-extended")
|
||||
self.screen:refresh(0)
|
||||
local powerd = self:getPowerDevice()
|
||||
if powerd ~= nil then
|
||||
powerd.fl:restore()
|
||||
end
|
||||
self.screen_saver_mode = false
|
||||
os.execute("echo 0 > /sys/power/state-extended")
|
||||
self.screen:refresh(0)
|
||||
local powerd = self:getPowerDevice()
|
||||
if powerd ~= nil then
|
||||
powerd.fl:restore()
|
||||
end
|
||||
self.screen_saver_mode = false
|
||||
end
|
||||
|
||||
function Device:usbPlugIn()
|
||||
--os.execute("echo 'usb in' >> /mnt/us/event_test.txt")
|
||||
if self.charging_mode == false and self.screen_saver_mode == false then
|
||||
self.screen:saveCurrentBB()
|
||||
--UIManager:show(InfoMessage:new{
|
||||
--text = "Going into USB mode... ",
|
||||
--timeout = 2,
|
||||
--})
|
||||
--util.sleep(1)
|
||||
--os.execute("killall -cont cvm")
|
||||
end
|
||||
self.charging_mode = true
|
||||
--os.execute("echo 'usb in' >> /mnt/us/event_test.txt")
|
||||
if self.charging_mode == false and self.screen_saver_mode == false then
|
||||
self.screen:saveCurrentBB()
|
||||
--UIManager:show(InfoMessage:new{
|
||||
--text = "Going into USB mode... ",
|
||||
--timeout = 2,
|
||||
--})
|
||||
--util.sleep(1)
|
||||
--os.execute("killall -cont cvm")
|
||||
end
|
||||
self.charging_mode = true
|
||||
end
|
||||
|
||||
function Device:usbPlugOut()
|
||||
--os.execute("echo 'usb out' >> /mnt/us/event_test.txt")
|
||||
if self.charging_mode == true and self.screen_saver_mode == false then
|
||||
--util.usleep(1500000)
|
||||
--os.execute("killall -stop cvm")
|
||||
self.screen:restoreFromSavedBB()
|
||||
self.screen:refresh(0)
|
||||
end
|
||||
--os.execute("echo 'usb out' >> /mnt/us/event_test.txt")
|
||||
if self.charging_mode == true and self.screen_saver_mode == false then
|
||||
--util.usleep(1500000)
|
||||
--os.execute("killall -stop cvm")
|
||||
self.screen:restoreFromSavedBB()
|
||||
self.screen:refresh(0)
|
||||
end
|
||||
|
||||
--@TODO signal filemanager for file changes 13.06 2012 (houqp)
|
||||
self.charging_mode = false
|
||||
--@TODO signal filemanager for file changes 13.06 2012 (houqp)
|
||||
self.charging_mode = false
|
||||
end
|
||||
|
||||
function Device:getPowerDevice()
|
||||
if self.powerd ~= nil then
|
||||
return self.powerd
|
||||
else
|
||||
local model = self:getModel()
|
||||
if model == "KindleTouch" or model == "KindlePaperWhite" or model == "KindlePaperWhite2" then
|
||||
self.powerd = KindlePowerD:new{model = model}
|
||||
elseif self:isKobo() then
|
||||
self.powerd = KoboPowerD:new()
|
||||
else -- emulated FrontLight
|
||||
self.powerd = BasePowerD:new()
|
||||
end
|
||||
end
|
||||
return self.powerd
|
||||
if self.powerd ~= nil then
|
||||
return self.powerd
|
||||
else
|
||||
local model = self:getModel()
|
||||
if model == "KindleTouch" or model == "KindlePaperWhite" or model == "KindlePaperWhite2" then
|
||||
self.powerd = KindlePowerD:new{model = model}
|
||||
elseif self:isKobo() then
|
||||
self.powerd = KoboPowerD:new()
|
||||
else -- emulated FrontLight
|
||||
self.powerd = BasePowerD:new()
|
||||
end
|
||||
end
|
||||
return self.powerd
|
||||
end
|
||||
|
||||
return Device
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
local BasePowerD = {
|
||||
fl_min = 0, -- min frontlight intensity
|
||||
fl_max = 10, -- max frontlight intensity
|
||||
flIntensity = nil, -- frontlight intensity
|
||||
battCapacity = nil, -- battery capacity
|
||||
model = nil, -- device model
|
||||
|
||||
capacity_pulled_count = 0,
|
||||
capacity_cached_count = 10,
|
||||
fl_min = 0, -- min frontlight intensity
|
||||
fl_max = 10, -- max frontlight intensity
|
||||
flIntensity = nil, -- frontlight intensity
|
||||
battCapacity = nil, -- battery capacity
|
||||
model = nil, -- device model
|
||||
|
||||
capacity_pulled_count = 0,
|
||||
capacity_cached_count = 10,
|
||||
}
|
||||
|
||||
function BasePowerD:new(o)
|
||||
local o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
if o.init then o:init() end
|
||||
return o
|
||||
local o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
if o.init then o:init() end
|
||||
return o
|
||||
end
|
||||
|
||||
function BasePowerD:init() end
|
||||
@@ -26,39 +26,39 @@ function BasePowerD:suspendHW() end
|
||||
function BasePowerD:wakeUpHW() end
|
||||
|
||||
function BasePowerD:read_int_file(file)
|
||||
local f = io.open(file, "r")
|
||||
local sysint = tonumber(f:read("*all"):match("%d+"))
|
||||
f:close()
|
||||
return sysint
|
||||
local f = io.open(file, "r")
|
||||
local sysint = tonumber(f:read("*all"):match("%d+"))
|
||||
f:close()
|
||||
return sysint
|
||||
end
|
||||
|
||||
function BasePowerD:setIntensity(intensity)
|
||||
intensity = intensity < self.fl_min and self.fl_min or intensity
|
||||
intensity = intensity > self.fl_max and self.fl_max or intensity
|
||||
self.flIntensity = intensity
|
||||
self:setIntensityHW()
|
||||
intensity = intensity < self.fl_min and self.fl_min or intensity
|
||||
intensity = intensity > self.fl_max and self.fl_max or intensity
|
||||
self.flIntensity = intensity
|
||||
self:setIntensityHW()
|
||||
end
|
||||
|
||||
function BasePowerD:getCapacity()
|
||||
if capacity_pulled_count == capacity_cached_count then
|
||||
capacity_pulled_count = 0
|
||||
return self:getCapacityHW()
|
||||
else
|
||||
capacity_pulled_count = capacity_pulled_count + 1
|
||||
return self.battCapacity or self:getCapacityHW()
|
||||
end
|
||||
if capacity_pulled_count == capacity_cached_count then
|
||||
capacity_pulled_count = 0
|
||||
return self:getCapacityHW()
|
||||
else
|
||||
capacity_pulled_count = capacity_pulled_count + 1
|
||||
return self.battCapacity or self:getCapacityHW()
|
||||
end
|
||||
end
|
||||
|
||||
function BasePowerD:isCharging()
|
||||
return self:isChargingHW()
|
||||
return self:isChargingHW()
|
||||
end
|
||||
|
||||
function BasePowerD:suspend()
|
||||
return self:suspendHW()
|
||||
return self:suspendHW()
|
||||
end
|
||||
|
||||
function BasePowerD:wakeUp()
|
||||
return self:wakeUpHW()
|
||||
return self:wakeUpHW()
|
||||
end
|
||||
|
||||
return BasePowerD
|
||||
|
||||
@@ -2,85 +2,85 @@ local BasePowerD = require("ui/device/basepowerd")
|
||||
-- liblipclua, see require below
|
||||
|
||||
local KindlePowerD = BasePowerD:new{
|
||||
fl_min = 0, fl_max = 24,
|
||||
kpw1_frontlight = "/sys/devices/system/fl_tps6116x/fl_tps6116x0/fl_intensity",
|
||||
kpw2_frontlight = "/sys/class/backlight/max77696-bl/brightness",
|
||||
kt_kpw_capacity = "/sys/devices/system/yoshi_battery/yoshi_battery0/battery_capacity",
|
||||
kpw_charging = "/sys/devices/platform/aplite_charger.0/charging",
|
||||
kt_charging = "/sys/devices/platform/fsl-usb2-udc/charging",
|
||||
|
||||
flIntensity = nil,
|
||||
battCapacity = nil,
|
||||
is_charging = nil,
|
||||
lipc_handle = nil,
|
||||
fl_min = 0, fl_max = 24,
|
||||
kpw1_frontlight = "/sys/devices/system/fl_tps6116x/fl_tps6116x0/fl_intensity",
|
||||
kpw2_frontlight = "/sys/class/backlight/max77696-bl/brightness",
|
||||
kt_kpw_capacity = "/sys/devices/system/yoshi_battery/yoshi_battery0/battery_capacity",
|
||||
kpw_charging = "/sys/devices/platform/aplite_charger.0/charging",
|
||||
kt_charging = "/sys/devices/platform/fsl-usb2-udc/charging",
|
||||
|
||||
flIntensity = nil,
|
||||
battCapacity = nil,
|
||||
is_charging = nil,
|
||||
lipc_handle = nil,
|
||||
}
|
||||
|
||||
function KindlePowerD:new(o)
|
||||
local o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
if o.init then o:init(o.model) end
|
||||
return o
|
||||
local o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
if o.init then o:init(o.model) end
|
||||
return o
|
||||
end
|
||||
|
||||
function KindlePowerD:init(model)
|
||||
local lipc = require("liblipclua")
|
||||
if lipc then
|
||||
self.lipc_handle = lipc.init("com.github.koreader")
|
||||
end
|
||||
|
||||
if model == "KindleTouch" then
|
||||
self.batt_capacity_file = self.kt_kpw_capacity
|
||||
self.is_charging_file = self.kt_charging
|
||||
elseif model == "KindlePaperWhite" then
|
||||
self.fl_intensity_file = self.kpw1_frontlight
|
||||
self.batt_capacity_file = self.kt_kpw_capacity
|
||||
self.is_charging_file = self.kpw_charging
|
||||
elseif model == "KindlePaperWhite2" then
|
||||
self.fl_intensity_file = self.kpw2_frontlight
|
||||
self.batt_capacity_file = self.kt_kpw_capacity
|
||||
self.is_charging_file = self.kpw_charging
|
||||
end
|
||||
if self.lipc_handle then
|
||||
self.flIntensity = self.lipc_handle:get_int_property("com.lab126.powerd", "flIntensity")
|
||||
else
|
||||
self.flIntensity = self:read_int_file(self.fl_intensity_file)
|
||||
end
|
||||
local lipc = require("liblipclua")
|
||||
if lipc then
|
||||
self.lipc_handle = lipc.init("com.github.koreader")
|
||||
end
|
||||
|
||||
if model == "KindleTouch" then
|
||||
self.batt_capacity_file = self.kt_kpw_capacity
|
||||
self.is_charging_file = self.kt_charging
|
||||
elseif model == "KindlePaperWhite" then
|
||||
self.fl_intensity_file = self.kpw1_frontlight
|
||||
self.batt_capacity_file = self.kt_kpw_capacity
|
||||
self.is_charging_file = self.kpw_charging
|
||||
elseif model == "KindlePaperWhite2" then
|
||||
self.fl_intensity_file = self.kpw2_frontlight
|
||||
self.batt_capacity_file = self.kt_kpw_capacity
|
||||
self.is_charging_file = self.kpw_charging
|
||||
end
|
||||
if self.lipc_handle then
|
||||
self.flIntensity = self.lipc_handle:get_int_property("com.lab126.powerd", "flIntensity")
|
||||
else
|
||||
self.flIntensity = self:read_int_file(self.fl_intensity_file)
|
||||
end
|
||||
end
|
||||
|
||||
function KindlePowerD:toggleFrontlight()
|
||||
local sysint = self:read_int_file(self.fl_intensity_file)
|
||||
if sysint == 0 then
|
||||
self:setIntensity(self.flIntensity)
|
||||
else
|
||||
os.execute("echo -n 0 > " .. self.fl_intensity_file)
|
||||
end
|
||||
local sysint = self:read_int_file(self.fl_intensity_file)
|
||||
if sysint == 0 then
|
||||
self:setIntensity(self.flIntensity)
|
||||
else
|
||||
os.execute("echo -n 0 > " .. self.fl_intensity_file)
|
||||
end
|
||||
end
|
||||
|
||||
function KindlePowerD:setIntensityHW()
|
||||
if self.lipc_handle ~= nil then
|
||||
self.lipc_handle:set_int_property("com.lab126.powerd", "flIntensity", self.flIntensity)
|
||||
else
|
||||
os.execute("echo -n ".. self.flIntensity .." > " .. self.fl_intensity_file)
|
||||
end
|
||||
if self.lipc_handle ~= nil then
|
||||
self.lipc_handle:set_int_property("com.lab126.powerd", "flIntensity", self.flIntensity)
|
||||
else
|
||||
os.execute("echo -n ".. self.flIntensity .." > " .. self.fl_intensity_file)
|
||||
end
|
||||
end
|
||||
|
||||
function KindlePowerD:getCapacityHW()
|
||||
if self.lipc_handle ~= nil then
|
||||
self.battCapacity = self.lipc_handle:get_int_property("com.lab126.powerd", "battLevel")
|
||||
else
|
||||
self.battCapacity = self:read_int_file(self.batt_capacity_file)
|
||||
end
|
||||
return self.battCapacity
|
||||
if self.lipc_handle ~= nil then
|
||||
self.battCapacity = self.lipc_handle:get_int_property("com.lab126.powerd", "battLevel")
|
||||
else
|
||||
self.battCapacity = self:read_int_file(self.batt_capacity_file)
|
||||
end
|
||||
return self.battCapacity
|
||||
end
|
||||
|
||||
function KindlePowerD:isChargingHW()
|
||||
if self.lipc_handle ~= nil then
|
||||
self.is_charging = self.lipc_handle:get_int_property("com.lab126.powerd", "isCharging")
|
||||
else
|
||||
self.is_charging = self:read_int_file(self.is_charging_file)
|
||||
end
|
||||
return self.is_charging == 1
|
||||
if self.lipc_handle ~= nil then
|
||||
self.is_charging = self.lipc_handle:get_int_property("com.lab126.powerd", "isCharging")
|
||||
else
|
||||
self.is_charging = self:read_int_file(self.is_charging_file)
|
||||
end
|
||||
return self.is_charging == 1
|
||||
end
|
||||
|
||||
return KindlePowerD
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
local BasePowerD = require("ui/device/basepowerd")
|
||||
|
||||
local KoboPowerD = BasePowerD:new{
|
||||
fl_min = 1, fl_max = 100,
|
||||
flIntensity = 20,
|
||||
restore_settings = true,
|
||||
fl = nil,
|
||||
|
||||
batt_capacity_file = "/sys/devices/platform/pmic_battery.1/power_supply/mc13892_bat/capacity",
|
||||
is_charging_file = "/sys/devices/platform/pmic_battery.1/power_supply/mc13892_bat/charge_now",
|
||||
battCapacity = nil,
|
||||
is_charging = nil,
|
||||
fl_min = 1, fl_max = 100,
|
||||
flIntensity = 20,
|
||||
restore_settings = true,
|
||||
fl = nil,
|
||||
|
||||
batt_capacity_file = "/sys/devices/platform/pmic_battery.1/power_supply/mc13892_bat/capacity",
|
||||
is_charging_file = "/sys/devices/platform/pmic_battery.1/power_supply/mc13892_bat/charge_now",
|
||||
battCapacity = nil,
|
||||
is_charging = nil,
|
||||
}
|
||||
|
||||
function KoboPowerD:init()
|
||||
self.fl = kobolight.open()
|
||||
self.fl = kobolight.open()
|
||||
end
|
||||
|
||||
function KoboPowerD:toggleFrontlight()
|
||||
if self.fl ~= nil then
|
||||
self.fl:toggle()
|
||||
end
|
||||
if self.fl ~= nil then
|
||||
self.fl:toggle()
|
||||
end
|
||||
end
|
||||
|
||||
function KoboPowerD:setIntensityHW()
|
||||
if self.fl ~= nil then
|
||||
self.fl:setBrightness(self.flIntensity)
|
||||
end
|
||||
if self.fl ~= nil then
|
||||
self.fl:setBrightness(self.flIntensity)
|
||||
end
|
||||
end
|
||||
|
||||
function KoboPowerD:getCapacityHW()
|
||||
self.battCapacity = self:read_int_file(self.batt_capacity_file)
|
||||
return self.battCapacity
|
||||
self.battCapacity = self:read_int_file(self.batt_capacity_file)
|
||||
return self.battCapacity
|
||||
end
|
||||
|
||||
function KoboPowerD:isChargingHW()
|
||||
self.is_charging = self:read_int_file(self.is_charging_file)
|
||||
return self.is_charging == 1
|
||||
self.is_charging = self:read_int_file(self.is_charging_file)
|
||||
return self.is_charging == 1
|
||||
end
|
||||
|
||||
return KoboPowerD
|
||||
|
||||
@@ -29,131 +29,131 @@ Codes for rotation modes:
|
||||
|
||||
|
||||
local Screen = {
|
||||
cur_rotation_mode = 0,
|
||||
native_rotation_mode = nil,
|
||||
blitbuffer_rotation_mode = 0,
|
||||
cur_rotation_mode = 0,
|
||||
native_rotation_mode = nil,
|
||||
blitbuffer_rotation_mode = 0,
|
||||
|
||||
bb = nil,
|
||||
saved_bb = nil,
|
||||
bb = nil,
|
||||
saved_bb = nil,
|
||||
|
||||
fb = einkfb.open("/dev/fb0"),
|
||||
-- will be set upon loading by Device class:
|
||||
device = nil,
|
||||
fb = einkfb.open("/dev/fb0"),
|
||||
-- will be set upon loading by Device class:
|
||||
device = nil,
|
||||
}
|
||||
|
||||
function Screen:init()
|
||||
self.bb = self.fb.bb
|
||||
self.blitbuffer_rotation_mode = self.bb:getRotation()
|
||||
-- asking the framebuffer for orientation is error prone,
|
||||
-- so we do this simple heuristic (for now)
|
||||
if self:getWidth() > self:getHeight() then
|
||||
self.native_rotation_mode = 1
|
||||
else
|
||||
self.native_rotation_mode = 0
|
||||
end
|
||||
self.cur_rotation_mode = self.native_rotation_mode
|
||||
self.bb = self.fb.bb
|
||||
self.blitbuffer_rotation_mode = self.bb:getRotation()
|
||||
-- asking the framebuffer for orientation is error prone,
|
||||
-- so we do this simple heuristic (for now)
|
||||
if self:getWidth() > self:getHeight() then
|
||||
self.native_rotation_mode = 1
|
||||
else
|
||||
self.native_rotation_mode = 0
|
||||
end
|
||||
self.cur_rotation_mode = self.native_rotation_mode
|
||||
end
|
||||
|
||||
function Screen:refresh(refresh_type, waveform_mode, x, y, w, h)
|
||||
self.fb:refresh(refresh_type, waveform_mode, x, y, w, h)
|
||||
self.fb:refresh(refresh_type, waveform_mode, x, y, w, h)
|
||||
end
|
||||
|
||||
function Screen:getSize()
|
||||
return Geom:new{w = self.bb:getWidth(), h = self.bb:getHeight()}
|
||||
return Geom:new{w = self.bb:getWidth(), h = self.bb:getHeight()}
|
||||
end
|
||||
|
||||
function Screen:getWidth()
|
||||
return self.bb:getWidth()
|
||||
return self.bb:getWidth()
|
||||
end
|
||||
|
||||
function Screen:getHeight()
|
||||
return self.bb:getHeight()
|
||||
return self.bb:getHeight()
|
||||
end
|
||||
|
||||
function Screen:getDPI()
|
||||
if(self.device:getModel() == "KindlePaperWhite")
|
||||
or (self.device:getModel() == "Kobo_kraken")
|
||||
or (self.device:getModel() == "Kobo_phoenix") then
|
||||
return 212
|
||||
elseif self.device:getModel() == "Kobo_dragon" then
|
||||
return 265
|
||||
elseif self.device:getModel() == "Kobo_pixie" then
|
||||
return 200
|
||||
else
|
||||
return 167
|
||||
end
|
||||
if(self.device:getModel() == "KindlePaperWhite")
|
||||
or (self.device:getModel() == "Kobo_kraken")
|
||||
or (self.device:getModel() == "Kobo_phoenix") then
|
||||
return 212
|
||||
elseif self.device:getModel() == "Kobo_dragon" then
|
||||
return 265
|
||||
elseif self.device:getModel() == "Kobo_pixie" then
|
||||
return 200
|
||||
else
|
||||
return 167
|
||||
end
|
||||
end
|
||||
|
||||
function Screen:scaleByDPI(px)
|
||||
return math.floor(px * self:getDPI()/167)
|
||||
return math.floor(px * self:getDPI()/167)
|
||||
end
|
||||
|
||||
function Screen:rescaleByDPI(px)
|
||||
return math.ceil(px * 167/self:getDPI())
|
||||
return math.ceil(px * 167/self:getDPI())
|
||||
end
|
||||
|
||||
function Screen:getRotationMode()
|
||||
return self.cur_rotation_mode
|
||||
return self.cur_rotation_mode
|
||||
end
|
||||
|
||||
function Screen:getScreenMode()
|
||||
if self:getWidth() > self:getHeight() then
|
||||
return "landscape"
|
||||
else
|
||||
return "portrait"
|
||||
end
|
||||
if self:getWidth() > self:getHeight() then
|
||||
return "landscape"
|
||||
else
|
||||
return "portrait"
|
||||
end
|
||||
end
|
||||
|
||||
function Screen:setRotationMode(mode)
|
||||
self.fb.bb:rotateAbsolute(-90 * (mode - self.native_rotation_mode - self.blitbuffer_rotation_mode))
|
||||
self.cur_rotation_mode = mode
|
||||
self.fb.bb:rotateAbsolute(-90 * (mode - self.native_rotation_mode - self.blitbuffer_rotation_mode))
|
||||
self.cur_rotation_mode = mode
|
||||
end
|
||||
|
||||
function Screen:setScreenMode(mode)
|
||||
if mode == "portrait" then
|
||||
if self.cur_rotation_mode ~= 0 then
|
||||
self:setRotationMode(0)
|
||||
end
|
||||
elseif mode == "landscape" then
|
||||
if self.cur_rotation_mode == 0 or self.cur_rotation_mode == 2 then
|
||||
self:setRotationMode(DLANDSCAPE_CLOCKWISE_ROTATION and 1 or 3)
|
||||
elseif self.cur_rotation_mode == 1 or self.cur_rotation_mode == 3 then
|
||||
self:setRotationMode((self.cur_rotation_mode + 2) % 4)
|
||||
end
|
||||
end
|
||||
if mode == "portrait" then
|
||||
if self.cur_rotation_mode ~= 0 then
|
||||
self:setRotationMode(0)
|
||||
end
|
||||
elseif mode == "landscape" then
|
||||
if self.cur_rotation_mode == 0 or self.cur_rotation_mode == 2 then
|
||||
self:setRotationMode(DLANDSCAPE_CLOCKWISE_ROTATION and 1 or 3)
|
||||
elseif self.cur_rotation_mode == 1 or self.cur_rotation_mode == 3 then
|
||||
self:setRotationMode((self.cur_rotation_mode + 2) % 4)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Screen:saveCurrentBB()
|
||||
local width, height = self:getWidth(), self:getHeight()
|
||||
local width, height = self:getWidth(), self:getHeight()
|
||||
|
||||
if not self.saved_bb then
|
||||
self.saved_bb = Blitbuffer.new(width, height)
|
||||
end
|
||||
if self.saved_bb:getWidth() ~= width then
|
||||
self.saved_bb:free()
|
||||
self.saved_bb = Blitbuffer.new(width, height)
|
||||
end
|
||||
self.saved_bb:blitFullFrom(self.bb)
|
||||
if not self.saved_bb then
|
||||
self.saved_bb = Blitbuffer.new(width, height)
|
||||
end
|
||||
if self.saved_bb:getWidth() ~= width then
|
||||
self.saved_bb:free()
|
||||
self.saved_bb = Blitbuffer.new(width, height)
|
||||
end
|
||||
self.saved_bb:blitFullFrom(self.bb)
|
||||
end
|
||||
|
||||
function Screen:restoreFromSavedBB()
|
||||
self:restoreFromBB(self.saved_bb)
|
||||
-- free data
|
||||
self.saved_bb = nil
|
||||
self:restoreFromBB(self.saved_bb)
|
||||
-- free data
|
||||
self.saved_bb = nil
|
||||
end
|
||||
|
||||
function Screen:getCurrentScreenBB()
|
||||
local bb = Blitbuffer.new(self:getWidth(), self:getHeight())
|
||||
bb:blitFullFrom(self.bb)
|
||||
return bb
|
||||
local bb = Blitbuffer.new(self:getWidth(), self:getHeight())
|
||||
bb:blitFullFrom(self.bb)
|
||||
return bb
|
||||
end
|
||||
|
||||
function Screen:restoreFromBB(bb)
|
||||
if bb then
|
||||
self.bb:blitFullFrom(bb)
|
||||
else
|
||||
DEBUG("Got nil bb in restoreFromSavedBB!")
|
||||
end
|
||||
if bb then
|
||||
self.bb:blitFullFrom(bb)
|
||||
else
|
||||
DEBUG("Got nil bb in restoreFromSavedBB!")
|
||||
end
|
||||
end
|
||||
|
||||
return Screen
|
||||
|
||||
@@ -10,13 +10,13 @@ below.
|
||||
local Event = {}
|
||||
|
||||
function Event:new(name, ...)
|
||||
local o = {
|
||||
handler = "on"..name,
|
||||
args = {...}
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
local o = {
|
||||
handler = "on"..name,
|
||||
args = {...}
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
return Event
|
||||
|
||||
@@ -2,102 +2,102 @@ local Screen = require("ui/screen")
|
||||
local DEBUG = require("dbg")
|
||||
|
||||
local Font = {
|
||||
fontmap = {
|
||||
-- default font for menu contents
|
||||
cfont = "droid/DroidSans.ttf",
|
||||
-- default font for title
|
||||
--tfont = "NimbusSanL-BoldItal.cff",
|
||||
tfont = "droid/DroidSans.ttf",
|
||||
-- default font for footer
|
||||
ffont = "droid/DroidSans.ttf",
|
||||
fontmap = {
|
||||
-- default font for menu contents
|
||||
cfont = "droid/DroidSans.ttf",
|
||||
-- default font for title
|
||||
--tfont = "NimbusSanL-BoldItal.cff",
|
||||
tfont = "droid/DroidSans.ttf",
|
||||
-- default font for footer
|
||||
ffont = "droid/DroidSans.ttf",
|
||||
|
||||
-- default font for reading position info
|
||||
rifont = "droid/DroidSans.ttf",
|
||||
-- default font for reading position info
|
||||
rifont = "droid/DroidSans.ttf",
|
||||
|
||||
-- default font for pagination display
|
||||
pgfont = "droid/DroidSans.ttf",
|
||||
-- default font for pagination display
|
||||
pgfont = "droid/DroidSans.ttf",
|
||||
|
||||
-- selectmenu: font for item shortcut
|
||||
scfont = "droid/DroidSansMono.ttf",
|
||||
-- selectmenu: font for item shortcut
|
||||
scfont = "droid/DroidSansMono.ttf",
|
||||
|
||||
-- help page: font for displaying keys
|
||||
hpkfont = "droid/DroidSansMono.ttf",
|
||||
-- font for displaying help messages
|
||||
hfont = "droid/DroidSans.ttf",
|
||||
-- help page: font for displaying keys
|
||||
hpkfont = "droid/DroidSansMono.ttf",
|
||||
-- font for displaying help messages
|
||||
hfont = "droid/DroidSans.ttf",
|
||||
|
||||
-- font for displaying input content
|
||||
-- we have to use mono here for better distance controlling
|
||||
infont = "droid/DroidSansMono.ttf",
|
||||
-- font for displaying input content
|
||||
-- we have to use mono here for better distance controlling
|
||||
infont = "droid/DroidSansMono.ttf",
|
||||
|
||||
-- font for info messages
|
||||
infofont = "droid/DroidSans.ttf",
|
||||
},
|
||||
fallbacks = {
|
||||
[1] = "droid/DroidSansFallback.ttf",
|
||||
[2] = "droid/DroidSans.ttf",
|
||||
[3] = "freefont/FreeSans.ttf",
|
||||
},
|
||||
-- font for info messages
|
||||
infofont = "droid/DroidSans.ttf",
|
||||
},
|
||||
fallbacks = {
|
||||
[1] = "droid/DroidSansFallback.ttf",
|
||||
[2] = "droid/DroidSans.ttf",
|
||||
[3] = "freefont/FreeSans.ttf",
|
||||
},
|
||||
|
||||
fontdir = os.getenv("FONTDIR") or "./fonts",
|
||||
fontdir = os.getenv("FONTDIR") or "./fonts",
|
||||
|
||||
-- face table
|
||||
faces = {},
|
||||
-- face table
|
||||
faces = {},
|
||||
}
|
||||
|
||||
|
||||
function Font:getFace(font, size)
|
||||
if not font then
|
||||
-- default to content font
|
||||
font = self.cfont
|
||||
end
|
||||
if not font then
|
||||
-- default to content font
|
||||
font = self.cfont
|
||||
end
|
||||
|
||||
local size = Screen:scaleByDPI(size)
|
||||
local size = Screen:scaleByDPI(size)
|
||||
|
||||
local face = self.faces[font..size]
|
||||
-- build face if not found
|
||||
if not face then
|
||||
local realname = self.fontmap[font]
|
||||
if not realname then
|
||||
realname = font
|
||||
end
|
||||
realname = self.fontdir.."/"..realname
|
||||
ok, face = pcall(freetype.newFace, realname, size)
|
||||
if not ok then
|
||||
DEBUG("#! Font "..font.." ("..realname..") not supported: "..face)
|
||||
return nil
|
||||
end
|
||||
self.faces[font..size] = face
|
||||
--DEBUG("getFace, found: "..realname.." size:"..size)
|
||||
end
|
||||
return { size = size, ftface = face, hash = font..size }
|
||||
local face = self.faces[font..size]
|
||||
-- build face if not found
|
||||
if not face then
|
||||
local realname = self.fontmap[font]
|
||||
if not realname then
|
||||
realname = font
|
||||
end
|
||||
realname = self.fontdir.."/"..realname
|
||||
ok, face = pcall(freetype.newFace, realname, size)
|
||||
if not ok then
|
||||
DEBUG("#! Font "..font.." ("..realname..") not supported: "..face)
|
||||
return nil
|
||||
end
|
||||
self.faces[font..size] = face
|
||||
--DEBUG("getFace, found: "..realname.." size:"..size)
|
||||
end
|
||||
return { size = size, ftface = face, hash = font..size }
|
||||
end
|
||||
|
||||
function Font:_readList(target, dir, effective_dir)
|
||||
for f in lfs.dir(dir) do
|
||||
if lfs.attributes(dir.."/"..f, "mode") == "directory" and f ~= "." and f ~= ".." then
|
||||
self:_readList(target, dir.."/"..f, effective_dir..f.."/")
|
||||
else
|
||||
local file_type = string.lower(string.match(f, ".+%.([^.]+)") or "")
|
||||
if file_type == "ttf" or file_type == "cff" or file_type == "otf" then
|
||||
table.insert(target, effective_dir..f)
|
||||
end
|
||||
end
|
||||
end
|
||||
for f in lfs.dir(dir) do
|
||||
if lfs.attributes(dir.."/"..f, "mode") == "directory" and f ~= "." and f ~= ".." then
|
||||
self:_readList(target, dir.."/"..f, effective_dir..f.."/")
|
||||
else
|
||||
local file_type = string.lower(string.match(f, ".+%.([^.]+)") or "")
|
||||
if file_type == "ttf" or file_type == "cff" or file_type == "otf" then
|
||||
table.insert(target, effective_dir..f)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Font:getFontList()
|
||||
fontlist = {}
|
||||
self:_readList(fontlist, self.fontdir, "")
|
||||
table.sort(fontlist)
|
||||
return fontlist
|
||||
fontlist = {}
|
||||
self:_readList(fontlist, self.fontdir, "")
|
||||
table.sort(fontlist)
|
||||
return fontlist
|
||||
end
|
||||
|
||||
function Font:update()
|
||||
for _k, _v in ipairs(self.faces) do
|
||||
_v:done()
|
||||
end
|
||||
self.faces = {}
|
||||
clearGlyphCache()
|
||||
for _k, _v in ipairs(self.faces) do
|
||||
_v:done()
|
||||
end
|
||||
self.faces = {}
|
||||
clearGlyphCache()
|
||||
end
|
||||
|
||||
return Font
|
||||
|
||||
@@ -12,48 +12,48 @@ just use it on simple tables that have x, y and/or w, h
|
||||
or define your own types using this as a metatable
|
||||
]]--
|
||||
local Geom = {
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = 0,
|
||||
h = 0
|
||||
x = 0,
|
||||
y = 0,
|
||||
w = 0,
|
||||
h = 0
|
||||
}
|
||||
|
||||
function Geom:new(o)
|
||||
local o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
local o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
function Geom:copy()
|
||||
local n = Geom:new()
|
||||
n.x = self.x
|
||||
n.y = self.y
|
||||
n.w = self.w
|
||||
n.h = self.h
|
||||
return n
|
||||
local n = Geom:new()
|
||||
n.x = self.x
|
||||
n.y = self.y
|
||||
n.w = self.w
|
||||
n.h = self.h
|
||||
return n
|
||||
end
|
||||
|
||||
function Geom:__tostring()
|
||||
return self.w.."x"..self.h.."+"..self.x.."+"..self.y
|
||||
return self.w.."x"..self.h.."+"..self.x.."+"..self.y
|
||||
end
|
||||
|
||||
--[[
|
||||
offset rectangle or point by relative values
|
||||
]]--
|
||||
function Geom:offsetBy(dx, dy)
|
||||
self.x = self.x + dx
|
||||
self.y = self.y + dy
|
||||
return self
|
||||
self.x = self.x + dx
|
||||
self.y = self.y + dy
|
||||
return self
|
||||
end
|
||||
|
||||
--[[
|
||||
offset rectangle or point to certain coordinates
|
||||
]]--
|
||||
function Geom:offsetTo(x, y)
|
||||
self.x = x
|
||||
self.y = y
|
||||
return self
|
||||
self.x = x
|
||||
self.y = y
|
||||
return self
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -62,29 +62,29 @@ scale rectangle (grow to bottom and to the right) or dimension
|
||||
if a single factor is given, it is applied to both width and height
|
||||
]]--
|
||||
function Geom:scaleBy(zx, zy)
|
||||
self.w = self.w * zx
|
||||
self.h = self.h * (zy or zx)
|
||||
return self
|
||||
self.w = self.w * zx
|
||||
self.h = self.h * (zy or zx)
|
||||
return self
|
||||
end
|
||||
|
||||
--[[
|
||||
this method also takes care of x and y
|
||||
]]--
|
||||
function Geom:transformByScale(zx, zy)
|
||||
self.x = self.x * zx
|
||||
self.y = self.y * (zx or zy)
|
||||
self:scaleBy(zx, zy)
|
||||
self.x = self.x * zx
|
||||
self.y = self.y * (zx or zy)
|
||||
self:scaleBy(zx, zy)
|
||||
end
|
||||
|
||||
--[[
|
||||
return size of geom
|
||||
]]--
|
||||
function Geom:sizeof()
|
||||
if not self.w or not self.h then
|
||||
return 0
|
||||
else
|
||||
return self.w * self.h
|
||||
end
|
||||
if not self.w or not self.h then
|
||||
return 0
|
||||
else
|
||||
return self.w * self.h
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -93,9 +93,9 @@ enlarges or shrinks dimensions or rectangles
|
||||
note that for rectangles the offset stays the same
|
||||
]]--
|
||||
function Geom:changeSizeBy(dw, dh)
|
||||
self.w = self.w + dw
|
||||
self.h = self.h + dh
|
||||
return self
|
||||
self.w = self.w + dw
|
||||
self.h = self.h + dh
|
||||
return self
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -104,25 +104,25 @@ return the outer rectangle that contains both us and a given rectangle
|
||||
works for rectangles, dimensions and points
|
||||
]]--
|
||||
function Geom:combine(rect_b)
|
||||
local combined = self:copy()
|
||||
if not rect_b or rect_b:sizeof() == 0 then return combined end
|
||||
if combined.x > rect_b.x then
|
||||
combined.x = rect_b.x
|
||||
end
|
||||
if combined.y > rect_b.y then
|
||||
combined.y = rect_b.y
|
||||
end
|
||||
if self.x + self.w > rect_b.x + rect_b.w then
|
||||
combined.w = self.x + self.w - combined.x
|
||||
else
|
||||
combined.w = rect_b.x + rect_b.w - combined.x
|
||||
end
|
||||
if self.y + self.h > rect_b.y + rect_b.h then
|
||||
combined.h = self.y + self.h - combined.y
|
||||
else
|
||||
combined.h = rect_b.y + rect_b.h - combined.y
|
||||
end
|
||||
return combined
|
||||
local combined = self:copy()
|
||||
if not rect_b or rect_b:sizeof() == 0 then return combined end
|
||||
if combined.x > rect_b.x then
|
||||
combined.x = rect_b.x
|
||||
end
|
||||
if combined.y > rect_b.y then
|
||||
combined.y = rect_b.y
|
||||
end
|
||||
if self.x + self.w > rect_b.x + rect_b.w then
|
||||
combined.w = self.x + self.w - combined.x
|
||||
else
|
||||
combined.w = rect_b.x + rect_b.w - combined.x
|
||||
end
|
||||
if self.y + self.h > rect_b.y + rect_b.h then
|
||||
combined.h = self.y + self.h - combined.y
|
||||
else
|
||||
combined.h = rect_b.y + rect_b.h - combined.y
|
||||
end
|
||||
return combined
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -131,47 +131,47 @@ returns a rectangle for the part that we and a given rectangle share
|
||||
TODO: what happens if there is no rectangle shared? currently behaviour is undefined.
|
||||
]]--
|
||||
function Geom:intersect(rect_b)
|
||||
-- make a copy of self
|
||||
local intersected = self:copy()
|
||||
if self.x < rect_b.x then
|
||||
intersected.x = rect_b.x
|
||||
end
|
||||
if self.y < rect_b.y then
|
||||
intersected.y = rect_b.y
|
||||
end
|
||||
if self.x + self.w < rect_b.x + rect_b.w then
|
||||
intersected.w = self.x + self.w - intersected.x
|
||||
else
|
||||
intersected.w = rect_b.x + rect_b.w - intersected.x
|
||||
end
|
||||
if self.y + self.h < rect_b.y + rect_b.h then
|
||||
intersected.h = self.y + self.h - intersected.y
|
||||
else
|
||||
intersected.h = rect_b.y + rect_b.h - intersected.y
|
||||
end
|
||||
return intersected
|
||||
-- make a copy of self
|
||||
local intersected = self:copy()
|
||||
if self.x < rect_b.x then
|
||||
intersected.x = rect_b.x
|
||||
end
|
||||
if self.y < rect_b.y then
|
||||
intersected.y = rect_b.y
|
||||
end
|
||||
if self.x + self.w < rect_b.x + rect_b.w then
|
||||
intersected.w = self.x + self.w - intersected.x
|
||||
else
|
||||
intersected.w = rect_b.x + rect_b.w - intersected.x
|
||||
end
|
||||
if self.y + self.h < rect_b.y + rect_b.h then
|
||||
intersected.h = self.y + self.h - intersected.y
|
||||
else
|
||||
intersected.h = rect_b.y + rect_b.h - intersected.y
|
||||
end
|
||||
return intersected
|
||||
end
|
||||
|
||||
--[[
|
||||
return true if self does not share any area with rect_b
|
||||
]]--
|
||||
function Geom:notIntersectWith(rect_b)
|
||||
if (self.x >= (rect_b.x + rect_b.w))
|
||||
or (self.y >= (rect_b.y + rect_b.h))
|
||||
or (rect_b.x >= (self.x + self.w))
|
||||
or (rect_b.y >= (self.y + self.h)) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
if (self.x >= (rect_b.x + rect_b.w))
|
||||
or (self.y >= (rect_b.y + rect_b.h))
|
||||
or (rect_b.x >= (self.x + self.w))
|
||||
or (rect_b.y >= (self.y + self.h)) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
set size of dimension or rectangle to size of given dimension/rectangle
|
||||
]]--
|
||||
function Geom:setSizeTo(rect_b)
|
||||
self.w = rect_b.w
|
||||
self.h = rect_b.h
|
||||
return self
|
||||
self.w = rect_b.w
|
||||
self.h = rect_b.h
|
||||
return self
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -181,14 +181,14 @@ works for dimensions, too
|
||||
for points, it is basically an equality check
|
||||
]]--
|
||||
function Geom:contains(rect_b)
|
||||
if self.x <= rect_b.x
|
||||
and self.y <= rect_b.y
|
||||
and self.x + self.w >= rect_b.x + rect_b.w
|
||||
and self.y + self.h >= rect_b.y + rect_b.h
|
||||
then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
if self.x <= rect_b.x
|
||||
and self.y <= rect_b.y
|
||||
and self.x + self.w >= rect_b.x + rect_b.w
|
||||
and self.y + self.h >= rect_b.y + rect_b.h
|
||||
then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -197,48 +197,48 @@ check for equality
|
||||
works for rectangles, points, dimensions
|
||||
]]--
|
||||
function Geom:__eq(rect_b)
|
||||
if self.x == rect_b.x
|
||||
and self.y == rect_b.y
|
||||
and self:equalSize(rect_b)
|
||||
then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
if self.x == rect_b.x
|
||||
and self.y == rect_b.y
|
||||
and self:equalSize(rect_b)
|
||||
then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
check size of dimension/rectangle for equality
|
||||
]]--
|
||||
function Geom:equalSize(rect_b)
|
||||
if self.w == rect_b.w
|
||||
and self.h == rect_b.h
|
||||
then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
if self.w == rect_b.w
|
||||
and self.h == rect_b.h
|
||||
then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
check if our size is smaller than the size of the given dimension/rectangle
|
||||
]]--
|
||||
function Geom:__lt(rect_b)
|
||||
DEBUG("lt:",self,rect_b)
|
||||
if self.w < rect_b.w and self.h < rect_b.h then
|
||||
DEBUG("lt:",self,rect_b)
|
||||
if self.w < rect_b.w and self.h < rect_b.h then
|
||||
DEBUG("lt+")
|
||||
return true
|
||||
end
|
||||
return true
|
||||
end
|
||||
DEBUG("lt-")
|
||||
return false
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
check if our size is smaller or equal the size of the given dimension/rectangle
|
||||
]]--
|
||||
function Geom:__le(rect_b)
|
||||
if self.w <= rect_b.w and self.h <= rect_b.h then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
if self.w <= rect_b.w and self.h <= rect_b.h then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -249,92 +249,92 @@ this can also be called with dx=0 and dy=0, which will fit the current
|
||||
rectangle into the given rectangle
|
||||
]]--
|
||||
function Geom:offsetWithin(rect_b, dx, dy)
|
||||
-- check size constraints and shrink us when we're too big
|
||||
if self.w > rect_b.w then
|
||||
self.w = rect_b.w
|
||||
end
|
||||
if self.h > rect_b.h then
|
||||
self.h = rect_b.h
|
||||
end
|
||||
-- offset
|
||||
self.x = self.x + dx
|
||||
self.y = self.y + dy
|
||||
-- check offsets
|
||||
if self.x < rect_b.x then
|
||||
self.x = rect_b.x
|
||||
end
|
||||
if self.y < rect_b.y then
|
||||
self.y = rect_b.y
|
||||
end
|
||||
if self.x + self.w > rect_b.x + rect_b.w then
|
||||
self.x = rect_b.x + rect_b.w - self.w
|
||||
end
|
||||
if self.y + self.h > rect_b.y + rect_b.h then
|
||||
self.y = rect_b.y + rect_b.h - self.h
|
||||
end
|
||||
-- check size constraints and shrink us when we're too big
|
||||
if self.w > rect_b.w then
|
||||
self.w = rect_b.w
|
||||
end
|
||||
if self.h > rect_b.h then
|
||||
self.h = rect_b.h
|
||||
end
|
||||
-- offset
|
||||
self.x = self.x + dx
|
||||
self.y = self.y + dy
|
||||
-- check offsets
|
||||
if self.x < rect_b.x then
|
||||
self.x = rect_b.x
|
||||
end
|
||||
if self.y < rect_b.y then
|
||||
self.y = rect_b.y
|
||||
end
|
||||
if self.x + self.w > rect_b.x + rect_b.w then
|
||||
self.x = rect_b.x + rect_b.w - self.w
|
||||
end
|
||||
if self.y + self.h > rect_b.y + rect_b.h then
|
||||
self.y = rect_b.y + rect_b.h - self.h
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
center the current rectangle at position x and y of a given rectangle
|
||||
]]--
|
||||
function Geom:centerWithin(rect_b, x, y)
|
||||
-- check size constraints and shrink us when we're too big
|
||||
if self.w > rect_b.w then
|
||||
self.w = rect_b.w
|
||||
end
|
||||
if self.h > rect_b.h then
|
||||
self.h = rect_b.h
|
||||
end
|
||||
-- place to center
|
||||
self.x = x - self.w/2
|
||||
self.y = y - self.h/2
|
||||
-- check boundary
|
||||
if self.x < rect_b.x then
|
||||
self.x = rect_b.x
|
||||
end
|
||||
if self.y < rect_b.y then
|
||||
self.y = rect_b.y
|
||||
end
|
||||
if self.x + self.w > rect_b.x + rect_b.w then
|
||||
self.x = rect_b.x + rect_b.w - self.w
|
||||
end
|
||||
if self.y + self.h > rect_b.y + rect_b.h then
|
||||
self.y = rect_b.y + rect_b.h - self.h
|
||||
end
|
||||
-- check size constraints and shrink us when we're too big
|
||||
if self.w > rect_b.w then
|
||||
self.w = rect_b.w
|
||||
end
|
||||
if self.h > rect_b.h then
|
||||
self.h = rect_b.h
|
||||
end
|
||||
-- place to center
|
||||
self.x = x - self.w/2
|
||||
self.y = y - self.h/2
|
||||
-- check boundary
|
||||
if self.x < rect_b.x then
|
||||
self.x = rect_b.x
|
||||
end
|
||||
if self.y < rect_b.y then
|
||||
self.y = rect_b.y
|
||||
end
|
||||
if self.x + self.w > rect_b.x + rect_b.w then
|
||||
self.x = rect_b.x + rect_b.w - self.w
|
||||
end
|
||||
if self.y + self.h > rect_b.y + rect_b.h then
|
||||
self.y = rect_b.y + rect_b.h - self.h
|
||||
end
|
||||
end
|
||||
|
||||
function Geom:shrinkInside(rect_b, dx, dy)
|
||||
self:offsetBy(dx, dy)
|
||||
return self:intersect(rect_b)
|
||||
self:offsetBy(dx, dy)
|
||||
return self:intersect(rect_b)
|
||||
end
|
||||
|
||||
--[[
|
||||
return the Euclidean distance between two geoms
|
||||
]]--
|
||||
function Geom:distance(geom)
|
||||
return math.sqrt(math.pow(self.x - geom.x, 2) + math.pow(self.y - geom.y, 2))
|
||||
return math.sqrt(math.pow(self.x - geom.x, 2) + math.pow(self.y - geom.y, 2))
|
||||
end
|
||||
|
||||
--[[
|
||||
return the midpoint of two geoms
|
||||
]]--
|
||||
function Geom:midpoint(geom)
|
||||
return Geom:new{
|
||||
x = (self.x + geom.x) / 2,
|
||||
y = (self.y + geom.y) / 2,
|
||||
w = 0, h = 0,
|
||||
}
|
||||
return Geom:new{
|
||||
x = (self.x + geom.x) / 2,
|
||||
y = (self.y + geom.y) / 2,
|
||||
w = 0, h = 0,
|
||||
}
|
||||
end
|
||||
|
||||
--[[
|
||||
return center point in this geom
|
||||
]]--
|
||||
function Geom:center()
|
||||
return Geom:new{
|
||||
x = self.x + self.w / 2,
|
||||
y = self.y + self.h / 2,
|
||||
w = 0, h = 0,
|
||||
}
|
||||
return Geom:new{
|
||||
x = self.x + self.w / 2,
|
||||
y = self.y + self.h / 2,
|
||||
w = 0, h = 0,
|
||||
}
|
||||
end
|
||||
|
||||
return Geom
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,50 +1,50 @@
|
||||
local TimeVal = require("ui/timeval")
|
||||
|
||||
local GestureRange = {
|
||||
ges = nil,
|
||||
-- spatial range limits the gesture emitting position
|
||||
range = nil,
|
||||
-- temproal range limits the gesture emitting rate
|
||||
rate = nil,
|
||||
-- span limits of this gesture
|
||||
scale = nil,
|
||||
ges = nil,
|
||||
-- spatial range limits the gesture emitting position
|
||||
range = nil,
|
||||
-- temproal range limits the gesture emitting rate
|
||||
rate = nil,
|
||||
-- span limits of this gesture
|
||||
scale = nil,
|
||||
}
|
||||
|
||||
function GestureRange:new(o)
|
||||
local o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
local o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
function GestureRange:match(gs)
|
||||
if gs.ges ~= self.ges then
|
||||
return false
|
||||
end
|
||||
if self.range then
|
||||
if not self.range:contains(gs.pos) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
if self.rate then
|
||||
local last_time = self.last_time or TimeVal:new{}
|
||||
if gs.time - last_time > TimeVal:new{usec = 1000000 / self.rate} then
|
||||
self.last_time = gs.time
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
if self.scale then
|
||||
if self.scale[1] > gs.span or self.scale[2] < gs.span then
|
||||
return false
|
||||
end
|
||||
end
|
||||
if self.direction then
|
||||
if self.direction ~= gs.direction then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
if gs.ges ~= self.ges then
|
||||
return false
|
||||
end
|
||||
if self.range then
|
||||
if not self.range:contains(gs.pos) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
if self.rate then
|
||||
local last_time = self.last_time or TimeVal:new{}
|
||||
if gs.time - last_time > TimeVal:new{usec = 1000000 / self.rate} then
|
||||
self.last_time = gs.time
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
if self.scale then
|
||||
if self.scale[1] > gs.span or self.scale[2] < gs.span then
|
||||
return false
|
||||
end
|
||||
end
|
||||
if self.direction then
|
||||
if self.direction ~= gs.direction then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
return GestureRange
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,47 +7,47 @@ local _ = require("gettext")
|
||||
Language = {}
|
||||
|
||||
function Language:changeLanguage(lang_locale)
|
||||
_.changeLang(lang_locale)
|
||||
G_reader_settings:saveSetting("language", lang_locale)
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Please restart reader for new language setting to take effect."),
|
||||
timeout = 3,
|
||||
})
|
||||
_.changeLang(lang_locale)
|
||||
G_reader_settings:saveSetting("language", lang_locale)
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Please restart reader for new language setting to take effect."),
|
||||
timeout = 3,
|
||||
})
|
||||
end
|
||||
|
||||
function Language:genLanguageSubItem(lang, lang_locale)
|
||||
return {
|
||||
text = lang,
|
||||
callback = function()
|
||||
self:changeLanguage(lang_locale)
|
||||
end
|
||||
}
|
||||
return {
|
||||
text = lang,
|
||||
callback = function()
|
||||
self:changeLanguage(lang_locale)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
function Language:getLangMenuTable()
|
||||
-- cache menu table
|
||||
if not self.LangMenuTable then
|
||||
self.LangMenuTable = {
|
||||
text = _("Language"),
|
||||
-- NOTE: language with no translation are commented out for now
|
||||
sub_item_table = {
|
||||
self:genLanguageSubItem("English", "C"),
|
||||
self:genLanguageSubItem("čeština", "cs_CZ"),
|
||||
self:genLanguageSubItem("Deutsch", "de"),
|
||||
self:genLanguageSubItem("français", "fr"),
|
||||
--self:genLanguageSubItem("magyar", "hu"),
|
||||
self:genLanguageSubItem("Italiano", "it_IT"),
|
||||
self:genLanguageSubItem("Polski", "pl"),
|
||||
self:genLanguageSubItem("Português do Brasil", "pt_BR"),
|
||||
self:genLanguageSubItem("Русский язык", "ru"),
|
||||
--self:genLanguageSubItem("svenska", "sv"),
|
||||
self:genLanguageSubItem("Türkçe", "tr"),
|
||||
--self:genLanguageSubItem("Tiếng Việt", "vi"),
|
||||
self:genLanguageSubItem("简体中文", "zh_CN"),
|
||||
}
|
||||
}
|
||||
end
|
||||
return self.LangMenuTable
|
||||
-- cache menu table
|
||||
if not self.LangMenuTable then
|
||||
self.LangMenuTable = {
|
||||
text = _("Language"),
|
||||
-- NOTE: language with no translation are commented out for now
|
||||
sub_item_table = {
|
||||
self:genLanguageSubItem("English", "C"),
|
||||
self:genLanguageSubItem("čeština", "cs_CZ"),
|
||||
self:genLanguageSubItem("Deutsch", "de"),
|
||||
self:genLanguageSubItem("français", "fr"),
|
||||
--self:genLanguageSubItem("magyar", "hu"),
|
||||
self:genLanguageSubItem("Italiano", "it_IT"),
|
||||
self:genLanguageSubItem("Polski", "pl"),
|
||||
self:genLanguageSubItem("Português do Brasil", "pt_BR"),
|
||||
self:genLanguageSubItem("Русский язык", "ru"),
|
||||
--self:genLanguageSubItem("svenska", "sv"),
|
||||
self:genLanguageSubItem("Türkçe", "tr"),
|
||||
--self:genLanguageSubItem("Tiếng Việt", "vi"),
|
||||
self:genLanguageSubItem("简体中文", "zh_CN"),
|
||||
}
|
||||
}
|
||||
end
|
||||
return self.LangMenuTable
|
||||
end
|
||||
|
||||
return Language
|
||||
|
||||
@@ -5,43 +5,43 @@ local Device = require("ui/device")
|
||||
local ReaderActivityIndicator = EventListener:new{}
|
||||
|
||||
function ReaderActivityIndicator:init()
|
||||
local dev_mod = Device:getModel()
|
||||
if dev_mod == "KindlePaperWhite" or dev_mod == "KindlePaperWhite2" or dev_mod == "KindleTouch" then
|
||||
require "liblipclua"
|
||||
self.lipc_handle = lipc.init("com.github.koreader.activityindicator")
|
||||
end
|
||||
local dev_mod = Device:getModel()
|
||||
if dev_mod == "KindlePaperWhite" or dev_mod == "KindlePaperWhite2" or dev_mod == "KindleTouch" then
|
||||
require "liblipclua"
|
||||
self.lipc_handle = lipc.init("com.github.koreader.activityindicator")
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderActivityIndicator:onStartActivityIndicator()
|
||||
if self.lipc_handle then
|
||||
-- check if activity indicator is needed
|
||||
if self.document.configurable.text_wrap == 1 then
|
||||
-- start indicator depends on pillow being enabled
|
||||
self.lipc_handle:set_string_property(
|
||||
"com.lab126.pillow", "activityIndicator",
|
||||
'{"activityIndicator":{ \
|
||||
"action":"start","timeout":10000, \
|
||||
"clientId":"com.github.koreader.activityindicator", \
|
||||
"priority":true}}')
|
||||
self.indicator_started = true
|
||||
end
|
||||
end
|
||||
return true
|
||||
function ReaderActivityIndicator:onStartActivityIndicator()
|
||||
if self.lipc_handle then
|
||||
-- check if activity indicator is needed
|
||||
if self.document.configurable.text_wrap == 1 then
|
||||
-- start indicator depends on pillow being enabled
|
||||
self.lipc_handle:set_string_property(
|
||||
"com.lab126.pillow", "activityIndicator",
|
||||
'{"activityIndicator":{ \
|
||||
"action":"start","timeout":10000, \
|
||||
"clientId":"com.github.koreader.activityindicator", \
|
||||
"priority":true}}')
|
||||
self.indicator_started = true
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderActivityIndicator:onStopActivityIndicator()
|
||||
if self.lipc_handle and self.indicator_started then
|
||||
-- stop indicator depends on pillow being enabled
|
||||
self.lipc_handle:set_string_property(
|
||||
"com.lab126.pillow", "activityIndicator",
|
||||
'{"activityIndicator":{ \
|
||||
"action":"stop","timeout":10000, \
|
||||
"clientId":"com.github.koreader.activityindicator", \
|
||||
"priority":true}}')
|
||||
self.indicator_started = false
|
||||
util.usleep(1000000)
|
||||
end
|
||||
return true
|
||||
if self.lipc_handle and self.indicator_started then
|
||||
-- stop indicator depends on pillow being enabled
|
||||
self.lipc_handle:set_string_property(
|
||||
"com.lab126.pillow", "activityIndicator",
|
||||
'{"activityIndicator":{ \
|
||||
"action":"stop","timeout":10000, \
|
||||
"clientId":"com.github.koreader.activityindicator", \
|
||||
"priority":true}}')
|
||||
self.indicator_started = false
|
||||
util.usleep(1000000)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
return ReaderActivityIndicator
|
||||
|
||||
@@ -11,218 +11,218 @@ local DEBUG = require("dbg")
|
||||
local _ = require("gettext")
|
||||
|
||||
local ReaderBookmark = InputContainer:new{
|
||||
bm_menu_title = _("Bookmarks"),
|
||||
bookmarks = nil,
|
||||
bm_menu_title = _("Bookmarks"),
|
||||
bookmarks = nil,
|
||||
}
|
||||
|
||||
function ReaderBookmark:init()
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ShowBookmark = {
|
||||
{ "B" },
|
||||
doc = _("show bookmarks") },
|
||||
}
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
ShowBookmark = {
|
||||
GestureRange:new{
|
||||
ges = "two_finger_swipe",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
},
|
||||
direction = "west"
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ShowBookmark = {
|
||||
{ "B" },
|
||||
doc = _("show bookmarks") },
|
||||
}
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
ShowBookmark = {
|
||||
GestureRange:new{
|
||||
ges = "two_finger_swipe",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
},
|
||||
direction = "west"
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function ReaderBookmark:onReadSettings(config)
|
||||
self.bookmarks = config:readSetting("bookmarks") or {}
|
||||
self.bookmarks = config:readSetting("bookmarks") or {}
|
||||
end
|
||||
|
||||
function ReaderBookmark:onSaveSettings()
|
||||
self.ui.doc_settings:saveSetting("bookmarks", self.bookmarks)
|
||||
self.ui.doc_settings:saveSetting("bookmarks", self.bookmarks)
|
||||
end
|
||||
|
||||
function ReaderBookmark:onToggleBookmark()
|
||||
local pn_or_xp = nil
|
||||
if self.ui.document.info.has_pages then
|
||||
pn_or_xp = self.view.state.page
|
||||
else
|
||||
pn_or_xp = self.ui.document:getXPointer()
|
||||
end
|
||||
self:toggleBookmark(pn_or_xp)
|
||||
self.view.dogear_visible = not self.view.dogear_visible
|
||||
UIManager:setDirty(self.view.dialog, "partial")
|
||||
return true
|
||||
local pn_or_xp = nil
|
||||
if self.ui.document.info.has_pages then
|
||||
pn_or_xp = self.view.state.page
|
||||
else
|
||||
pn_or_xp = self.ui.document:getXPointer()
|
||||
end
|
||||
self:toggleBookmark(pn_or_xp)
|
||||
self.view.dogear_visible = not self.view.dogear_visible
|
||||
UIManager:setDirty(self.view.dialog, "partial")
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderBookmark:setDogearVisibility(pn_or_xp)
|
||||
if self:isBookmarked(pn_or_xp) then
|
||||
self.ui:handleEvent(Event:new("SetDogearVisibility", true))
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetDogearVisibility", false))
|
||||
end
|
||||
if self:isBookmarked(pn_or_xp) then
|
||||
self.ui:handleEvent(Event:new("SetDogearVisibility", true))
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetDogearVisibility", false))
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderBookmark:onPageUpdate(pageno)
|
||||
if self.ui.document.info.has_pages then
|
||||
self:setDogearVisibility(pageno)
|
||||
else
|
||||
-- FIXME: this is a dirty hack to prevent crash in isXPointerInCurrentPage
|
||||
if pageno ~= 1 then
|
||||
self:setDogearVisibility("dummy")
|
||||
end
|
||||
end
|
||||
if self.ui.document.info.has_pages then
|
||||
self:setDogearVisibility(pageno)
|
||||
else
|
||||
-- FIXME: this is a dirty hack to prevent crash in isXPointerInCurrentPage
|
||||
if pageno ~= 1 then
|
||||
self:setDogearVisibility("dummy")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderBookmark:onPosUpdate(pos)
|
||||
self:setDogearVisibility("dummy")
|
||||
self:setDogearVisibility("dummy")
|
||||
end
|
||||
|
||||
function ReaderBookmark:onShowBookmark()
|
||||
-- build up item_table
|
||||
for k, v in ipairs(self.bookmarks) do
|
||||
local page = v.page
|
||||
-- for CREngine, bookmark page is xpointer
|
||||
if type(page) == "string" then
|
||||
page = self.ui.document:getPageFromXPointer(v.page)
|
||||
end
|
||||
v.text = "Page "..page.." "..v.notes.." @ "..v.datetime
|
||||
end
|
||||
|
||||
local menu_container = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
}
|
||||
-- build up item_table
|
||||
for k, v in ipairs(self.bookmarks) do
|
||||
local page = v.page
|
||||
-- for CREngine, bookmark page is xpointer
|
||||
if type(page) == "string" then
|
||||
page = self.ui.document:getPageFromXPointer(v.page)
|
||||
end
|
||||
v.text = "Page "..page.." "..v.notes.." @ "..v.datetime
|
||||
end
|
||||
|
||||
local menu_container = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
}
|
||||
|
||||
local bm_menu = Menu:new{
|
||||
title = "Bookmarks",
|
||||
item_table = self.bookmarks,
|
||||
width = Screen:getWidth()-50,
|
||||
height = Screen:getHeight()-50,
|
||||
show_parent = menu_container,
|
||||
}
|
||||
|
||||
table.insert(menu_container, bm_menu)
|
||||
|
||||
-- buid up menu widget method as closure
|
||||
local doc = self.ui.document
|
||||
local view = self.view
|
||||
local sendEv = function(ev)
|
||||
self.ui:handleEvent(ev)
|
||||
end
|
||||
function bm_menu:onMenuChoice(item)
|
||||
if doc.info.has_pages then
|
||||
sendEv(Event:new("PageUpdate", item.page))
|
||||
elseif view.view_mode == "page" then
|
||||
sendEv(Event:new("PageUpdate", doc:getPageFromXPointer(item.page)))
|
||||
else
|
||||
sendEv(Event:new("PosUpdate", doc:getPosFromXPointer(item.page)))
|
||||
end
|
||||
end
|
||||
local bm_menu = Menu:new{
|
||||
title = "Bookmarks",
|
||||
item_table = self.bookmarks,
|
||||
width = Screen:getWidth()-50,
|
||||
height = Screen:getHeight()-50,
|
||||
show_parent = menu_container,
|
||||
}
|
||||
|
||||
table.insert(menu_container, bm_menu)
|
||||
|
||||
-- buid up menu widget method as closure
|
||||
local doc = self.ui.document
|
||||
local view = self.view
|
||||
local sendEv = function(ev)
|
||||
self.ui:handleEvent(ev)
|
||||
end
|
||||
function bm_menu:onMenuChoice(item)
|
||||
if doc.info.has_pages then
|
||||
sendEv(Event:new("PageUpdate", item.page))
|
||||
elseif view.view_mode == "page" then
|
||||
sendEv(Event:new("PageUpdate", doc:getPageFromXPointer(item.page)))
|
||||
else
|
||||
sendEv(Event:new("PosUpdate", doc:getPosFromXPointer(item.page)))
|
||||
end
|
||||
end
|
||||
|
||||
bm_menu.close_callback = function()
|
||||
UIManager:close(menu_container)
|
||||
end
|
||||
bm_menu.close_callback = function()
|
||||
UIManager:close(menu_container)
|
||||
end
|
||||
|
||||
UIManager:show(menu_container)
|
||||
return true
|
||||
UIManager:show(menu_container)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderBookmark:addToMainMenu(tab_item_table)
|
||||
-- insert table to main reader menu
|
||||
table.insert(tab_item_table.navi, {
|
||||
text = self.bm_menu_title,
|
||||
callback = function()
|
||||
self:onShowBookmark()
|
||||
end,
|
||||
})
|
||||
-- insert table to main reader menu
|
||||
table.insert(tab_item_table.navi, {
|
||||
text = self.bm_menu_title,
|
||||
callback = function()
|
||||
self:onShowBookmark()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
function ReaderBookmark:isBookmarked(pn_or_xp)
|
||||
for k,v in ipairs(self.bookmarks) do
|
||||
if (type(pn_or_xp) == "number" and v.page == pn_or_xp) or
|
||||
(type(pn_or_xp) == "string" and self.ui.document:isXPointerInCurrentPage(v.page)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
for k,v in ipairs(self.bookmarks) do
|
||||
if (type(pn_or_xp) == "number" and v.page == pn_or_xp) or
|
||||
(type(pn_or_xp) == "string" and self.ui.document:isXPointerInCurrentPage(v.page)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function ReaderBookmark:addBookmark(pn_or_xp)
|
||||
-- build notes from TOC
|
||||
local notes = self.ui.toc:getTocTitleByPage(pn_or_xp)
|
||||
if notes ~= "" then
|
||||
notes = "in "..notes
|
||||
end
|
||||
mark_item = {
|
||||
page = pn_or_xp,
|
||||
datetime = os.date("%Y-%m-%d %H:%M:%S"),
|
||||
notes = notes,
|
||||
}
|
||||
table.insert(self.bookmarks, mark_item)
|
||||
table.sort(self.bookmarks, function(a,b)
|
||||
return self:isBookmarkInSequence(a, b)
|
||||
end)
|
||||
return true
|
||||
-- build notes from TOC
|
||||
local notes = self.ui.toc:getTocTitleByPage(pn_or_xp)
|
||||
if notes ~= "" then
|
||||
notes = "in "..notes
|
||||
end
|
||||
mark_item = {
|
||||
page = pn_or_xp,
|
||||
datetime = os.date("%Y-%m-%d %H:%M:%S"),
|
||||
notes = notes,
|
||||
}
|
||||
table.insert(self.bookmarks, mark_item)
|
||||
table.sort(self.bookmarks, function(a,b)
|
||||
return self:isBookmarkInSequence(a, b)
|
||||
end)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderBookmark:isBookmarkInSequence(a, b)
|
||||
return a.page < b.page
|
||||
return a.page < b.page
|
||||
end
|
||||
|
||||
function ReaderBookmark:toggleBookmark(pn_or_xp)
|
||||
for k,v in ipairs(self.bookmarks) do
|
||||
if (type(pn_or_xp) == "number" and v.page == pn_or_xp) or
|
||||
(type(pn_or_xp) == "string" and self.ui.document:isXPointerInCurrentPage(v.page)) then
|
||||
table.remove(self.bookmarks, k)
|
||||
return
|
||||
end
|
||||
end
|
||||
self:addBookmark(pn_or_xp)
|
||||
for k,v in ipairs(self.bookmarks) do
|
||||
if (type(pn_or_xp) == "number" and v.page == pn_or_xp) or
|
||||
(type(pn_or_xp) == "string" and self.ui.document:isXPointerInCurrentPage(v.page)) then
|
||||
table.remove(self.bookmarks, k)
|
||||
return
|
||||
end
|
||||
end
|
||||
self:addBookmark(pn_or_xp)
|
||||
end
|
||||
|
||||
function ReaderBookmark:getPreviousBookmarkedPage(pn_or_xp)
|
||||
for i = #self.bookmarks, 1, -1 do
|
||||
if pn_or_xp > self.bookmarks[i].page then
|
||||
return self.bookmarks[i].page
|
||||
end
|
||||
end
|
||||
for i = #self.bookmarks, 1, -1 do
|
||||
if pn_or_xp > self.bookmarks[i].page then
|
||||
return self.bookmarks[i].page
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderBookmark:getNextBookmarkedPage(pn_or_xp)
|
||||
for i = 1, #self.bookmarks do
|
||||
if pn_or_xp < self.bookmarks[i].page then
|
||||
return self.bookmarks[i].page
|
||||
end
|
||||
end
|
||||
for i = 1, #self.bookmarks do
|
||||
if pn_or_xp < self.bookmarks[i].page then
|
||||
return self.bookmarks[i].page
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderBookmark:onGotoPreviousBookmark(pn_or_xp)
|
||||
self:GotoBookmark(self:getPreviousBookmarkedPage(pn_or_xp))
|
||||
return true
|
||||
self:GotoBookmark(self:getPreviousBookmarkedPage(pn_or_xp))
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderBookmark:onGotoNextBookmark(pn_or_xp)
|
||||
self:GotoBookmark(self:getNextBookmarkedPage(pn_or_xp))
|
||||
return true
|
||||
self:GotoBookmark(self:getNextBookmarkedPage(pn_or_xp))
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderBookmark:GotoBookmark(pn_or_xp)
|
||||
if type(pn_or_xp) == "string" then
|
||||
if self.view.view_mode == "page" then
|
||||
self.ui:handleEvent(Event:new("PageUpdate", self.ui.document:getPageFromXPointer(pn_or_xp)))
|
||||
else
|
||||
self.ui:handleEvent(Event:new("PosUpdate", self.ui.document:getPosFromXPointer(pn_or_xp)))
|
||||
end
|
||||
elseif type(pn_or_xp) == "number" then
|
||||
self.ui:handleEvent(Event:new("PageUpdate", pn_or_xp))
|
||||
end
|
||||
if type(pn_or_xp) == "string" then
|
||||
if self.view.view_mode == "page" then
|
||||
self.ui:handleEvent(Event:new("PageUpdate", self.ui.document:getPageFromXPointer(pn_or_xp)))
|
||||
else
|
||||
self.ui:handleEvent(Event:new("PosUpdate", self.ui.document:getPosFromXPointer(pn_or_xp)))
|
||||
end
|
||||
elseif type(pn_or_xp) == "number" then
|
||||
self.ui:handleEvent(Event:new("PageUpdate", pn_or_xp))
|
||||
end
|
||||
end
|
||||
|
||||
return ReaderBookmark
|
||||
|
||||
@@ -9,87 +9,87 @@ local UIManager = require("ui/uimanager")
|
||||
local _ = require("gettext")
|
||||
|
||||
local ReaderConfig = InputContainer:new{
|
||||
last_panel_index = 1,
|
||||
last_panel_index = 1,
|
||||
}
|
||||
|
||||
function ReaderConfig:init()
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ShowConfigMenu = { { "AA" }, doc = _("show config dialog") },
|
||||
}
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ShowConfigMenu = { { "AA" }, doc = _("show config dialog") },
|
||||
}
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderConfig:initGesListener()
|
||||
self.ges_events = {
|
||||
TapShowConfigMenu = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = Screen:getWidth()*DTAP_ZONE_CONFIG.x,
|
||||
y = Screen:getHeight()*DTAP_ZONE_CONFIG.y,
|
||||
w = Screen:getWidth()*DTAP_ZONE_CONFIG.w,
|
||||
h = Screen:getHeight()*DTAP_ZONE_CONFIG.h,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.ges_events = {
|
||||
TapShowConfigMenu = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = Screen:getWidth()*DTAP_ZONE_CONFIG.x,
|
||||
y = Screen:getHeight()*DTAP_ZONE_CONFIG.y,
|
||||
w = Screen:getWidth()*DTAP_ZONE_CONFIG.w,
|
||||
h = Screen:getHeight()*DTAP_ZONE_CONFIG.h,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function ReaderConfig:onShowConfigMenu()
|
||||
self.config_dialog = ConfigDialog:new{
|
||||
dimen = self.dimen:copy(),
|
||||
ui = self.ui,
|
||||
configurable = self.configurable,
|
||||
config_options = self.options,
|
||||
is_always_active = true,
|
||||
close_callback = function() self:onCloseCallback() end,
|
||||
}
|
||||
self.ui:handleEvent(Event:new("DisableHinting"))
|
||||
-- show last used panel when opening config dialog
|
||||
self.config_dialog:onShowConfigPanel(self.last_panel_index)
|
||||
UIManager:show(self.config_dialog)
|
||||
self.config_dialog = ConfigDialog:new{
|
||||
dimen = self.dimen:copy(),
|
||||
ui = self.ui,
|
||||
configurable = self.configurable,
|
||||
config_options = self.options,
|
||||
is_always_active = true,
|
||||
close_callback = function() self:onCloseCallback() end,
|
||||
}
|
||||
self.ui:handleEvent(Event:new("DisableHinting"))
|
||||
-- show last used panel when opening config dialog
|
||||
self.config_dialog:onShowConfigPanel(self.last_panel_index)
|
||||
UIManager:show(self.config_dialog)
|
||||
|
||||
return true
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderConfig:onTapShowConfigMenu()
|
||||
self:onShowConfigMenu()
|
||||
return true
|
||||
self:onShowConfigMenu()
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderConfig:onSetDimensions(dimen)
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
-- since we cannot redraw config_dialog with new size, we close
|
||||
-- the old one on screen size change
|
||||
if self.config_dialog then
|
||||
self.config_dialog:closeDialog()
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
-- since we cannot redraw config_dialog with new size, we close
|
||||
-- the old one on screen size change
|
||||
if self.config_dialog then
|
||||
self.config_dialog:closeDialog()
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderConfig:onCloseCallback()
|
||||
self.last_panel_index = self.config_dialog.panel_index
|
||||
self.ui:handleEvent(Event:new("RestoreHinting"))
|
||||
self.last_panel_index = self.config_dialog.panel_index
|
||||
self.ui:handleEvent(Event:new("RestoreHinting"))
|
||||
end
|
||||
|
||||
-- event handler for readercropping
|
||||
function ReaderConfig:onCloseConfig()
|
||||
self.config_dialog:closeDialog()
|
||||
self.config_dialog:closeDialog()
|
||||
end
|
||||
|
||||
function ReaderConfig:onReadSettings(config)
|
||||
self.configurable:loadSettings(config, self.options.prefix.."_")
|
||||
self.last_panel_index = config:readSetting("config_panel_index") or 1
|
||||
self.configurable:loadSettings(config, self.options.prefix.."_")
|
||||
self.last_panel_index = config:readSetting("config_panel_index") or 1
|
||||
end
|
||||
|
||||
function ReaderConfig:onSaveSettings()
|
||||
self.configurable:saveSettings(self.ui.doc_settings, self.options.prefix.."_")
|
||||
self.ui.doc_settings:saveSetting("config_panel_index", self.last_panel_index)
|
||||
self.configurable:saveSettings(self.ui.doc_settings, self.options.prefix.."_")
|
||||
self.ui.doc_settings:saveSetting("config_panel_index", self.last_panel_index)
|
||||
end
|
||||
|
||||
return ReaderConfig
|
||||
|
||||
@@ -4,29 +4,29 @@ local Event = require("ui/event")
|
||||
local ReaderCoptListener = EventListener:new{}
|
||||
|
||||
function ReaderCoptListener:onReadSettings(config)
|
||||
local embedded_css = config:readSetting("copt_embedded_css")
|
||||
local toggle_embedded_css = embedded_css == 0 and false or true
|
||||
table.insert(self.ui.postInitCallback, function()
|
||||
local embedded_css = config:readSetting("copt_embedded_css")
|
||||
local toggle_embedded_css = embedded_css == 0 and false or true
|
||||
table.insert(self.ui.postInitCallback, function()
|
||||
self.ui:handleEvent(Event:new("ToggleEmbeddedStyleSheet", toggle_embedded_css))
|
||||
end)
|
||||
|
||||
local view_mode = config:readSetting("copt_view_mode")
|
||||
if view_mode == 0 then
|
||||
table.insert(self.ui.postInitCallback, function()
|
||||
self.ui:handleEvent(Event:new("SetViewMode", "page"))
|
||||
end)
|
||||
elseif view_mode == 1 then
|
||||
table.insert(self.ui.postInitCallback, function()
|
||||
self.ui:handleEvent(Event:new("SetViewMode", "scroll"))
|
||||
end)
|
||||
end
|
||||
|
||||
local status_line = config:readSetting("copt_status_line") or DCREREADER_PROGRESS_BAR
|
||||
self.document:setStatusLineProp(status_line)
|
||||
|
||||
local view_mode = config:readSetting("copt_view_mode")
|
||||
if view_mode == 0 then
|
||||
table.insert(self.ui.postInitCallback, function()
|
||||
self.ui:handleEvent(Event:new("SetViewMode", "page"))
|
||||
end)
|
||||
elseif view_mode == 1 then
|
||||
table.insert(self.ui.postInitCallback, function()
|
||||
self.ui:handleEvent(Event:new("SetViewMode", "scroll"))
|
||||
end)
|
||||
end
|
||||
|
||||
local status_line = config:readSetting("copt_status_line") or DCREREADER_PROGRESS_BAR
|
||||
self.document:setStatusLineProp(status_line)
|
||||
end
|
||||
|
||||
function ReaderCoptListener:onSetFontSize(font_size)
|
||||
self.document.configurable.font_size = font_size
|
||||
self.document.configurable.font_size = font_size
|
||||
end
|
||||
|
||||
return ReaderCoptListener
|
||||
|
||||
@@ -15,149 +15,149 @@ local Math = require("optmath")
|
||||
local DEBUG = require("dbg")
|
||||
|
||||
local PageCropDialog = VerticalGroup:new{
|
||||
ok_text = "OK",
|
||||
cancel_text = "Cancel",
|
||||
ok_callback = function() end,
|
||||
cancel_callback = function() end,
|
||||
button_width = math.floor(Screen:scaleByDPI(70)),
|
||||
ok_text = "OK",
|
||||
cancel_text = "Cancel",
|
||||
ok_callback = function() end,
|
||||
cancel_callback = function() end,
|
||||
button_width = math.floor(Screen:scaleByDPI(70)),
|
||||
}
|
||||
|
||||
function PageCropDialog:init()
|
||||
local horizontal_group = HorizontalGroup:new{}
|
||||
local ok_button = Button:new{
|
||||
text = self.ok_text,
|
||||
callback = self.ok_callback,
|
||||
width = self.button_width,
|
||||
bordersize = 2,
|
||||
radius = 7,
|
||||
text_font_face = "cfont",
|
||||
text_font_size = 20,
|
||||
}
|
||||
local cancel_button = Button:new{
|
||||
text = self.cancel_text,
|
||||
callback = self.cancel_callback,
|
||||
width = self.button_width,
|
||||
bordersize = 2,
|
||||
radius = 7,
|
||||
text_font_face = "cfont",
|
||||
text_font_size = 20,
|
||||
}
|
||||
local ok_container = RightContainer:new{
|
||||
dimen = Geom:new{ w = Screen:getWidth()*0.33, h = Screen:getHeight()/12},
|
||||
ok_button,
|
||||
}
|
||||
local cancel_container = LeftContainer:new{
|
||||
dimen = Geom:new{ w = Screen:getWidth()*0.33, h = Screen:getHeight()/12},
|
||||
cancel_button,
|
||||
}
|
||||
table.insert(horizontal_group, ok_container)
|
||||
table.insert(horizontal_group, HorizontalSpan:new{ width = Screen:getWidth()*0.34})
|
||||
table.insert(horizontal_group, cancel_container)
|
||||
self[2] = FrameContainer:new{
|
||||
horizontal_group,
|
||||
background = 0,
|
||||
bordersize = 0,
|
||||
padding = 0,
|
||||
}
|
||||
local horizontal_group = HorizontalGroup:new{}
|
||||
local ok_button = Button:new{
|
||||
text = self.ok_text,
|
||||
callback = self.ok_callback,
|
||||
width = self.button_width,
|
||||
bordersize = 2,
|
||||
radius = 7,
|
||||
text_font_face = "cfont",
|
||||
text_font_size = 20,
|
||||
}
|
||||
local cancel_button = Button:new{
|
||||
text = self.cancel_text,
|
||||
callback = self.cancel_callback,
|
||||
width = self.button_width,
|
||||
bordersize = 2,
|
||||
radius = 7,
|
||||
text_font_face = "cfont",
|
||||
text_font_size = 20,
|
||||
}
|
||||
local ok_container = RightContainer:new{
|
||||
dimen = Geom:new{ w = Screen:getWidth()*0.33, h = Screen:getHeight()/12},
|
||||
ok_button,
|
||||
}
|
||||
local cancel_container = LeftContainer:new{
|
||||
dimen = Geom:new{ w = Screen:getWidth()*0.33, h = Screen:getHeight()/12},
|
||||
cancel_button,
|
||||
}
|
||||
table.insert(horizontal_group, ok_container)
|
||||
table.insert(horizontal_group, HorizontalSpan:new{ width = Screen:getWidth()*0.34})
|
||||
table.insert(horizontal_group, cancel_container)
|
||||
self[2] = FrameContainer:new{
|
||||
horizontal_group,
|
||||
background = 0,
|
||||
bordersize = 0,
|
||||
padding = 0,
|
||||
}
|
||||
end
|
||||
|
||||
local ReaderCropping = InputContainer:new{}
|
||||
|
||||
function ReaderCropping:onPageCrop(mode)
|
||||
if mode == "auto" then return end
|
||||
self.ui:handleEvent(Event:new("CloseConfig"))
|
||||
-- backup original view dimen
|
||||
self.orig_view_dimen = Geom:new{w = self.view.dimen.w, h = self.view.dimen.h}
|
||||
-- backup original view bgcolor
|
||||
self.orig_view_bgcolor = self.view.outer_page_color
|
||||
self.view.outer_page_color = 7 -- gray bgcolor
|
||||
-- backup original zoom mode as cropping use "page" zoom mode
|
||||
self.orig_zoom_mode = self.view.zoom_mode
|
||||
-- backup original page scroll
|
||||
self.orig_page_scroll = self.view.page_scroll
|
||||
self.view.page_scroll = false
|
||||
-- backup and disable original hinting state
|
||||
self.ui:handleEvent(Event:new("DisableHinting"))
|
||||
-- backup original reflow mode as cropping use non-reflow mode
|
||||
self.orig_reflow_mode = self.document.configurable.text_wrap
|
||||
if self.orig_reflow_mode == 1 then
|
||||
self.document.configurable.text_wrap = 0
|
||||
-- if we are in reflow mode, then we are already in page
|
||||
-- mode, just force readerview to recalculate visible_area
|
||||
self.view:recalculate()
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", "page", "cropping"))
|
||||
end
|
||||
self.ui:handleEvent(Event:new("SetDimensions",
|
||||
Geom:new{w = Screen:getWidth(), h = Screen:getHeight()*11/12})
|
||||
)
|
||||
self.bbox_widget = BBoxWidget:new{
|
||||
crop = self,
|
||||
ui = self.ui,
|
||||
view = self.view,
|
||||
document = self.document,
|
||||
}
|
||||
self.crop_dialog = PageCropDialog:new{
|
||||
self.bbox_widget,
|
||||
ok_callback = function() self:onConfirmPageCrop() end,
|
||||
cancel_callback = function() self:onCancelPageCrop() end,
|
||||
}
|
||||
UIManager:show(self.crop_dialog)
|
||||
return true
|
||||
if mode == "auto" then return end
|
||||
self.ui:handleEvent(Event:new("CloseConfig"))
|
||||
-- backup original view dimen
|
||||
self.orig_view_dimen = Geom:new{w = self.view.dimen.w, h = self.view.dimen.h}
|
||||
-- backup original view bgcolor
|
||||
self.orig_view_bgcolor = self.view.outer_page_color
|
||||
self.view.outer_page_color = 7 -- gray bgcolor
|
||||
-- backup original zoom mode as cropping use "page" zoom mode
|
||||
self.orig_zoom_mode = self.view.zoom_mode
|
||||
-- backup original page scroll
|
||||
self.orig_page_scroll = self.view.page_scroll
|
||||
self.view.page_scroll = false
|
||||
-- backup and disable original hinting state
|
||||
self.ui:handleEvent(Event:new("DisableHinting"))
|
||||
-- backup original reflow mode as cropping use non-reflow mode
|
||||
self.orig_reflow_mode = self.document.configurable.text_wrap
|
||||
if self.orig_reflow_mode == 1 then
|
||||
self.document.configurable.text_wrap = 0
|
||||
-- if we are in reflow mode, then we are already in page
|
||||
-- mode, just force readerview to recalculate visible_area
|
||||
self.view:recalculate()
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", "page", "cropping"))
|
||||
end
|
||||
self.ui:handleEvent(Event:new("SetDimensions",
|
||||
Geom:new{w = Screen:getWidth(), h = Screen:getHeight()*11/12})
|
||||
)
|
||||
self.bbox_widget = BBoxWidget:new{
|
||||
crop = self,
|
||||
ui = self.ui,
|
||||
view = self.view,
|
||||
document = self.document,
|
||||
}
|
||||
self.crop_dialog = PageCropDialog:new{
|
||||
self.bbox_widget,
|
||||
ok_callback = function() self:onConfirmPageCrop() end,
|
||||
cancel_callback = function() self:onCancelPageCrop() end,
|
||||
}
|
||||
UIManager:show(self.crop_dialog)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderCropping:onConfirmPageCrop()
|
||||
--DEBUG("new bbox", new_bbox)
|
||||
UIManager:close(self.crop_dialog)
|
||||
local new_bbox = self.bbox_widget:getModifiedPageBBox()
|
||||
self.ui:handleEvent(Event:new("BBoxUpdate", new_bbox))
|
||||
local pageno = self.view.state.page
|
||||
self.document.bbox[pageno] = new_bbox
|
||||
self.document.bbox[Math.oddEven(pageno)] = new_bbox
|
||||
self:exitPageCrop(true)
|
||||
return true
|
||||
--DEBUG("new bbox", new_bbox)
|
||||
UIManager:close(self.crop_dialog)
|
||||
local new_bbox = self.bbox_widget:getModifiedPageBBox()
|
||||
self.ui:handleEvent(Event:new("BBoxUpdate", new_bbox))
|
||||
local pageno = self.view.state.page
|
||||
self.document.bbox[pageno] = new_bbox
|
||||
self.document.bbox[Math.oddEven(pageno)] = new_bbox
|
||||
self:exitPageCrop(true)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderCropping:onCancelPageCrop()
|
||||
UIManager:close(self.crop_dialog)
|
||||
self:exitPageCrop(false)
|
||||
return true
|
||||
UIManager:close(self.crop_dialog)
|
||||
self:exitPageCrop(false)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderCropping:exitPageCrop(confirmed)
|
||||
-- restore hinting state
|
||||
self.ui:handleEvent(Event:new("RestoreHinting"))
|
||||
-- restore page scroll
|
||||
self.view.page_scroll = self.orig_page_scroll
|
||||
-- restore view bgcolor
|
||||
self.view.outer_page_color = self.orig_view_bgcolor
|
||||
-- restore reflow mode
|
||||
self.document.configurable.text_wrap = self.orig_reflow_mode
|
||||
-- restore view dimens
|
||||
self.ui:handleEvent(Event:new("RestoreDimensions", self.orig_view_dimen))
|
||||
self.view:recalculate()
|
||||
-- Exiting should have the same look and feel with entering.
|
||||
if self.orig_reflow_mode == 1 then
|
||||
self.ui:handleEvent(Event:new("RestoreZoomMode"))
|
||||
else
|
||||
if confirmed then
|
||||
-- if original zoom mode is not "content", set zoom mode to "contentwidth"
|
||||
self.ui:handleEvent(Event:new("SetZoomMode",
|
||||
self.orig_zoom_mode:find("content") and self.orig_zoom_mode or "contentwidth"))
|
||||
self.ui:handleEvent(Event:new("InitScrollPageStates"))
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", self.orig_zoom_mode))
|
||||
end
|
||||
end
|
||||
UIManager.repaint_all = true
|
||||
-- restore hinting state
|
||||
self.ui:handleEvent(Event:new("RestoreHinting"))
|
||||
-- restore page scroll
|
||||
self.view.page_scroll = self.orig_page_scroll
|
||||
-- restore view bgcolor
|
||||
self.view.outer_page_color = self.orig_view_bgcolor
|
||||
-- restore reflow mode
|
||||
self.document.configurable.text_wrap = self.orig_reflow_mode
|
||||
-- restore view dimens
|
||||
self.ui:handleEvent(Event:new("RestoreDimensions", self.orig_view_dimen))
|
||||
self.view:recalculate()
|
||||
-- Exiting should have the same look and feel with entering.
|
||||
if self.orig_reflow_mode == 1 then
|
||||
self.ui:handleEvent(Event:new("RestoreZoomMode"))
|
||||
else
|
||||
if confirmed then
|
||||
-- if original zoom mode is not "content", set zoom mode to "contentwidth"
|
||||
self.ui:handleEvent(Event:new("SetZoomMode",
|
||||
self.orig_zoom_mode:find("content") and self.orig_zoom_mode or "contentwidth"))
|
||||
self.ui:handleEvent(Event:new("InitScrollPageStates"))
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", self.orig_zoom_mode))
|
||||
end
|
||||
end
|
||||
UIManager.repaint_all = true
|
||||
end
|
||||
|
||||
function ReaderCropping:onReadSettings(config)
|
||||
self.document.bbox = config:readSetting("bbox")
|
||||
self.document.bbox = config:readSetting("bbox")
|
||||
end
|
||||
|
||||
function ReaderCropping:onSaveSettings()
|
||||
self.ui.doc_settings:saveSetting("bbox", self.document.bbox)
|
||||
self.ui.doc_settings:saveSetting("bbox", self.document.bbox)
|
||||
end
|
||||
|
||||
return ReaderCropping
|
||||
|
||||
@@ -9,69 +9,69 @@ local DEBUG = require("dbg")
|
||||
local ReaderDictionary = EventListener:new{}
|
||||
|
||||
function ReaderDictionary:onLookupWord(highlight, word, box)
|
||||
self.highlight = highlight
|
||||
self:stardictLookup(word, box)
|
||||
self.highlight = highlight
|
||||
self:stardictLookup(word, box)
|
||||
end
|
||||
|
||||
function ReaderDictionary:stardictLookup(word, box)
|
||||
DEBUG("lookup word:", word, box)
|
||||
if word then
|
||||
-- strip punctuation characters around selected word
|
||||
word = string.gsub(word, "^%p+", '')
|
||||
word = string.gsub(word, "%p+$", '')
|
||||
DEBUG("stripped word:", word)
|
||||
-- escape quotes and other funny characters in word
|
||||
local std_out = io.popen("./sdcv --utf8-input --utf8-output -nj "..("%q"):format(word), "r")
|
||||
local results_str = nil
|
||||
if std_out then results_str = std_out:read("*all") end
|
||||
if results_str then
|
||||
--DEBUG("result str:", word, results_str)
|
||||
local ok, results = pcall(JSON.decode, JSON, results_str)
|
||||
--DEBUG("lookup result table:", word, results)
|
||||
self:showDict(results, box)
|
||||
end
|
||||
end
|
||||
DEBUG("lookup word:", word, box)
|
||||
if word then
|
||||
-- strip punctuation characters around selected word
|
||||
word = string.gsub(word, "^%p+", '')
|
||||
word = string.gsub(word, "%p+$", '')
|
||||
DEBUG("stripped word:", word)
|
||||
-- escape quotes and other funny characters in word
|
||||
local std_out = io.popen("./sdcv --utf8-input --utf8-output -nj "..("%q"):format(word), "r")
|
||||
local results_str = nil
|
||||
if std_out then results_str = std_out:read("*all") end
|
||||
if results_str then
|
||||
--DEBUG("result str:", word, results_str)
|
||||
local ok, results = pcall(JSON.decode, JSON, results_str)
|
||||
--DEBUG("lookup result table:", word, results)
|
||||
self:showDict(results, box)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderDictionary:showDict(results, box)
|
||||
if results and results[1] and box then
|
||||
DEBUG("showing quick lookup dictionary window")
|
||||
local align = nil
|
||||
local region = Geom:new{x = 0, w = Screen:getWidth()}
|
||||
if box.y + box.h/2 < Screen:getHeight()/2 then
|
||||
region.y = box.y + box.h
|
||||
region.h = Screen:getHeight() - box.y - box.h
|
||||
align = "top"
|
||||
else
|
||||
region.y = 0
|
||||
region.h = box.y
|
||||
align = "bottom"
|
||||
end
|
||||
UIManager:show(DictQuickLookup:new{
|
||||
ui = self.ui,
|
||||
highlight = self.highlight,
|
||||
dialog = self.dialog,
|
||||
results = results,
|
||||
dictionary = self.default_dictionary,
|
||||
width = Screen:getWidth() - Screen:scaleByDPI(80),
|
||||
height = math.min(region.h*0.7, Screen:getHeight()*0.5),
|
||||
region = region,
|
||||
align = align,
|
||||
})
|
||||
end
|
||||
if results and results[1] and box then
|
||||
DEBUG("showing quick lookup dictionary window")
|
||||
local align = nil
|
||||
local region = Geom:new{x = 0, w = Screen:getWidth()}
|
||||
if box.y + box.h/2 < Screen:getHeight()/2 then
|
||||
region.y = box.y + box.h
|
||||
region.h = Screen:getHeight() - box.y - box.h
|
||||
align = "top"
|
||||
else
|
||||
region.y = 0
|
||||
region.h = box.y
|
||||
align = "bottom"
|
||||
end
|
||||
UIManager:show(DictQuickLookup:new{
|
||||
ui = self.ui,
|
||||
highlight = self.highlight,
|
||||
dialog = self.dialog,
|
||||
results = results,
|
||||
dictionary = self.default_dictionary,
|
||||
width = Screen:getWidth() - Screen:scaleByDPI(80),
|
||||
height = math.min(region.h*0.7, Screen:getHeight()*0.5),
|
||||
region = region,
|
||||
align = align,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderDictionary:onUpdateDefaultDict(dict)
|
||||
DEBUG("make default dictionary:", dict)
|
||||
self.default_dictionary = dict
|
||||
DEBUG("make default dictionary:", dict)
|
||||
self.default_dictionary = dict
|
||||
end
|
||||
|
||||
function ReaderDictionary:onReadSettings(config)
|
||||
self.default_dictionary = config:readSetting("default_dictionary")
|
||||
self.default_dictionary = config:readSetting("default_dictionary")
|
||||
end
|
||||
|
||||
function ReaderDictionary:onSaveSettings()
|
||||
self.ui.doc_settings:saveSetting("default_dictionary", self.default_dictionary)
|
||||
self.ui.doc_settings:saveSetting("default_dictionary", self.default_dictionary)
|
||||
end
|
||||
|
||||
return ReaderDictionary
|
||||
|
||||
@@ -11,54 +11,54 @@ local Event = require("ui/event")
|
||||
local ReaderDogear = InputContainer:new{}
|
||||
|
||||
function ReaderDogear:init()
|
||||
local widget = ImageWidget:new{
|
||||
file = "resources/icons/dogear.png",
|
||||
}
|
||||
self[1] = RightContainer:new{
|
||||
dimen = Geom:new{w = Screen:getWidth(), h = widget:getSize().h},
|
||||
widget,
|
||||
}
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
Tap = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = Screen:getWidth()*DTAP_ZONE_BOOKMARK.x,
|
||||
y = Screen:getHeight()*DTAP_ZONE_BOOKMARK.y,
|
||||
w = Screen:getWidth()*DTAP_ZONE_BOOKMARK.w,
|
||||
h = Screen:getHeight()*DTAP_ZONE_BOOKMARK.h
|
||||
}
|
||||
}
|
||||
},
|
||||
Hold = {
|
||||
GestureRange:new{
|
||||
ges = "hold",
|
||||
range = Geom:new{
|
||||
x = Screen:getWidth()*DTAP_ZONE_BOOKMARK.x,
|
||||
y = Screen:getHeight()*DTAP_ZONE_BOOKMARK.y,
|
||||
w = Screen:getWidth()*DTAP_ZONE_BOOKMARK.w,
|
||||
h = Screen:getHeight()*DTAP_ZONE_BOOKMARK.h
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
local widget = ImageWidget:new{
|
||||
file = "resources/icons/dogear.png",
|
||||
}
|
||||
self[1] = RightContainer:new{
|
||||
dimen = Geom:new{w = Screen:getWidth(), h = widget:getSize().h},
|
||||
widget,
|
||||
}
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
Tap = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = Screen:getWidth()*DTAP_ZONE_BOOKMARK.x,
|
||||
y = Screen:getHeight()*DTAP_ZONE_BOOKMARK.y,
|
||||
w = Screen:getWidth()*DTAP_ZONE_BOOKMARK.w,
|
||||
h = Screen:getHeight()*DTAP_ZONE_BOOKMARK.h
|
||||
}
|
||||
}
|
||||
},
|
||||
Hold = {
|
||||
GestureRange:new{
|
||||
ges = "hold",
|
||||
range = Geom:new{
|
||||
x = Screen:getWidth()*DTAP_ZONE_BOOKMARK.x,
|
||||
y = Screen:getHeight()*DTAP_ZONE_BOOKMARK.y,
|
||||
w = Screen:getWidth()*DTAP_ZONE_BOOKMARK.w,
|
||||
h = Screen:getHeight()*DTAP_ZONE_BOOKMARK.h
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderDogear:onTap()
|
||||
self.ui:handleEvent(Event:new("ToggleBookmark"))
|
||||
return true
|
||||
self.ui:handleEvent(Event:new("ToggleBookmark"))
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderDogear:onHold()
|
||||
self.ui:handleEvent(Event:new("ToggleBookmarkFlipping"))
|
||||
return true
|
||||
self.ui:handleEvent(Event:new("ToggleBookmarkFlipping"))
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderDogear:onSetDogearVisibility(visible)
|
||||
self.view.dogear_visible = visible
|
||||
return true
|
||||
self.view.dogear_visible = visible
|
||||
return true
|
||||
end
|
||||
|
||||
return ReaderDogear
|
||||
|
||||
@@ -8,37 +8,37 @@ local Screen = require("ui/screen")
|
||||
local Event = require("ui/event")
|
||||
|
||||
local ReaderFlipping = InputContainer:new{
|
||||
orig_reflow_mode = 0,
|
||||
orig_reflow_mode = 0,
|
||||
}
|
||||
|
||||
function ReaderFlipping:init()
|
||||
local widget = ImageWidget:new{
|
||||
file = "resources/icons/appbar.book.open.png",
|
||||
}
|
||||
self[1] = LeftContainer:new{
|
||||
dimen = Geom:new{w = Screen:getWidth(), h = widget:getSize().h},
|
||||
widget,
|
||||
}
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
Tap = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = Screen:getWidth()*DTAP_ZONE_FLIPPING.x,
|
||||
y = Screen:getHeight()*DTAP_ZONE_FLIPPING.y,
|
||||
w = Screen:getWidth()*DTAP_ZONE_FLIPPING.w,
|
||||
h = Screen:getHeight()*DTAP_ZONE_FLIPPING.h
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
local widget = ImageWidget:new{
|
||||
file = "resources/icons/appbar.book.open.png",
|
||||
}
|
||||
self[1] = LeftContainer:new{
|
||||
dimen = Geom:new{w = Screen:getWidth(), h = widget:getSize().h},
|
||||
widget,
|
||||
}
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
Tap = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = Screen:getWidth()*DTAP_ZONE_FLIPPING.x,
|
||||
y = Screen:getHeight()*DTAP_ZONE_FLIPPING.y,
|
||||
w = Screen:getWidth()*DTAP_ZONE_FLIPPING.w,
|
||||
h = Screen:getHeight()*DTAP_ZONE_FLIPPING.h
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderFlipping:onTap()
|
||||
self.ui:handleEvent(Event:new("TogglePageFlipping"))
|
||||
return true
|
||||
self.ui:handleEvent(Event:new("TogglePageFlipping"))
|
||||
return true
|
||||
end
|
||||
|
||||
return ReaderFlipping
|
||||
|
||||
@@ -12,220 +12,220 @@ local DEBUG = require("dbg")
|
||||
local _ = require("gettext")
|
||||
|
||||
local ReaderFont = InputContainer:new{
|
||||
font_face = nil,
|
||||
font_size = nil,
|
||||
line_space_percent = nil,
|
||||
font_menu_title = _("Change font"),
|
||||
face_table = nil,
|
||||
-- default gamma from crengine's lvfntman.cpp
|
||||
gamma_index = nil,
|
||||
font_face = nil,
|
||||
font_size = nil,
|
||||
line_space_percent = nil,
|
||||
font_menu_title = _("Change font"),
|
||||
face_table = nil,
|
||||
-- default gamma from crengine's lvfntman.cpp
|
||||
gamma_index = nil,
|
||||
}
|
||||
|
||||
function ReaderFont:init()
|
||||
if Device:hasKeyboard() then
|
||||
-- add shortcut for keyboard
|
||||
self.key_events = {
|
||||
ShowFontMenu = { {"F"}, doc = _("show font menu") },
|
||||
IncreaseSize = {
|
||||
{ "Shift", Input.group.PgFwd },
|
||||
doc = _("increase font size"),
|
||||
event = "ChangeSize", args = "increase" },
|
||||
DecreaseSize = {
|
||||
{ "Shift", Input.group.PgBack },
|
||||
doc = _("decrease font size"),
|
||||
event = "ChangeSize", args = "decrease" },
|
||||
IncreaseLineSpace = {
|
||||
{ "Alt", Input.group.PgFwd },
|
||||
doc = _("increase line space"),
|
||||
event = "ChangeLineSpace", args = "increase" },
|
||||
DecreaseLineSpace = {
|
||||
{ "Alt", Input.group.PgBack },
|
||||
doc = _("decrease line space"),
|
||||
event = "ChangeLineSpace", args = "decrease" },
|
||||
}
|
||||
end
|
||||
-- build face_table for menu
|
||||
self.face_table = {}
|
||||
local face_list = cre.getFontFaces()
|
||||
for k,v in ipairs(face_list) do
|
||||
table.insert(self.face_table, {
|
||||
text = v,
|
||||
callback = function()
|
||||
self:setFont(v)
|
||||
end
|
||||
})
|
||||
face_list[k] = {text = v}
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
if Device:hasKeyboard() then
|
||||
-- add shortcut for keyboard
|
||||
self.key_events = {
|
||||
ShowFontMenu = { {"F"}, doc = _("show font menu") },
|
||||
IncreaseSize = {
|
||||
{ "Shift", Input.group.PgFwd },
|
||||
doc = _("increase font size"),
|
||||
event = "ChangeSize", args = "increase" },
|
||||
DecreaseSize = {
|
||||
{ "Shift", Input.group.PgBack },
|
||||
doc = _("decrease font size"),
|
||||
event = "ChangeSize", args = "decrease" },
|
||||
IncreaseLineSpace = {
|
||||
{ "Alt", Input.group.PgFwd },
|
||||
doc = _("increase line space"),
|
||||
event = "ChangeLineSpace", args = "increase" },
|
||||
DecreaseLineSpace = {
|
||||
{ "Alt", Input.group.PgBack },
|
||||
doc = _("decrease line space"),
|
||||
event = "ChangeLineSpace", args = "decrease" },
|
||||
}
|
||||
end
|
||||
-- build face_table for menu
|
||||
self.face_table = {}
|
||||
local face_list = cre.getFontFaces()
|
||||
for k,v in ipairs(face_list) do
|
||||
table.insert(self.face_table, {
|
||||
text = v,
|
||||
callback = function()
|
||||
self:setFont(v)
|
||||
end
|
||||
})
|
||||
face_list[k] = {text = v}
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function ReaderFont:onSetDimensions(dimen)
|
||||
self.dimen = dimen
|
||||
self.dimen = dimen
|
||||
end
|
||||
|
||||
function ReaderFont:onReadSettings(config)
|
||||
self.font_face = config:readSetting("font_face")
|
||||
if not self.font_face then
|
||||
self.font_face = self.ui.document.default_font
|
||||
end
|
||||
self.ui.document:setFontFace(self.font_face)
|
||||
self.font_face = config:readSetting("font_face")
|
||||
if not self.font_face then
|
||||
self.font_face = self.ui.document.default_font
|
||||
end
|
||||
self.ui.document:setFontFace(self.font_face)
|
||||
|
||||
self.header_font_face = config:readSetting("header_font_face")
|
||||
if not self.header_font_face then
|
||||
self.header_font_face = self.ui.document.header_font
|
||||
end
|
||||
self.ui.document:setHeaderFont(self.header_font_face)
|
||||
self.header_font_face = config:readSetting("header_font_face")
|
||||
if not self.header_font_face then
|
||||
self.header_font_face = self.ui.document.header_font
|
||||
end
|
||||
self.ui.document:setHeaderFont(self.header_font_face)
|
||||
|
||||
self.font_size = config:readSetting("font_size")
|
||||
if not self.font_size then
|
||||
--@TODO change this! 12.01 2013 (houqp)
|
||||
self.font_size = DCREREADER_CONFIG_DEFAULT_FONT_SIZE
|
||||
end
|
||||
self.ui.document:setFontSize(Screen:scaleByDPI(self.font_size))
|
||||
self.font_size = config:readSetting("font_size")
|
||||
if not self.font_size then
|
||||
--@TODO change this! 12.01 2013 (houqp)
|
||||
self.font_size = DCREREADER_CONFIG_DEFAULT_FONT_SIZE
|
||||
end
|
||||
self.ui.document:setFontSize(Screen:scaleByDPI(self.font_size))
|
||||
|
||||
self.line_space_percent = config:readSetting("line_space_percent")
|
||||
if not self.line_space_percent then
|
||||
self.line_space_percent = 100
|
||||
else
|
||||
self.ui.document:setInterlineSpacePercent(self.line_space_percent)
|
||||
end
|
||||
self.line_space_percent = config:readSetting("line_space_percent")
|
||||
if not self.line_space_percent then
|
||||
self.line_space_percent = 100
|
||||
else
|
||||
self.ui.document:setInterlineSpacePercent(self.line_space_percent)
|
||||
end
|
||||
|
||||
self.gamma_index = config:readSetting("gamma_index")
|
||||
if not self.gamma_index then
|
||||
self.gamma_index = 15
|
||||
end
|
||||
self.ui.document:setGammaIndex(self.gamma_index)
|
||||
self.gamma_index = config:readSetting("gamma_index")
|
||||
if not self.gamma_index then
|
||||
self.gamma_index = 15
|
||||
end
|
||||
self.ui.document:setGammaIndex(self.gamma_index)
|
||||
|
||||
-- Dirty hack: we have to add folloing call in order to set
|
||||
-- m_is_rendered(member of LVDocView) to true. Otherwise position inside
|
||||
-- document will be reset to 0 on first view render.
|
||||
-- So far, I don't know why this call will alter the value of m_is_rendered.
|
||||
table.insert(self.ui.postInitCallback, function()
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
end)
|
||||
-- Dirty hack: we have to add folloing call in order to set
|
||||
-- m_is_rendered(member of LVDocView) to true. Otherwise position inside
|
||||
-- document will be reset to 0 on first view render.
|
||||
-- So far, I don't know why this call will alter the value of m_is_rendered.
|
||||
table.insert(self.ui.postInitCallback, function()
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
end)
|
||||
end
|
||||
|
||||
function ReaderFont:onShowFontMenu()
|
||||
-- build menu widget
|
||||
local main_menu = Menu:new{
|
||||
title = self.font_menu_title,
|
||||
item_table = self.face_table,
|
||||
width = Screen:getWidth() - 100,
|
||||
}
|
||||
-- build container
|
||||
local menu_container = CenterContainer:new{
|
||||
main_menu,
|
||||
dimen = Screen:getSize(),
|
||||
}
|
||||
main_menu.close_callback = function ()
|
||||
UIManager:close(menu_container)
|
||||
end
|
||||
-- show menu
|
||||
UIManager:show(menu_container)
|
||||
return true
|
||||
-- build menu widget
|
||||
local main_menu = Menu:new{
|
||||
title = self.font_menu_title,
|
||||
item_table = self.face_table,
|
||||
width = Screen:getWidth() - 100,
|
||||
}
|
||||
-- build container
|
||||
local menu_container = CenterContainer:new{
|
||||
main_menu,
|
||||
dimen = Screen:getSize(),
|
||||
}
|
||||
main_menu.close_callback = function ()
|
||||
UIManager:close(menu_container)
|
||||
end
|
||||
-- show menu
|
||||
UIManager:show(menu_container)
|
||||
return true
|
||||
end
|
||||
|
||||
--[[
|
||||
UpdatePos event is used to tell ReaderRolling to update pos.
|
||||
UpdatePos event is used to tell ReaderRolling to update pos.
|
||||
--]]
|
||||
function ReaderFont:onChangeSize(direction)
|
||||
local delta = direction == "decrease" and -1 or 1
|
||||
self.font_size = self.font_size + delta
|
||||
self.ui:handleEvent(Event:new("SetFontSize", self.font_size))
|
||||
return true
|
||||
local delta = direction == "decrease" and -1 or 1
|
||||
self.font_size = self.font_size + delta
|
||||
self.ui:handleEvent(Event:new("SetFontSize", self.font_size))
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderFont:onSetFontSize(new_size)
|
||||
if new_size > 72 then new_size = 72 end
|
||||
if new_size < 12 then new_size = 12 end
|
||||
if new_size > 72 then new_size = 72 end
|
||||
if new_size < 12 then new_size = 12 end
|
||||
|
||||
self.font_size = new_size
|
||||
UIManager:show(Notification:new{
|
||||
text = _("Set font size to ")..self.font_size,
|
||||
timeout = 1,
|
||||
})
|
||||
self.ui.document:setFontSize(Screen:scaleByDPI(new_size))
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
self.font_size = new_size
|
||||
UIManager:show(Notification:new{
|
||||
text = _("Set font size to ")..self.font_size,
|
||||
timeout = 1,
|
||||
})
|
||||
self.ui.document:setFontSize(Screen:scaleByDPI(new_size))
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
|
||||
return true
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderFont:onChangeLineSpace(direction)
|
||||
local msg = ""
|
||||
if direction == "decrease" then
|
||||
self.line_space_percent = self.line_space_percent - 10
|
||||
-- NuPogodi, 15.05.12: reduce lowest space_percent to 80
|
||||
self.line_space_percent = math.max(self.line_space_percent, 80)
|
||||
msg = _("Decrease line space to ")
|
||||
else
|
||||
self.line_space_percent = self.line_space_percent + 10
|
||||
self.line_space_percent = math.min(self.line_space_percent, 200)
|
||||
msg = _("Increase line space to ")
|
||||
end
|
||||
UIManager:show(Notification:new{
|
||||
text = msg..self.line_space_percent.."%",
|
||||
timeout = 1,
|
||||
})
|
||||
self.ui.document:setInterlineSpacePercent(self.line_space_percent)
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
local msg = ""
|
||||
if direction == "decrease" then
|
||||
self.line_space_percent = self.line_space_percent - 10
|
||||
-- NuPogodi, 15.05.12: reduce lowest space_percent to 80
|
||||
self.line_space_percent = math.max(self.line_space_percent, 80)
|
||||
msg = _("Decrease line space to ")
|
||||
else
|
||||
self.line_space_percent = self.line_space_percent + 10
|
||||
self.line_space_percent = math.min(self.line_space_percent, 200)
|
||||
msg = _("Increase line space to ")
|
||||
end
|
||||
UIManager:show(Notification:new{
|
||||
text = msg..self.line_space_percent.."%",
|
||||
timeout = 1,
|
||||
})
|
||||
self.ui.document:setInterlineSpacePercent(self.line_space_percent)
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
|
||||
return true
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderFont:onToggleFontBolder()
|
||||
self.ui.document:toggleFontBolder()
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
return true
|
||||
self.ui.document:toggleFontBolder()
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderFont:onChangeFontGamma(direction)
|
||||
local msg = ""
|
||||
if direction == "increase" then
|
||||
cre.setGammaIndex(self.gamma_index+2)
|
||||
msg = _("Increase gamma to ")
|
||||
elseif direction == "decrease" then
|
||||
cre.setGammaIndex(self.gamma_index-2)
|
||||
msg = _("Decrease gamma to ")
|
||||
end
|
||||
self.gamma_index = cre.getGammaIndex()
|
||||
UIManager:show(Notification:new{
|
||||
text = msg..self.gamma_index,
|
||||
timeout = 1
|
||||
})
|
||||
self.ui:handleEvent(Event:new("RedrawCurrentView"))
|
||||
return true
|
||||
local msg = ""
|
||||
if direction == "increase" then
|
||||
cre.setGammaIndex(self.gamma_index+2)
|
||||
msg = _("Increase gamma to ")
|
||||
elseif direction == "decrease" then
|
||||
cre.setGammaIndex(self.gamma_index-2)
|
||||
msg = _("Decrease gamma to ")
|
||||
end
|
||||
self.gamma_index = cre.getGammaIndex()
|
||||
UIManager:show(Notification:new{
|
||||
text = msg..self.gamma_index,
|
||||
timeout = 1
|
||||
})
|
||||
self.ui:handleEvent(Event:new("RedrawCurrentView"))
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderFont:onSaveSettings()
|
||||
self.ui.doc_settings:saveSetting("font_face", self.font_face)
|
||||
self.ui.doc_settings:saveSetting("header_font_face", self.header_font_face)
|
||||
self.ui.doc_settings:saveSetting("font_size", self.font_size)
|
||||
self.ui.doc_settings:saveSetting("line_space_percent", self.line_space_percent)
|
||||
self.ui.doc_settings:saveSetting("gamma_index", self.gamma_index)
|
||||
self.ui.doc_settings:saveSetting("font_face", self.font_face)
|
||||
self.ui.doc_settings:saveSetting("header_font_face", self.header_font_face)
|
||||
self.ui.doc_settings:saveSetting("font_size", self.font_size)
|
||||
self.ui.doc_settings:saveSetting("line_space_percent", self.line_space_percent)
|
||||
self.ui.doc_settings:saveSetting("gamma_index", self.gamma_index)
|
||||
end
|
||||
|
||||
function ReaderFont:setFont(face)
|
||||
if face and self.font_face ~= face then
|
||||
self.font_face = face
|
||||
UIManager:show(Notification:new{
|
||||
text = _("Redrawing with font ")..face,
|
||||
timeout = 1,
|
||||
})
|
||||
if face and self.font_face ~= face then
|
||||
self.font_face = face
|
||||
UIManager:show(Notification:new{
|
||||
text = _("Redrawing with font ")..face,
|
||||
timeout = 1,
|
||||
})
|
||||
|
||||
self.ui.document:setFontFace(face)
|
||||
-- signal readerrolling to update pos in new height
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
self.ui.document:setFontFace(face)
|
||||
-- signal readerrolling to update pos in new height
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
|
||||
UIManager:close(msg)
|
||||
end
|
||||
UIManager:close(msg)
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderFont:addToMainMenu(tab_item_table)
|
||||
-- insert table to main reader menu
|
||||
table.insert(tab_item_table.typeset, {
|
||||
text = self.font_menu_title,
|
||||
sub_item_table = self.face_table,
|
||||
})
|
||||
-- insert table to main reader menu
|
||||
table.insert(tab_item_table.typeset, {
|
||||
text = self.font_menu_title,
|
||||
sub_item_table = self.face_table,
|
||||
})
|
||||
end
|
||||
|
||||
return ReaderFont
|
||||
|
||||
@@ -16,136 +16,136 @@ local Font = require("ui/font")
|
||||
local DEBUG = require("dbg")
|
||||
|
||||
local ReaderFooter = InputContainer:new{
|
||||
visible = true,
|
||||
pageno = nil,
|
||||
pages = nil,
|
||||
progress_percentage = 0.0,
|
||||
progress_text = "0 / 0",
|
||||
show_time = false,
|
||||
bar_width = 0.85,
|
||||
text_width = 0.15,
|
||||
text_font_face = "ffont",
|
||||
text_font_size = 14,
|
||||
height = 19,
|
||||
visible = true,
|
||||
pageno = nil,
|
||||
pages = nil,
|
||||
progress_percentage = 0.0,
|
||||
progress_text = "0 / 0",
|
||||
show_time = false,
|
||||
bar_width = 0.85,
|
||||
text_width = 0.15,
|
||||
text_font_face = "ffont",
|
||||
text_font_size = 14,
|
||||
height = 19,
|
||||
}
|
||||
|
||||
function ReaderFooter:init()
|
||||
self.progress_bar = ProgressWidget:new{
|
||||
width = math.floor(Screen:getWidth()*(self.bar_width-0.02)),
|
||||
height = 7,
|
||||
percentage = self.progress_percentage,
|
||||
}
|
||||
self.progress_text = TextWidget:new{
|
||||
text = self.progress_text,
|
||||
face = Font:getFace(self.text_font_face, self.text_font_size),
|
||||
}
|
||||
local _, text_height = self.progress_text:getSize()
|
||||
local horizontal_group = HorizontalGroup:new{}
|
||||
local bar_container = RightContainer:new{
|
||||
dimen = Geom:new{w = Screen:getWidth()*self.bar_width, h = self.height},
|
||||
self.progress_bar,
|
||||
}
|
||||
local text_container = CenterContainer:new{
|
||||
dimen = Geom:new{w = Screen:getWidth()*self.text_width, h = self.height},
|
||||
self.progress_text,
|
||||
}
|
||||
table.insert(horizontal_group, bar_container)
|
||||
table.insert(horizontal_group, text_container)
|
||||
self[1] = BottomContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
FrameContainer:new{
|
||||
horizontal_group,
|
||||
background = 0,
|
||||
bordersize = 0,
|
||||
padding = 0,
|
||||
}
|
||||
}
|
||||
self.dimen = self[1]:getSize()
|
||||
self.pageno = self.view.state.page
|
||||
self.pages = self.view.document.info.number_of_pages
|
||||
self:updateFooterPage()
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapFooter = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self[1]:contentRange(),
|
||||
},
|
||||
},
|
||||
HoldFooter = {
|
||||
GestureRange:new{
|
||||
ges = "hold",
|
||||
range = self[1]:contentRange(),
|
||||
},
|
||||
},
|
||||
}
|
||||
end
|
||||
self.progress_bar = ProgressWidget:new{
|
||||
width = math.floor(Screen:getWidth()*(self.bar_width-0.02)),
|
||||
height = 7,
|
||||
percentage = self.progress_percentage,
|
||||
}
|
||||
self.progress_text = TextWidget:new{
|
||||
text = self.progress_text,
|
||||
face = Font:getFace(self.text_font_face, self.text_font_size),
|
||||
}
|
||||
local _, text_height = self.progress_text:getSize()
|
||||
local horizontal_group = HorizontalGroup:new{}
|
||||
local bar_container = RightContainer:new{
|
||||
dimen = Geom:new{w = Screen:getWidth()*self.bar_width, h = self.height},
|
||||
self.progress_bar,
|
||||
}
|
||||
local text_container = CenterContainer:new{
|
||||
dimen = Geom:new{w = Screen:getWidth()*self.text_width, h = self.height},
|
||||
self.progress_text,
|
||||
}
|
||||
table.insert(horizontal_group, bar_container)
|
||||
table.insert(horizontal_group, text_container)
|
||||
self[1] = BottomContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
FrameContainer:new{
|
||||
horizontal_group,
|
||||
background = 0,
|
||||
bordersize = 0,
|
||||
padding = 0,
|
||||
}
|
||||
}
|
||||
self.dimen = self[1]:getSize()
|
||||
self.pageno = self.view.state.page
|
||||
self.pages = self.view.document.info.number_of_pages
|
||||
self:updateFooterPage()
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapFooter = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self[1]:contentRange(),
|
||||
},
|
||||
},
|
||||
HoldFooter = {
|
||||
GestureRange:new{
|
||||
ges = "hold",
|
||||
range = self[1]:contentRange(),
|
||||
},
|
||||
},
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderFooter:updateFooterPage()
|
||||
if type(self.pageno) ~= "number" then return end
|
||||
self.progress_bar.percentage = self.pageno / self.pages
|
||||
|
||||
if self.show_time then
|
||||
self.progress_text.text = os.date("%H:%M")
|
||||
else
|
||||
self.progress_text.text = string.format("%d / %d", self.pageno, self.pages)
|
||||
end
|
||||
if type(self.pageno) ~= "number" then return end
|
||||
self.progress_bar.percentage = self.pageno / self.pages
|
||||
|
||||
if self.show_time then
|
||||
self.progress_text.text = os.date("%H:%M")
|
||||
else
|
||||
self.progress_text.text = string.format("%d / %d", self.pageno, self.pages)
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderFooter:updateFooterPos()
|
||||
if type(self.position) ~= "number" then return end
|
||||
self.progress_bar.percentage = self.position / self.doc_height
|
||||
|
||||
if self.show_time then
|
||||
self.progress_text.text = os.date("%H:%M")
|
||||
else
|
||||
self.progress_text.text = string.format("%1.f", self.progress_bar.percentage*100).."%"
|
||||
end
|
||||
if type(self.position) ~= "number" then return end
|
||||
self.progress_bar.percentage = self.position / self.doc_height
|
||||
|
||||
if self.show_time then
|
||||
self.progress_text.text = os.date("%H:%M")
|
||||
else
|
||||
self.progress_text.text = string.format("%1.f", self.progress_bar.percentage*100).."%"
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderFooter:onPageUpdate(pageno)
|
||||
self.pageno = pageno
|
||||
self.pages = self.view.document.info.number_of_pages
|
||||
self:updateFooterPage()
|
||||
self.pageno = pageno
|
||||
self.pages = self.view.document.info.number_of_pages
|
||||
self:updateFooterPage()
|
||||
end
|
||||
|
||||
function ReaderFooter:onPosUpdate(pos)
|
||||
self.position = pos
|
||||
self.doc_height = self.view.document.info.doc_height
|
||||
self:updateFooterPos()
|
||||
self.position = pos
|
||||
self.doc_height = self.view.document.info.doc_height
|
||||
self:updateFooterPos()
|
||||
end
|
||||
|
||||
function ReaderFooter:onTapFooter(arg, ges)
|
||||
if self.view.flipping_visible then
|
||||
local pos = ges.pos
|
||||
local dimen = self.progress_bar.dimen
|
||||
local percentage = (pos.x - dimen.x)/dimen.w
|
||||
self.ui:handleEvent(Event:new("GotoPercentage", percentage))
|
||||
else
|
||||
self.show_time = not self.show_time
|
||||
end
|
||||
if self.pageno then
|
||||
self:updateFooterPage()
|
||||
else
|
||||
self:updateFooterPos()
|
||||
end
|
||||
UIManager:setDirty(self.view.dialog, "partial")
|
||||
-- consume this tap when footer is visible
|
||||
if self.view.footer_visible then
|
||||
return true
|
||||
end
|
||||
if self.view.flipping_visible then
|
||||
local pos = ges.pos
|
||||
local dimen = self.progress_bar.dimen
|
||||
local percentage = (pos.x - dimen.x)/dimen.w
|
||||
self.ui:handleEvent(Event:new("GotoPercentage", percentage))
|
||||
else
|
||||
self.show_time = not self.show_time
|
||||
end
|
||||
if self.pageno then
|
||||
self:updateFooterPage()
|
||||
else
|
||||
self:updateFooterPos()
|
||||
end
|
||||
UIManager:setDirty(self.view.dialog, "partial")
|
||||
-- consume this tap when footer is visible
|
||||
if self.view.footer_visible then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderFooter:onHoldFooter(arg, ges)
|
||||
self.ui:handleEvent(Event:new("ShowGotoDialog"))
|
||||
return true
|
||||
self.ui:handleEvent(Event:new("ShowGotoDialog"))
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderFooter:onSetStatusLine(status_line)
|
||||
self.view.footer_visible = status_line == 1 and true or false
|
||||
self.ui.document:setStatusLineProp(status_line)
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
self.view.footer_visible = status_line == 1 and true or false
|
||||
self.ui.document:setStatusLineProp(status_line)
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
end
|
||||
|
||||
return ReaderFooter
|
||||
|
||||
@@ -7,86 +7,86 @@ local DEBUG = require("dbg")
|
||||
local _ = require("gettext")
|
||||
|
||||
local ReaderGoto = InputContainer:new{
|
||||
goto_menu_title = _("Go To"),
|
||||
goto_dialog_title = _("Go to Page or Location"),
|
||||
goto_menu_title = _("Go To"),
|
||||
goto_dialog_title = _("Go to Page or Location"),
|
||||
}
|
||||
|
||||
function ReaderGoto:init()
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function ReaderGoto:addToMainMenu(tab_item_table)
|
||||
-- insert goto command to main reader menu
|
||||
table.insert(tab_item_table.navi, {
|
||||
text = self.goto_menu_title,
|
||||
callback = function()
|
||||
self:onShowGotoDialog()
|
||||
end,
|
||||
})
|
||||
-- insert goto command to main reader menu
|
||||
table.insert(tab_item_table.navi, {
|
||||
text = self.goto_menu_title,
|
||||
callback = function()
|
||||
self:onShowGotoDialog()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
function ReaderGoto:onShowGotoDialog()
|
||||
DEBUG("show goto dialog")
|
||||
self.goto_dialog = InputDialog:new{
|
||||
title = self.goto_dialog_title,
|
||||
input_hint = "(1 - "..self.document:getPageCount()..")",
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Cancel"),
|
||||
enabled = true,
|
||||
callback = function()
|
||||
self:close()
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Page"),
|
||||
enabled = self.document.info.has_pages,
|
||||
callback = function()
|
||||
self:gotoPage()
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Location"),
|
||||
enabled = not self.document.info.has_pages,
|
||||
callback = function()
|
||||
self:gotoLocation()
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
input_type = "number",
|
||||
enter_callback = self.document.info.has_pages
|
||||
and function() self:gotoPage() end
|
||||
or function() self:gotoLocation() end,
|
||||
width = Screen:getWidth() * 0.8,
|
||||
height = Screen:getHeight() * 0.2,
|
||||
}
|
||||
self.goto_dialog:onShowKeyboard()
|
||||
UIManager:show(self.goto_dialog)
|
||||
DEBUG("show goto dialog")
|
||||
self.goto_dialog = InputDialog:new{
|
||||
title = self.goto_dialog_title,
|
||||
input_hint = "(1 - "..self.document:getPageCount()..")",
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Cancel"),
|
||||
enabled = true,
|
||||
callback = function()
|
||||
self:close()
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Page"),
|
||||
enabled = self.document.info.has_pages,
|
||||
callback = function()
|
||||
self:gotoPage()
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Location"),
|
||||
enabled = not self.document.info.has_pages,
|
||||
callback = function()
|
||||
self:gotoLocation()
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
input_type = "number",
|
||||
enter_callback = self.document.info.has_pages
|
||||
and function() self:gotoPage() end
|
||||
or function() self:gotoLocation() end,
|
||||
width = Screen:getWidth() * 0.8,
|
||||
height = Screen:getHeight() * 0.2,
|
||||
}
|
||||
self.goto_dialog:onShowKeyboard()
|
||||
UIManager:show(self.goto_dialog)
|
||||
end
|
||||
|
||||
function ReaderGoto:close()
|
||||
self.goto_dialog:onClose()
|
||||
UIManager:close(self.goto_dialog)
|
||||
self.goto_dialog:onClose()
|
||||
UIManager:close(self.goto_dialog)
|
||||
end
|
||||
|
||||
function ReaderGoto:gotoPage()
|
||||
local number = tonumber(self.goto_dialog:getInputText())
|
||||
if number then
|
||||
self.ui:handleEvent(Event:new("GotoPage", number))
|
||||
end
|
||||
self:close()
|
||||
return true
|
||||
local number = tonumber(self.goto_dialog:getInputText())
|
||||
if number then
|
||||
self.ui:handleEvent(Event:new("GotoPage", number))
|
||||
end
|
||||
self:close()
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderGoto:gotoLocation()
|
||||
local number = tonumber(self.goto_dialog:getInputText())
|
||||
if number then
|
||||
self.ui:handleEvent(Event:new("GotoPage", number))
|
||||
end
|
||||
self:close()
|
||||
return true
|
||||
local number = tonumber(self.goto_dialog:getInputText())
|
||||
if number then
|
||||
self.ui:handleEvent(Event:new("GotoPage", number))
|
||||
end
|
||||
self:close()
|
||||
return true
|
||||
end
|
||||
|
||||
return ReaderGoto
|
||||
|
||||
@@ -12,405 +12,405 @@ local _ = require("gettext")
|
||||
local ReaderHighlight = InputContainer:new{}
|
||||
|
||||
function ReaderHighlight:init()
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ShowToc = {
|
||||
{ "." },
|
||||
doc = _("highlight text") },
|
||||
}
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ShowToc = {
|
||||
{ "." },
|
||||
doc = _("highlight text") },
|
||||
}
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function ReaderHighlight:initGesListener()
|
||||
self.ges_events = {
|
||||
Tap = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight()
|
||||
}
|
||||
}
|
||||
},
|
||||
Hold = {
|
||||
GestureRange:new{
|
||||
ges = "hold",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight()
|
||||
}
|
||||
}
|
||||
},
|
||||
HoldRelease = {
|
||||
GestureRange:new{
|
||||
ges = "hold_release",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight()
|
||||
}
|
||||
}
|
||||
},
|
||||
HoldPan = {
|
||||
GestureRange:new{
|
||||
ges = "hold_pan",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight()
|
||||
},
|
||||
rate = 2.0,
|
||||
}
|
||||
},
|
||||
}
|
||||
self.ges_events = {
|
||||
Tap = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight()
|
||||
}
|
||||
}
|
||||
},
|
||||
Hold = {
|
||||
GestureRange:new{
|
||||
ges = "hold",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight()
|
||||
}
|
||||
}
|
||||
},
|
||||
HoldRelease = {
|
||||
GestureRange:new{
|
||||
ges = "hold_release",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight()
|
||||
}
|
||||
}
|
||||
},
|
||||
HoldPan = {
|
||||
GestureRange:new{
|
||||
ges = "hold_pan",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight()
|
||||
},
|
||||
rate = 2.0,
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
function ReaderHighlight:addToMainMenu(tab_item_table)
|
||||
-- insert table to main reader menu
|
||||
table.insert(tab_item_table.typeset, {
|
||||
text_func = function()
|
||||
return _("Set highlight drawer ").."( "..self.view.highlight.saved_drawer.." )"
|
||||
end,
|
||||
sub_item_table = self:genHighlightDrawerMenu(),
|
||||
})
|
||||
-- insert table to main reader menu
|
||||
table.insert(tab_item_table.typeset, {
|
||||
text_func = function()
|
||||
return _("Set highlight drawer ").."( "..self.view.highlight.saved_drawer.." )"
|
||||
end,
|
||||
sub_item_table = self:genHighlightDrawerMenu(),
|
||||
})
|
||||
end
|
||||
|
||||
function ReaderHighlight:genHighlightDrawerMenu()
|
||||
return {
|
||||
{
|
||||
text = _("Lighten"),
|
||||
callback = function()
|
||||
self.view.highlight.saved_drawer = "lighten"
|
||||
end
|
||||
},
|
||||
{
|
||||
text = _("Underscore"),
|
||||
callback = function()
|
||||
self.view.highlight.saved_drawer = "underscore"
|
||||
end
|
||||
},
|
||||
{
|
||||
text = _("Invert"),
|
||||
callback = function()
|
||||
self.view.highlight.saved_drawer = "invert"
|
||||
end
|
||||
},
|
||||
}
|
||||
return {
|
||||
{
|
||||
text = _("Lighten"),
|
||||
callback = function()
|
||||
self.view.highlight.saved_drawer = "lighten"
|
||||
end
|
||||
},
|
||||
{
|
||||
text = _("Underscore"),
|
||||
callback = function()
|
||||
self.view.highlight.saved_drawer = "underscore"
|
||||
end
|
||||
},
|
||||
{
|
||||
text = _("Invert"),
|
||||
callback = function()
|
||||
self.view.highlight.saved_drawer = "invert"
|
||||
end
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
function ReaderHighlight:onSetDimensions(dimen)
|
||||
-- update listening according to new screen dimen
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
-- update listening according to new screen dimen
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHighlight:onTap(arg, ges)
|
||||
if self.hold_pos then
|
||||
if self.ui.document.info.has_pages then
|
||||
self.view.highlight.temp[self.hold_pos.page] = nil
|
||||
else
|
||||
self.ui.document:clearSelection()
|
||||
end
|
||||
self.hold_pos = nil
|
||||
UIManager:setDirty(self.dialog, "partial")
|
||||
return true
|
||||
end
|
||||
if self.ui.document.info.has_pages then
|
||||
return self:onTapPageSavedHighlight(ges)
|
||||
else
|
||||
return self:onTapXPointerSavedHighlight(ges)
|
||||
end
|
||||
if self.hold_pos then
|
||||
if self.ui.document.info.has_pages then
|
||||
self.view.highlight.temp[self.hold_pos.page] = nil
|
||||
else
|
||||
self.ui.document:clearSelection()
|
||||
end
|
||||
self.hold_pos = nil
|
||||
UIManager:setDirty(self.dialog, "partial")
|
||||
return true
|
||||
end
|
||||
if self.ui.document.info.has_pages then
|
||||
return self:onTapPageSavedHighlight(ges)
|
||||
else
|
||||
return self:onTapXPointerSavedHighlight(ges)
|
||||
end
|
||||
end
|
||||
|
||||
local function inside_box(pos, box)
|
||||
if pos then
|
||||
local x, y = pos.x, pos.y
|
||||
if box.x <= x and box.y <= y
|
||||
and box.x + box.w >= x
|
||||
and box.y + box.h >= y then
|
||||
return true
|
||||
end
|
||||
end
|
||||
if pos then
|
||||
local x, y = pos.x, pos.y
|
||||
if box.x <= x and box.y <= y
|
||||
and box.x + box.w >= x
|
||||
and box.y + box.h >= y then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHighlight:onTapPageSavedHighlight(ges)
|
||||
local pages = self.view:getCurrentPageList()
|
||||
local pos = self.view:screenToPageTransform(ges.pos)
|
||||
for key, page in pairs(pages) do
|
||||
local items = self.view.highlight.saved[page]
|
||||
if not items then items = {} end
|
||||
for i = 1, #items do
|
||||
local pos0, pos1 = items[i].pos0, items[i].pos1
|
||||
local boxes = self.ui.document:getPageBoxesFromPositions(page, pos0, pos1)
|
||||
if boxes then
|
||||
for index, box in pairs(boxes) do
|
||||
if inside_box(pos, box) then
|
||||
DEBUG("Tap on hightlight")
|
||||
return self:onShowHighlightDialog(page, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local pages = self.view:getCurrentPageList()
|
||||
local pos = self.view:screenToPageTransform(ges.pos)
|
||||
for key, page in pairs(pages) do
|
||||
local items = self.view.highlight.saved[page]
|
||||
if not items then items = {} end
|
||||
for i = 1, #items do
|
||||
local pos0, pos1 = items[i].pos0, items[i].pos1
|
||||
local boxes = self.ui.document:getPageBoxesFromPositions(page, pos0, pos1)
|
||||
if boxes then
|
||||
for index, box in pairs(boxes) do
|
||||
if inside_box(pos, box) then
|
||||
DEBUG("Tap on hightlight")
|
||||
return self:onShowHighlightDialog(page, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHighlight:onTapXPointerSavedHighlight(ges)
|
||||
local pos = self.view:screenToPageTransform(ges.pos)
|
||||
for page, _ in pairs(self.view.highlight.saved) do
|
||||
local items = self.view.highlight.saved[page]
|
||||
if not items then items = {} end
|
||||
for i = 1, #items do
|
||||
local pos0, pos1 = items[i].pos0, items[i].pos1
|
||||
local boxes = self.ui.document:getScreenBoxesFromPositions(pos0, pos1)
|
||||
if boxes then
|
||||
for index, box in pairs(boxes) do
|
||||
if inside_box(pos, box) then
|
||||
DEBUG("Tap on hightlight")
|
||||
return self:onShowHighlightDialog(page, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local pos = self.view:screenToPageTransform(ges.pos)
|
||||
for page, _ in pairs(self.view.highlight.saved) do
|
||||
local items = self.view.highlight.saved[page]
|
||||
if not items then items = {} end
|
||||
for i = 1, #items do
|
||||
local pos0, pos1 = items[i].pos0, items[i].pos1
|
||||
local boxes = self.ui.document:getScreenBoxesFromPositions(pos0, pos1)
|
||||
if boxes then
|
||||
for index, box in pairs(boxes) do
|
||||
if inside_box(pos, box) then
|
||||
DEBUG("Tap on hightlight")
|
||||
return self:onShowHighlightDialog(page, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHighlight:onShowHighlightDialog(page, index)
|
||||
self.edit_highlight_dialog = ButtonDialog:new{
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Delete"),
|
||||
callback = function()
|
||||
self:deleteHighlight(page, index)
|
||||
UIManager:close(self.edit_highlight_dialog)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Edit"),
|
||||
enabled = false,
|
||||
callback = function()
|
||||
self:editHighlight()
|
||||
UIManager:close(self.edit_highlight_dialog)
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
UIManager:show(self.edit_highlight_dialog)
|
||||
return true
|
||||
self.edit_highlight_dialog = ButtonDialog:new{
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Delete"),
|
||||
callback = function()
|
||||
self:deleteHighlight(page, index)
|
||||
UIManager:close(self.edit_highlight_dialog)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Edit"),
|
||||
enabled = false,
|
||||
callback = function()
|
||||
self:editHighlight()
|
||||
UIManager:close(self.edit_highlight_dialog)
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
UIManager:show(self.edit_highlight_dialog)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderHighlight:onHold(arg, ges)
|
||||
self.hold_pos = self.view:screenToPageTransform(ges.pos)
|
||||
DEBUG("hold position in page", self.hold_pos)
|
||||
if not self.hold_pos then
|
||||
DEBUG("not inside page area")
|
||||
return true
|
||||
end
|
||||
self.hold_pos = self.view:screenToPageTransform(ges.pos)
|
||||
DEBUG("hold position in page", self.hold_pos)
|
||||
if not self.hold_pos then
|
||||
DEBUG("not inside page area")
|
||||
return true
|
||||
end
|
||||
|
||||
local ok, word = pcall(self.ui.document.getWordFromPosition, self.ui.document, self.hold_pos)
|
||||
if ok and word then
|
||||
DEBUG("selected word:", word)
|
||||
self.selected_word = word
|
||||
if self.ui.document.info.has_pages then
|
||||
local boxes = {}
|
||||
table.insert(boxes, self.selected_word.sbox)
|
||||
self.view.highlight.temp[self.hold_pos.page] = boxes
|
||||
end
|
||||
UIManager:setDirty(self.dialog, "partial")
|
||||
end
|
||||
return true
|
||||
local ok, word = pcall(self.ui.document.getWordFromPosition, self.ui.document, self.hold_pos)
|
||||
if ok and word then
|
||||
DEBUG("selected word:", word)
|
||||
self.selected_word = word
|
||||
if self.ui.document.info.has_pages then
|
||||
local boxes = {}
|
||||
table.insert(boxes, self.selected_word.sbox)
|
||||
self.view.highlight.temp[self.hold_pos.page] = boxes
|
||||
end
|
||||
UIManager:setDirty(self.dialog, "partial")
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderHighlight:onHoldPan(arg, ges)
|
||||
if self.hold_pos == nil then
|
||||
DEBUG("no previous hold position")
|
||||
return true
|
||||
end
|
||||
self.holdpan_pos = self.view:screenToPageTransform(ges.pos)
|
||||
DEBUG("holdpan position in page", self.holdpan_pos)
|
||||
self.selected_text = self.ui.document:getTextFromPositions(self.hold_pos, self.holdpan_pos)
|
||||
DEBUG("selected text:", self.selected_text)
|
||||
if self.selected_text then
|
||||
self.view.highlight.temp[self.hold_pos.page] = self.selected_text.sboxes
|
||||
-- remove selected word if hold moves out of word box
|
||||
if not self.selected_text.sboxes or #self.selected_text.sboxes == 0 then
|
||||
self.selected_word = nil
|
||||
elseif self.selected_word and not self.selected_word.sbox:contains(self.selected_text.sboxes[1]) or
|
||||
#self.selected_text.sboxes > 1 then
|
||||
self.selected_word = nil
|
||||
end
|
||||
end
|
||||
UIManager:setDirty(self.dialog, "partial")
|
||||
if self.hold_pos == nil then
|
||||
DEBUG("no previous hold position")
|
||||
return true
|
||||
end
|
||||
self.holdpan_pos = self.view:screenToPageTransform(ges.pos)
|
||||
DEBUG("holdpan position in page", self.holdpan_pos)
|
||||
self.selected_text = self.ui.document:getTextFromPositions(self.hold_pos, self.holdpan_pos)
|
||||
DEBUG("selected text:", self.selected_text)
|
||||
if self.selected_text then
|
||||
self.view.highlight.temp[self.hold_pos.page] = self.selected_text.sboxes
|
||||
-- remove selected word if hold moves out of word box
|
||||
if not self.selected_text.sboxes or #self.selected_text.sboxes == 0 then
|
||||
self.selected_word = nil
|
||||
elseif self.selected_word and not self.selected_word.sbox:contains(self.selected_text.sboxes[1]) or
|
||||
#self.selected_text.sboxes > 1 then
|
||||
self.selected_word = nil
|
||||
end
|
||||
end
|
||||
UIManager:setDirty(self.dialog, "partial")
|
||||
end
|
||||
|
||||
function ReaderHighlight:lookup(selected_word)
|
||||
-- if we extracted text directly
|
||||
if selected_word.word then
|
||||
local word_box = self.view:pageToScreenTransform(self.hold_pos.page, selected_word.sbox)
|
||||
self.ui:handleEvent(Event:new("LookupWord", self, selected_word.word, word_box))
|
||||
-- or we will do OCR
|
||||
elseif selected_word.sbox and self.hold_pos then
|
||||
local word = self.ui.document:getOCRWord(self.hold_pos.page, selected_word)
|
||||
DEBUG("OCRed word:", word)
|
||||
local word_box = self.view:pageToScreenTransform(self.hold_pos.page, selected_word.sbox)
|
||||
self.ui:handleEvent(Event:new("LookupWord", self, word, word_box))
|
||||
end
|
||||
-- if we extracted text directly
|
||||
if selected_word.word then
|
||||
local word_box = self.view:pageToScreenTransform(self.hold_pos.page, selected_word.sbox)
|
||||
self.ui:handleEvent(Event:new("LookupWord", self, selected_word.word, word_box))
|
||||
-- or we will do OCR
|
||||
elseif selected_word.sbox and self.hold_pos then
|
||||
local word = self.ui.document:getOCRWord(self.hold_pos.page, selected_word)
|
||||
DEBUG("OCRed word:", word)
|
||||
local word_box = self.view:pageToScreenTransform(self.hold_pos.page, selected_word.sbox)
|
||||
self.ui:handleEvent(Event:new("LookupWord", self, word, word_box))
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHighlight:translate(selected_text)
|
||||
if selected_text.text ~= "" then
|
||||
self.ui:handleEvent(Event:new("TranslateText", self, selected_text.text))
|
||||
-- or we will do OCR
|
||||
else
|
||||
local text = self.ui.document:getOCRText(self.hold_pos.page, selected_text)
|
||||
DEBUG("OCRed text:", text)
|
||||
self.ui:handleEvent(Event:new("TranslateText", self, text))
|
||||
end
|
||||
if selected_text.text ~= "" then
|
||||
self.ui:handleEvent(Event:new("TranslateText", self, selected_text.text))
|
||||
-- or we will do OCR
|
||||
else
|
||||
local text = self.ui.document:getOCRText(self.hold_pos.page, selected_text)
|
||||
DEBUG("OCRed text:", text)
|
||||
self.ui:handleEvent(Event:new("TranslateText", self, text))
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHighlight:onHoldRelease(arg, ges)
|
||||
if self.selected_word then
|
||||
self:lookup(self.selected_word)
|
||||
self.selected_word = nil
|
||||
elseif self.selected_text then
|
||||
DEBUG("show highlight dialog")
|
||||
self.highlight_dialog = ButtonDialog:new{
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Highlight"),
|
||||
callback = function()
|
||||
self:saveHighlight()
|
||||
UIManager:close(self.highlight_dialog)
|
||||
self:handleEvent(Event:new("Tap"))
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Add Note"),
|
||||
enabled = false,
|
||||
callback = function()
|
||||
self:addNote()
|
||||
UIManager:close(self.highlight_dialog)
|
||||
self:handleEvent(Event:new("Tap"))
|
||||
end,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
text = _("Translate"),
|
||||
callback = function()
|
||||
self:translate(self.selected_text)
|
||||
UIManager:close(self.highlight_dialog)
|
||||
self:handleEvent(Event:new("Tap"))
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Share"),
|
||||
enabled = false,
|
||||
callback = function()
|
||||
self:shareHighlight()
|
||||
UIManager:close(self.highlight_dialog)
|
||||
self:handleEvent(Event:new("Tap"))
|
||||
end,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
text = _("More"),
|
||||
enabled = false,
|
||||
callback = function()
|
||||
self:moreAction()
|
||||
UIManager:close(self.highlight_dialog)
|
||||
self:handleEvent(Event:new("Tap"))
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
tap_close_callback = function() self:handleEvent(Event:new("Tap")) end,
|
||||
}
|
||||
UIManager:show(self.highlight_dialog)
|
||||
end
|
||||
return true
|
||||
if self.selected_word then
|
||||
self:lookup(self.selected_word)
|
||||
self.selected_word = nil
|
||||
elseif self.selected_text then
|
||||
DEBUG("show highlight dialog")
|
||||
self.highlight_dialog = ButtonDialog:new{
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Highlight"),
|
||||
callback = function()
|
||||
self:saveHighlight()
|
||||
UIManager:close(self.highlight_dialog)
|
||||
self:handleEvent(Event:new("Tap"))
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Add Note"),
|
||||
enabled = false,
|
||||
callback = function()
|
||||
self:addNote()
|
||||
UIManager:close(self.highlight_dialog)
|
||||
self:handleEvent(Event:new("Tap"))
|
||||
end,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
text = _("Translate"),
|
||||
callback = function()
|
||||
self:translate(self.selected_text)
|
||||
UIManager:close(self.highlight_dialog)
|
||||
self:handleEvent(Event:new("Tap"))
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Share"),
|
||||
enabled = false,
|
||||
callback = function()
|
||||
self:shareHighlight()
|
||||
UIManager:close(self.highlight_dialog)
|
||||
self:handleEvent(Event:new("Tap"))
|
||||
end,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
text = _("More"),
|
||||
enabled = false,
|
||||
callback = function()
|
||||
self:moreAction()
|
||||
UIManager:close(self.highlight_dialog)
|
||||
self:handleEvent(Event:new("Tap"))
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
tap_close_callback = function() self:handleEvent(Event:new("Tap")) end,
|
||||
}
|
||||
UIManager:show(self.highlight_dialog)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderHighlight:saveHighlight()
|
||||
DEBUG("save highlight")
|
||||
local page = self.hold_pos.page
|
||||
if self.hold_pos and self.selected_text then
|
||||
if not self.view.highlight.saved[page] then
|
||||
self.view.highlight.saved[page] = {}
|
||||
end
|
||||
local hl_item = {}
|
||||
hl_item["text"] = self.selected_text.text
|
||||
hl_item["pos0"] = self.selected_text.pos0
|
||||
hl_item["pos1"] = self.selected_text.pos1
|
||||
hl_item["pboxes"] = self.selected_text.pboxes
|
||||
hl_item["datetime"] = os.date("%Y-%m-%d %H:%M:%S")
|
||||
hl_item["drawer"] = self.view.highlight.saved_drawer
|
||||
table.insert(self.view.highlight.saved[page], hl_item)
|
||||
if self.selected_text.text ~= "" then
|
||||
self:exportToClippings(page, hl_item)
|
||||
end
|
||||
if self.selected_text.pboxes then
|
||||
self:exportToDocument(page, hl_item)
|
||||
end
|
||||
end
|
||||
--DEBUG("saved hightlights", self.view.highlight.saved[page])
|
||||
DEBUG("save highlight")
|
||||
local page = self.hold_pos.page
|
||||
if self.hold_pos and self.selected_text then
|
||||
if not self.view.highlight.saved[page] then
|
||||
self.view.highlight.saved[page] = {}
|
||||
end
|
||||
local hl_item = {}
|
||||
hl_item["text"] = self.selected_text.text
|
||||
hl_item["pos0"] = self.selected_text.pos0
|
||||
hl_item["pos1"] = self.selected_text.pos1
|
||||
hl_item["pboxes"] = self.selected_text.pboxes
|
||||
hl_item["datetime"] = os.date("%Y-%m-%d %H:%M:%S")
|
||||
hl_item["drawer"] = self.view.highlight.saved_drawer
|
||||
table.insert(self.view.highlight.saved[page], hl_item)
|
||||
if self.selected_text.text ~= "" then
|
||||
self:exportToClippings(page, hl_item)
|
||||
end
|
||||
if self.selected_text.pboxes then
|
||||
self:exportToDocument(page, hl_item)
|
||||
end
|
||||
end
|
||||
--DEBUG("saved hightlights", self.view.highlight.saved[page])
|
||||
end
|
||||
|
||||
function ReaderHighlight:exportToClippings(page, item)
|
||||
DEBUG("export highlight to clippings", item)
|
||||
local clippings = io.open("/mnt/us/documents/My Clippings.txt", "a+")
|
||||
if clippings and item.text then
|
||||
local current_locale = os.setlocale()
|
||||
os.setlocale("C")
|
||||
clippings:write(self.document.file:gsub("(.*/)(.*)", "%2").."\n")
|
||||
clippings:write("- Koreader Highlight Page "..page.." ")
|
||||
clippings:write("| Added on "..os.date("%A, %b %d, %Y %I:%M:%S %p\n\n"))
|
||||
clippings:write(item["text"].."\n")
|
||||
clippings:write("==========\n")
|
||||
clippings:close()
|
||||
os.setlocale(current_locale)
|
||||
end
|
||||
DEBUG("export highlight to clippings", item)
|
||||
local clippings = io.open("/mnt/us/documents/My Clippings.txt", "a+")
|
||||
if clippings and item.text then
|
||||
local current_locale = os.setlocale()
|
||||
os.setlocale("C")
|
||||
clippings:write(self.document.file:gsub("(.*/)(.*)", "%2").."\n")
|
||||
clippings:write("- Koreader Highlight Page "..page.." ")
|
||||
clippings:write("| Added on "..os.date("%A, %b %d, %Y %I:%M:%S %p\n\n"))
|
||||
clippings:write(item["text"].."\n")
|
||||
clippings:write("==========\n")
|
||||
clippings:close()
|
||||
os.setlocale(current_locale)
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHighlight:exportToDocument(page, item)
|
||||
DEBUG("export highlight to document", item)
|
||||
self.ui.document:saveHighlight(page, item)
|
||||
DEBUG("export highlight to document", item)
|
||||
self.ui.document:saveHighlight(page, item)
|
||||
end
|
||||
|
||||
function ReaderHighlight:addNote()
|
||||
DEBUG("add Note")
|
||||
DEBUG("add Note")
|
||||
end
|
||||
|
||||
function ReaderHighlight:shareHighlight()
|
||||
DEBUG("share highlight")
|
||||
DEBUG("share highlight")
|
||||
end
|
||||
|
||||
function ReaderHighlight:moreAction()
|
||||
DEBUG("more action")
|
||||
DEBUG("more action")
|
||||
end
|
||||
|
||||
function ReaderHighlight:deleteHighlight(page, i)
|
||||
DEBUG("delete highlight")
|
||||
table.remove(self.view.highlight.saved[page], i)
|
||||
DEBUG("delete highlight")
|
||||
table.remove(self.view.highlight.saved[page], i)
|
||||
end
|
||||
|
||||
function ReaderHighlight:editHighlight()
|
||||
DEBUG("edit highlight")
|
||||
DEBUG("edit highlight")
|
||||
end
|
||||
|
||||
function ReaderHighlight:onReadSettings(config)
|
||||
self.view.highlight.saved_drawer = config:readSetting("highlight_drawer") or self.view.highlight.saved_drawer
|
||||
self.view.highlight.saved_drawer = config:readSetting("highlight_drawer") or self.view.highlight.saved_drawer
|
||||
end
|
||||
|
||||
function ReaderHighlight:onSaveSettings()
|
||||
self.ui.doc_settings:saveSetting("highlight_drawer", self.view.highlight.saved_drawer)
|
||||
self.ui.doc_settings:saveSetting("highlight_drawer", self.view.highlight.saved_drawer)
|
||||
end
|
||||
|
||||
return ReaderHighlight
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
local EventListener = require("ui/widget/eventlistener")
|
||||
|
||||
local ReaderHinting = EventListener:new{
|
||||
hinting_states = {}
|
||||
hinting_states = {}
|
||||
}
|
||||
|
||||
function ReaderHinting:onHintPage()
|
||||
if not self.view.hinting then return true end
|
||||
for i=1, DHINTCOUNT do
|
||||
if self.view.state.page + i <= self.ui.document.info.number_of_pages then
|
||||
self.ui.document:hintPage(
|
||||
self.view.state.page + i,
|
||||
self.zoom:getZoom(self.view.state.page + i),
|
||||
self.view.state.rotation,
|
||||
self.view.state.gamma,
|
||||
self.view.render_mode)
|
||||
end
|
||||
end
|
||||
return true
|
||||
if not self.view.hinting then return true end
|
||||
for i=1, DHINTCOUNT do
|
||||
if self.view.state.page + i <= self.ui.document.info.number_of_pages then
|
||||
self.ui.document:hintPage(
|
||||
self.view.state.page + i,
|
||||
self.zoom:getZoom(self.view.state.page + i),
|
||||
self.view.state.rotation,
|
||||
self.view.state.gamma,
|
||||
self.view.render_mode)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderHinting:onSetHinting(hinting)
|
||||
self.view.hinting = hinting
|
||||
self.view.hinting = hinting
|
||||
end
|
||||
|
||||
function ReaderHinting:onDisableHinting()
|
||||
table.insert(self.hinting_states, self.view.hinting)
|
||||
self.view.hinting = false
|
||||
return true
|
||||
table.insert(self.hinting_states, self.view.hinting)
|
||||
self.view.hinting = false
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderHinting:onRestoreHinting()
|
||||
self.view.hinting = table.remove(self.hinting_states)
|
||||
return true
|
||||
self.view.hinting = table.remove(self.hinting_states)
|
||||
return true
|
||||
end
|
||||
|
||||
return ReaderHinting
|
||||
|
||||
@@ -4,52 +4,52 @@ local InfoMessage = require("ui/widget/infomessage")
|
||||
local _ = require("gettext")
|
||||
|
||||
local ReaderHyphenation = InputContainer:new{
|
||||
hyph_menu_title = _("Hyphenation"),
|
||||
hyph_table = nil,
|
||||
cur_hyph_idx = nil,
|
||||
hyph_menu_title = _("Hyphenation"),
|
||||
hyph_table = nil,
|
||||
cur_hyph_idx = nil,
|
||||
}
|
||||
|
||||
function ReaderHyphenation:_changeSel(k)
|
||||
if self.cur_hyph_idx then
|
||||
self.hyph_table[self.cur_hyph_idx].selected = false
|
||||
end
|
||||
self.hyph_table[k].selected = true
|
||||
self.cur_hyph_idx = k
|
||||
if self.cur_hyph_idx then
|
||||
self.hyph_table[self.cur_hyph_idx].selected = false
|
||||
end
|
||||
self.hyph_table[k].selected = true
|
||||
self.cur_hyph_idx = k
|
||||
end
|
||||
|
||||
function ReaderHyphenation:init()
|
||||
self.hyph_table = {}
|
||||
self.hyph_alg = cre.getSelectedHyphDict()
|
||||
for k,v in ipairs(cre.getHyphDictList()) do
|
||||
if v == self.hyph_alg then
|
||||
self.cur_hyph_idx = k
|
||||
end
|
||||
table.insert(self.hyph_table, {
|
||||
text = v,
|
||||
callback = function()
|
||||
self.hyph_alg = v
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Change Hyphenation to ")..v,
|
||||
})
|
||||
self:_changeSel(k)
|
||||
cre.setHyphDictionary(v)
|
||||
end
|
||||
})
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
self.hyph_table = {}
|
||||
self.hyph_alg = cre.getSelectedHyphDict()
|
||||
for k,v in ipairs(cre.getHyphDictList()) do
|
||||
if v == self.hyph_alg then
|
||||
self.cur_hyph_idx = k
|
||||
end
|
||||
table.insert(self.hyph_table, {
|
||||
text = v,
|
||||
callback = function()
|
||||
self.hyph_alg = v
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Change Hyphenation to ")..v,
|
||||
})
|
||||
self:_changeSel(k)
|
||||
cre.setHyphDictionary(v)
|
||||
end
|
||||
})
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function ReaderHyphenation:onReadSettings(config)
|
||||
local hyph_alg = config:readSetting("hyph_alg")
|
||||
if hyph_alg then
|
||||
cre.setHyphDictionary(hyph_alg)
|
||||
end
|
||||
self.hyph_alg = cre.getSelectedHyphDict()
|
||||
for k,v in ipairs(self.hyph_table) do
|
||||
if v.text == self.hyph_alg then
|
||||
self:_changeSel(k)
|
||||
end
|
||||
end
|
||||
local hyph_alg = config:readSetting("hyph_alg")
|
||||
if hyph_alg then
|
||||
cre.setHyphDictionary(hyph_alg)
|
||||
end
|
||||
self.hyph_alg = cre.getSelectedHyphDict()
|
||||
for k,v in ipairs(self.hyph_table) do
|
||||
if v.text == self.hyph_alg then
|
||||
self:_changeSel(k)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHyphenation:onSaveSettings()
|
||||
@@ -57,11 +57,11 @@ function ReaderHyphenation:onSaveSettings()
|
||||
end
|
||||
|
||||
function ReaderHyphenation:addToMainMenu(tab_item_table)
|
||||
-- insert table to main reader menu
|
||||
table.insert(tab_item_table.typeset, {
|
||||
text = self.hyph_menu_title,
|
||||
sub_item_table = self.hyph_table,
|
||||
})
|
||||
-- insert table to main reader menu
|
||||
table.insert(tab_item_table.typeset, {
|
||||
text = self.hyph_menu_title,
|
||||
sub_item_table = self.hyph_table,
|
||||
})
|
||||
end
|
||||
|
||||
return ReaderHyphenation
|
||||
|
||||
@@ -4,56 +4,56 @@ local Event = require("ui/event")
|
||||
local ReaderKoptListener = EventListener:new{}
|
||||
|
||||
function ReaderKoptListener:setZoomMode(zoom_mode)
|
||||
if self.document.configurable.text_wrap == 1 then
|
||||
-- in reflow mode only "page" zoom mode is valid so override any other zoom mode
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", "page", "koptlistener"))
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", zoom_mode, "koptlistener"))
|
||||
end
|
||||
if self.document.configurable.text_wrap == 1 then
|
||||
-- in reflow mode only "page" zoom mode is valid so override any other zoom mode
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", "page", "koptlistener"))
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", zoom_mode, "koptlistener"))
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderKoptListener:onReadSettings(config)
|
||||
-- normal zoom mode is zoom mode used in non-reflow mode.
|
||||
self.normal_zoom_mode = config:readSetting("normal_zoom_mode") or "page"
|
||||
self:setZoomMode(self.normal_zoom_mode)
|
||||
-- normal zoom mode is zoom mode used in non-reflow mode.
|
||||
self.normal_zoom_mode = config:readSetting("normal_zoom_mode") or "page"
|
||||
self:setZoomMode(self.normal_zoom_mode)
|
||||
end
|
||||
|
||||
function ReaderKoptListener:onSaveSettings()
|
||||
self.ui.doc_settings:saveSetting("normal_zoom_mode", self.normal_zoom_mode)
|
||||
self.ui.doc_settings:saveSetting("normal_zoom_mode", self.normal_zoom_mode)
|
||||
end
|
||||
|
||||
function ReaderKoptListener:onRestoreZoomMode()
|
||||
-- "RestoreZoomMode" event is sent when reflow mode on/off is toggled
|
||||
self:setZoomMode(self.normal_zoom_mode)
|
||||
return true
|
||||
-- "RestoreZoomMode" event is sent when reflow mode on/off is toggled
|
||||
self:setZoomMode(self.normal_zoom_mode)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderKoptListener:onSetZoomMode(zoom_mode, orig)
|
||||
if orig == "koptlistener" then return end
|
||||
-- capture zoom mode set outside of koptlistener which should always be normal zoom mode
|
||||
self.normal_zoom_mode = zoom_mode
|
||||
self:setZoomMode(self.normal_zoom_mode)
|
||||
if orig == "koptlistener" then return end
|
||||
-- capture zoom mode set outside of koptlistener which should always be normal zoom mode
|
||||
self.normal_zoom_mode = zoom_mode
|
||||
self:setZoomMode(self.normal_zoom_mode)
|
||||
end
|
||||
|
||||
function ReaderKoptListener:onFineTuningFontSize(delta)
|
||||
self.document.configurable.font_size = self.document.configurable.font_size + delta
|
||||
self.document.configurable.font_size = self.document.configurable.font_size + delta
|
||||
end
|
||||
|
||||
function ReaderKoptListener:onZoomUpdate(zoom)
|
||||
-- an exceptional case is reflow mode
|
||||
if self.document.configurable.text_wrap == 1 then
|
||||
self.view.state.zoom = 1.0
|
||||
end
|
||||
-- an exceptional case is reflow mode
|
||||
if self.document.configurable.text_wrap == 1 then
|
||||
self.view.state.zoom = 1.0
|
||||
end
|
||||
end
|
||||
|
||||
-- misc koptoption handler
|
||||
function ReaderKoptListener:onDocLangUpdate(lang)
|
||||
if lang == "chi_sim" or lang == "chi_tra" or
|
||||
lang == "jpn" or lang == "kor" then
|
||||
self.document.configurable.word_spacing = DKOPTREADER_CONFIG_WORD_SAPCINGS[1]
|
||||
else
|
||||
self.document.configurable.word_spacing = DKOPTREADER_CONFIG_WORD_SAPCINGS[3]
|
||||
end
|
||||
if lang == "chi_sim" or lang == "chi_tra" or
|
||||
lang == "jpn" or lang == "kor" then
|
||||
self.document.configurable.word_spacing = DKOPTREADER_CONFIG_WORD_SAPCINGS[1]
|
||||
else
|
||||
self.document.configurable.word_spacing = DKOPTREADER_CONFIG_WORD_SAPCINGS[3]
|
||||
end
|
||||
end
|
||||
|
||||
return ReaderKoptListener
|
||||
|
||||
@@ -7,100 +7,100 @@ local Event = require("ui/event")
|
||||
local DEBUG = require("dbg")
|
||||
|
||||
local ReaderLink = InputContainer:new{
|
||||
link_states = {}
|
||||
link_states = {}
|
||||
}
|
||||
|
||||
function ReaderLink:init()
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderLink:onReadSettings(config)
|
||||
-- called when loading new document
|
||||
self.link_states = {}
|
||||
-- called when loading new document
|
||||
self.link_states = {}
|
||||
end
|
||||
|
||||
function ReaderLink:initGesListener()
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
Tap = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight()
|
||||
}
|
||||
}
|
||||
},
|
||||
Swipe = {
|
||||
GestureRange:new{
|
||||
ges = "swipe",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
Tap = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight()
|
||||
}
|
||||
}
|
||||
},
|
||||
Swipe = {
|
||||
GestureRange:new{
|
||||
ges = "swipe",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderLink:onSetDimensions(dimen)
|
||||
-- update listening according to new screen dimen
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
-- update listening according to new screen dimen
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderLink:onTap(arg, ges)
|
||||
if self.ui.document.info.has_pages then
|
||||
local pos = self.view:screenToPageTransform(ges.pos)
|
||||
if pos then
|
||||
local link = self.ui.document:getLinkFromPosition(pos.page, pos)
|
||||
if link then
|
||||
return self:onGotoLink(link)
|
||||
end
|
||||
end
|
||||
else
|
||||
local link = self.ui.document:getLinkFromPosition(ges.pos)
|
||||
if link ~= "" then
|
||||
return self:onGotoLink(link)
|
||||
end
|
||||
end
|
||||
if self.ui.document.info.has_pages then
|
||||
local pos = self.view:screenToPageTransform(ges.pos)
|
||||
if pos then
|
||||
local link = self.ui.document:getLinkFromPosition(pos.page, pos)
|
||||
if link then
|
||||
return self:onGotoLink(link)
|
||||
end
|
||||
end
|
||||
else
|
||||
local link = self.ui.document:getLinkFromPosition(ges.pos)
|
||||
if link ~= "" then
|
||||
return self:onGotoLink(link)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderLink:onGotoLink(link)
|
||||
if self.ui.document.info.has_pages then
|
||||
table.insert(self.link_states, self.view.state.page)
|
||||
self.ui:handleEvent(Event:new("PageUpdate", link.page + 1))
|
||||
else
|
||||
table.insert(self.link_states, self.ui.document:getXPointer())
|
||||
self.document:gotoLink(link)
|
||||
self.ui:handleEvent(Event:new("UpdateXPointer"))
|
||||
end
|
||||
return true
|
||||
if self.ui.document.info.has_pages then
|
||||
table.insert(self.link_states, self.view.state.page)
|
||||
self.ui:handleEvent(Event:new("PageUpdate", link.page + 1))
|
||||
else
|
||||
table.insert(self.link_states, self.ui.document:getXPointer())
|
||||
self.document:gotoLink(link)
|
||||
self.ui:handleEvent(Event:new("UpdateXPointer"))
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderLink:onSwipe(arg, ges)
|
||||
if ges.direction == "east" then
|
||||
if self.ui.document.info.has_pages then
|
||||
local last_page = table.remove(self.link_states)
|
||||
if last_page then
|
||||
self.ui:handleEvent(Event:new("PageUpdate", last_page))
|
||||
return true
|
||||
end
|
||||
else
|
||||
local last_xp = table.remove(self.link_states)
|
||||
if last_xp then
|
||||
self.ui.document:gotoXPointer(last_xp)
|
||||
self.ui:handleEvent(Event:new("UpdateXPointer"))
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
if ges.direction == "east" then
|
||||
if self.ui.document.info.has_pages then
|
||||
local last_page = table.remove(self.link_states)
|
||||
if last_page then
|
||||
self.ui:handleEvent(Event:new("PageUpdate", last_page))
|
||||
return true
|
||||
end
|
||||
else
|
||||
local last_xp = table.remove(self.link_states)
|
||||
if last_xp then
|
||||
self.ui.document:gotoXPointer(last_xp)
|
||||
self.ui:handleEvent(Event:new("UpdateXPointer"))
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return ReaderLink
|
||||
|
||||
@@ -13,146 +13,146 @@ local Language = require("ui/language")
|
||||
local _ = require("gettext")
|
||||
|
||||
local ReaderMenu = InputContainer:new{
|
||||
tab_item_table = nil,
|
||||
registered_widgets = {},
|
||||
tab_item_table = nil,
|
||||
registered_widgets = {},
|
||||
}
|
||||
|
||||
function ReaderMenu:init()
|
||||
self.tab_item_table = {
|
||||
main = {
|
||||
icon = "resources/icons/appbar.pokeball.png",
|
||||
},
|
||||
navi = {
|
||||
icon = "resources/icons/appbar.page.corner.bookmark.png",
|
||||
},
|
||||
typeset = {
|
||||
icon = "resources/icons/appbar.page.text.png",
|
||||
},
|
||||
home = {
|
||||
icon = "resources/icons/appbar.home.png",
|
||||
callback = function()
|
||||
self.ui:handleEvent(Event:new("RestoreScreenMode",
|
||||
G_reader_settings:readSetting("screen_mode") or "portrait"))
|
||||
UIManager:close(self.menu_container)
|
||||
self.ui:onClose()
|
||||
end,
|
||||
},
|
||||
}
|
||||
self.registered_widgets = {}
|
||||
self.tab_item_table = {
|
||||
main = {
|
||||
icon = "resources/icons/appbar.pokeball.png",
|
||||
},
|
||||
navi = {
|
||||
icon = "resources/icons/appbar.page.corner.bookmark.png",
|
||||
},
|
||||
typeset = {
|
||||
icon = "resources/icons/appbar.page.text.png",
|
||||
},
|
||||
home = {
|
||||
icon = "resources/icons/appbar.home.png",
|
||||
callback = function()
|
||||
self.ui:handleEvent(Event:new("RestoreScreenMode",
|
||||
G_reader_settings:readSetting("screen_mode") or "portrait"))
|
||||
UIManager:close(self.menu_container)
|
||||
self.ui:onClose()
|
||||
end,
|
||||
},
|
||||
}
|
||||
self.registered_widgets = {}
|
||||
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ShowMenu = { { "Menu" }, doc = _("show menu") },
|
||||
}
|
||||
end
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ShowMenu = { { "Menu" }, doc = _("show menu") },
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderMenu:initGesListener()
|
||||
self.ges_events = {
|
||||
TapShowMenu = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = Screen:getWidth()*DTAP_ZONE_MENU.x,
|
||||
y = Screen:getHeight()*DTAP_ZONE_MENU.y,
|
||||
w = Screen:getWidth()*DTAP_ZONE_MENU.w,
|
||||
h = Screen:getHeight()*DTAP_ZONE_MENU.h
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
self.ges_events = {
|
||||
TapShowMenu = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = Screen:getWidth()*DTAP_ZONE_MENU.x,
|
||||
y = Screen:getHeight()*DTAP_ZONE_MENU.y,
|
||||
w = Screen:getWidth()*DTAP_ZONE_MENU.w,
|
||||
h = Screen:getHeight()*DTAP_ZONE_MENU.h
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
function ReaderMenu:setUpdateItemTable()
|
||||
for _, widget in pairs(self.registered_widgets) do
|
||||
widget:addToMainMenu(self.tab_item_table)
|
||||
end
|
||||
for _, widget in pairs(self.registered_widgets) do
|
||||
widget:addToMainMenu(self.tab_item_table)
|
||||
end
|
||||
|
||||
table.insert(self.tab_item_table.main, {
|
||||
text = _("Help"),
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Please report bugs to https://github.com/koreader/ koreader/issues, Click at the bottom of the page for more options"),
|
||||
})
|
||||
end
|
||||
})
|
||||
table.insert(self.tab_item_table.main, {
|
||||
text = _("Version"),
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = io.open("git-rev", "r"):read(),
|
||||
})
|
||||
end
|
||||
})
|
||||
table.insert(self.tab_item_table.main, Language:getLangMenuTable())
|
||||
table.insert(self.tab_item_table.main, {
|
||||
text = _("Help"),
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Please report bugs to https://github.com/koreader/ koreader/issues, Click at the bottom of the page for more options"),
|
||||
})
|
||||
end
|
||||
})
|
||||
table.insert(self.tab_item_table.main, {
|
||||
text = _("Version"),
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = io.open("git-rev", "r"):read(),
|
||||
})
|
||||
end
|
||||
})
|
||||
table.insert(self.tab_item_table.main, Language:getLangMenuTable())
|
||||
end
|
||||
|
||||
function ReaderMenu:onShowReaderMenu()
|
||||
if #self.tab_item_table.main == 0 then
|
||||
self:setUpdateItemTable()
|
||||
end
|
||||
if #self.tab_item_table.main == 0 then
|
||||
self:setUpdateItemTable()
|
||||
end
|
||||
|
||||
local menu_container = CenterContainer:new{
|
||||
ignore = "height",
|
||||
dimen = Screen:getSize(),
|
||||
}
|
||||
local menu_container = CenterContainer:new{
|
||||
ignore = "height",
|
||||
dimen = Screen:getSize(),
|
||||
}
|
||||
|
||||
local main_menu = nil
|
||||
if Device:isTouchDevice() then
|
||||
main_menu = TouchMenu:new{
|
||||
width = Screen:getWidth(),
|
||||
tab_item_table = {
|
||||
self.tab_item_table.navi,
|
||||
self.tab_item_table.typeset,
|
||||
self.tab_item_table.main,
|
||||
self.tab_item_table.home,
|
||||
},
|
||||
show_parent = menu_container,
|
||||
}
|
||||
else
|
||||
main_menu = Menu:new{
|
||||
title = _("Document menu"),
|
||||
item_table = {},
|
||||
width = Screen:getWidth() - 100,
|
||||
}
|
||||
local main_menu = nil
|
||||
if Device:isTouchDevice() then
|
||||
main_menu = TouchMenu:new{
|
||||
width = Screen:getWidth(),
|
||||
tab_item_table = {
|
||||
self.tab_item_table.navi,
|
||||
self.tab_item_table.typeset,
|
||||
self.tab_item_table.main,
|
||||
self.tab_item_table.home,
|
||||
},
|
||||
show_parent = menu_container,
|
||||
}
|
||||
else
|
||||
main_menu = Menu:new{
|
||||
title = _("Document menu"),
|
||||
item_table = {},
|
||||
width = Screen:getWidth() - 100,
|
||||
}
|
||||
|
||||
for _,item_table in pairs(self.tab_item_table) do
|
||||
for k,v in ipairs(item_table) do
|
||||
table.insert(main_menu.item_table, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
for _,item_table in pairs(self.tab_item_table) do
|
||||
for k,v in ipairs(item_table) do
|
||||
table.insert(main_menu.item_table, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
main_menu.close_callback = function ()
|
||||
UIManager:close(menu_container)
|
||||
end
|
||||
main_menu.close_callback = function ()
|
||||
UIManager:close(menu_container)
|
||||
end
|
||||
|
||||
menu_container[1] = main_menu
|
||||
-- maintain a reference to menu_container
|
||||
self.menu_container = menu_container
|
||||
UIManager:show(menu_container)
|
||||
menu_container[1] = main_menu
|
||||
-- maintain a reference to menu_container
|
||||
self.menu_container = menu_container
|
||||
UIManager:show(menu_container)
|
||||
|
||||
return true
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderMenu:onTapShowMenu()
|
||||
self.ui:handleEvent(Event:new("ShowConfigMenu"))
|
||||
self.ui:handleEvent(Event:new("ShowReaderMenu"))
|
||||
return true
|
||||
self.ui:handleEvent(Event:new("ShowConfigMenu"))
|
||||
self.ui:handleEvent(Event:new("ShowReaderMenu"))
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderMenu:onSetDimensions(dimen)
|
||||
-- update listening according to new screen dimen
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
-- update listening according to new screen dimen
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderMenu:onSaveSettings()
|
||||
end
|
||||
|
||||
function ReaderMenu:registerToMainMenu(widget)
|
||||
table.insert(self.registered_widgets, widget)
|
||||
table.insert(self.registered_widgets, widget)
|
||||
end
|
||||
|
||||
return ReaderMenu
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,48 +4,48 @@ local DEBUG = require("dbg")
|
||||
local _ = require("gettext")
|
||||
|
||||
local ReaderPanning = InputContainer:new{
|
||||
-- defaults
|
||||
panning_steps = {
|
||||
normal = 50,
|
||||
alt = 25,
|
||||
shift = 10,
|
||||
altshift = 5
|
||||
},
|
||||
-- defaults
|
||||
panning_steps = {
|
||||
normal = 50,
|
||||
alt = 25,
|
||||
shift = 10,
|
||||
altshift = 5
|
||||
},
|
||||
}
|
||||
|
||||
function ReaderPanning:init()
|
||||
if Device:isTouchDevice() then
|
||||
else
|
||||
self.key_events = {
|
||||
-- these will all generate the same event, just with different arguments
|
||||
MoveUp = {
|
||||
{ "Up" }, doc = _("move visible area up"),
|
||||
event = "Panning", args = {0, -1} },
|
||||
MoveDown = {
|
||||
{ "Down" }, doc = _("move visible area down"),
|
||||
event = "Panning", args = {0, 1} },
|
||||
MoveLeft = {
|
||||
{ "Left" }, doc = _("move visible area left"),
|
||||
event = "Panning", args = {-1, 0} },
|
||||
MoveRight = {
|
||||
{ "Right" }, doc = _("move visible area right"),
|
||||
event = "Panning", args = {1, 0} },
|
||||
}
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
else
|
||||
self.key_events = {
|
||||
-- these will all generate the same event, just with different arguments
|
||||
MoveUp = {
|
||||
{ "Up" }, doc = _("move visible area up"),
|
||||
event = "Panning", args = {0, -1} },
|
||||
MoveDown = {
|
||||
{ "Down" }, doc = _("move visible area down"),
|
||||
event = "Panning", args = {0, 1} },
|
||||
MoveLeft = {
|
||||
{ "Left" }, doc = _("move visible area left"),
|
||||
event = "Panning", args = {-1, 0} },
|
||||
MoveRight = {
|
||||
{ "Right" }, doc = _("move visible area right"),
|
||||
event = "Panning", args = {1, 0} },
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderPanning:onSetDimensions(dimensions)
|
||||
self.dimen = dimensions
|
||||
self.dimen = dimensions
|
||||
end
|
||||
|
||||
function ReaderPanning:onPanning(args, key)
|
||||
local dx, dy = unpack(args)
|
||||
DEBUG("key =", key)
|
||||
-- for now, bounds checking/calculation is done in the view
|
||||
self.view:PanningUpdate(
|
||||
dx * self.panning_steps.normal * self.dimen.w / 100,
|
||||
dy * self.panning_steps.normal * self.dimen.h / 100)
|
||||
return true
|
||||
local dx, dy = unpack(args)
|
||||
DEBUG("key =", key)
|
||||
-- for now, bounds checking/calculation is done in the view
|
||||
self.view:PanningUpdate(
|
||||
dx * self.panning_steps.normal * self.dimen.w / 100,
|
||||
dy * self.panning_steps.normal * self.dimen.h / 100)
|
||||
return true
|
||||
end
|
||||
|
||||
return ReaderPanning
|
||||
|
||||
@@ -11,363 +11,363 @@ 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,
|
||||
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
|
||||
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)
|
||||
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,
|
||||
}
|
||||
},
|
||||
}
|
||||
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
|
||||
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())
|
||||
-- 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
|
||||
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
|
||||
self:onGotoViewRel(1)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderRolling:onTapBackward()
|
||||
self:onGotoViewRel(-1)
|
||||
return true
|
||||
self:onGotoViewRel(-1)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderRolling:onSwipe(arg, ges)
|
||||
if ges.direction == "west" or ges.direction == "north" then
|
||||
self:onGotoViewRel(1)
|
||||
elseif ges.direction == "east" or ges.direction == "south" then
|
||||
self:onGotoViewRel(-1)
|
||||
end
|
||||
return true
|
||||
if ges.direction == "west" or ges.direction == "north" then
|
||||
self:onGotoViewRel(1)
|
||||
elseif ges.direction == "east" or ges.direction == "south" then
|
||||
self:onGotoViewRel(-1)
|
||||
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
|
||||
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:updateBatteryState()
|
||||
self.current_pos = new_pos
|
||||
self:updateBatteryState()
|
||||
end
|
||||
|
||||
function ReaderRolling:onPageUpdate(new_page)
|
||||
self.current_page = new_page
|
||||
self:updateBatteryState()
|
||||
self.current_page = new_page
|
||||
self:updateBatteryState()
|
||||
end
|
||||
|
||||
function ReaderRolling:onResume()
|
||||
self:updateBatteryState()
|
||||
self:updateBatteryState()
|
||||
end
|
||||
|
||||
function ReaderRolling:onNotCharging()
|
||||
self:updateBatteryState()
|
||||
self:updateBatteryState()
|
||||
end
|
||||
|
||||
function ReaderRolling:onGotoPercent(percent)
|
||||
DEBUG("goto document offset in percent:", percent)
|
||||
self:gotoPercent(percent)
|
||||
return true
|
||||
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
|
||||
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
|
||||
--@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()
|
||||
--@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.
|
||||
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
|
||||
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
|
||||
-- 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
|
||||
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
|
||||
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
|
||||
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
|
||||
-- update listening according to new screen dimen
|
||||
if Device:isTouchDevice() then
|
||||
self:initGesListener()
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderRolling:onChangeScreenMode(mode)
|
||||
self.ui:handleEvent(Event:new("SetScreenMode", mode))
|
||||
self:onChangeViewMode()
|
||||
self.ui:handleEvent(Event:new("SetScreenMode", mode))
|
||||
self:onChangeViewMode()
|
||||
end
|
||||
|
||||
--[[
|
||||
PosUpdate event is used to signal other widgets that pos has been changed.
|
||||
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))
|
||||
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()))
|
||||
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
|
||||
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)
|
||||
self:gotoPos(new_percent * self.doc_height / 10000)
|
||||
end
|
||||
|
||||
function ReaderRolling:onGotoPage(number)
|
||||
self:gotoPage(number)
|
||||
return true
|
||||
self:gotoPage(number)
|
||||
return true
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -375,20 +375,20 @@ currently we don't need to get page links on each page/pos update
|
||||
since we can check link on the fly when tapping on the screen
|
||||
--]]
|
||||
function ReaderRolling:updatePageLink()
|
||||
DEBUG("update page link")
|
||||
local links = self.ui.document:getPageLinks()
|
||||
self.view.links = links
|
||||
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
|
||||
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
|
||||
|
||||
@@ -7,72 +7,72 @@ local GestureRange = require("ui/gesturerange")
|
||||
local _ = require("gettext")
|
||||
|
||||
local ReaderRotation = InputContainer:new{
|
||||
ROTATE_ANGLE_THRESHOLD = 15,
|
||||
current_rotation = 0
|
||||
ROTATE_ANGLE_THRESHOLD = 15,
|
||||
current_rotation = 0
|
||||
}
|
||||
|
||||
function ReaderRotation:init()
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
-- these will all generate the same event, just with different arguments
|
||||
RotateLeft = {
|
||||
{"J"},
|
||||
doc = _("rotate left by 90 degrees"),
|
||||
event = "Rotate", args = -90 },
|
||||
RotateRight = {
|
||||
{"K"},
|
||||
doc = _("rotate right by 90 degrees"),
|
||||
event = "Rotate", args = 90 },
|
||||
}
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
RotateGes = {
|
||||
GestureRange:new{
|
||||
ges = "rotate",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
},
|
||||
TwoFingerPanRelease = {
|
||||
GestureRange:new{
|
||||
ges = "two_finger_pan_release",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
-- these will all generate the same event, just with different arguments
|
||||
RotateLeft = {
|
||||
{"J"},
|
||||
doc = _("rotate left by 90 degrees"),
|
||||
event = "Rotate", args = -90 },
|
||||
RotateRight = {
|
||||
{"K"},
|
||||
doc = _("rotate right by 90 degrees"),
|
||||
event = "Rotate", args = 90 },
|
||||
}
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
RotateGes = {
|
||||
GestureRange:new{
|
||||
ges = "rotate",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
},
|
||||
TwoFingerPanRelease = {
|
||||
GestureRange:new{
|
||||
ges = "two_finger_pan_release",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO: reset rotation on new document, maybe on new page?
|
||||
|
||||
function ReaderRotation:onRotate(rotate_by)
|
||||
self.current_rotation = (self.current_rotation + rotate_by) % 360
|
||||
self.ui:handleEvent(Event:new("RotationUpdate", self.current_rotation))
|
||||
return true
|
||||
self.current_rotation = (self.current_rotation + rotate_by) % 360
|
||||
self.ui:handleEvent(Event:new("RotationUpdate", self.current_rotation))
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderRotation:onRotateGes(arg, ges)
|
||||
self.rotate_angle = ges.angle
|
||||
return true
|
||||
self.rotate_angle = ges.angle
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderRotation:onTwoFingerPanRelease(arg, ges)
|
||||
if self.rotate_angle and self.rotate_angle > self.ROTATE_ANGLE_THRESHOLD then
|
||||
if Screen:getScreenMode() == "portrait" then
|
||||
self.ui:handleEvent(Event:new("SetScreenMode", "landscape"))
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetScreenMode", "portrait"))
|
||||
end
|
||||
self.rotate_angle = nil
|
||||
end
|
||||
if self.rotate_angle and self.rotate_angle > self.ROTATE_ANGLE_THRESHOLD then
|
||||
if Screen:getScreenMode() == "portrait" then
|
||||
self.ui:handleEvent(Event:new("SetScreenMode", "landscape"))
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetScreenMode", "portrait"))
|
||||
end
|
||||
self.rotate_angle = nil
|
||||
end
|
||||
end
|
||||
|
||||
return ReaderRotation
|
||||
|
||||
@@ -10,36 +10,36 @@ local DEBUG = require("dbg")
|
||||
local ReaderScreenshot = InputContainer:new{}
|
||||
|
||||
function ReaderScreenshot:init()
|
||||
local diagonal = math.sqrt(
|
||||
math.pow(Screen:getWidth(), 2) +
|
||||
math.pow(Screen:getHeight(), 2)
|
||||
)
|
||||
self.ges_events = {
|
||||
Screenshot = {
|
||||
GestureRange:new{
|
||||
ges = "two_finger_tap",
|
||||
scale = {diagonal - Screen:scaleByDPI(100), diagonal},
|
||||
rate = 1.0,
|
||||
}
|
||||
},
|
||||
}
|
||||
local diagonal = math.sqrt(
|
||||
math.pow(Screen:getWidth(), 2) +
|
||||
math.pow(Screen:getHeight(), 2)
|
||||
)
|
||||
self.ges_events = {
|
||||
Screenshot = {
|
||||
GestureRange:new{
|
||||
ges = "two_finger_tap",
|
||||
scale = {diagonal - Screen:scaleByDPI(100), diagonal},
|
||||
rate = 1.0,
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
function ReaderScreenshot:onScreenshot()
|
||||
if Device:getModel() ~= 'Kobo_phoenix' then
|
||||
os.execute("screenshot")
|
||||
else Screen.bb:invert()
|
||||
local screenshot_name = os.date("screenshots/Screenshot_%Y-%B-%d_%Hh%M.pam")
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Writing screen to ")..screenshot_name,
|
||||
timeout = 2,
|
||||
})
|
||||
Screen.bb:writePAM(screenshot_name)
|
||||
DEBUG(screenshot_name)
|
||||
Screen.bb:invert()
|
||||
end
|
||||
UIManager.full_refresh = true
|
||||
return true
|
||||
if Device:getModel() ~= 'Kobo_phoenix' then
|
||||
os.execute("screenshot")
|
||||
else Screen.bb:invert()
|
||||
local screenshot_name = os.date("screenshots/Screenshot_%Y-%B-%d_%Hh%M.pam")
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Writing screen to ")..screenshot_name,
|
||||
timeout = 2,
|
||||
})
|
||||
Screen.bb:writePAM(screenshot_name)
|
||||
DEBUG(screenshot_name)
|
||||
Screen.bb:invert()
|
||||
end
|
||||
UIManager.full_refresh = true
|
||||
return true
|
||||
end
|
||||
|
||||
return ReaderScreenshot
|
||||
|
||||
@@ -10,135 +10,135 @@ local Event = require("ui/event")
|
||||
local _ = require("gettext")
|
||||
|
||||
local ReaderToc = InputContainer:new{
|
||||
toc = nil,
|
||||
toc_menu_title = _("Table of contents"),
|
||||
toc = nil,
|
||||
toc_menu_title = _("Table of contents"),
|
||||
}
|
||||
|
||||
function ReaderToc:init()
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ShowToc = {
|
||||
{ "T" },
|
||||
doc = _("show Table of Content menu") },
|
||||
}
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
ShowToc = {
|
||||
GestureRange:new{
|
||||
ges = "two_finger_swipe",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
},
|
||||
direction = "east"
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ShowToc = {
|
||||
{ "T" },
|
||||
doc = _("show Table of Content menu") },
|
||||
}
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
ShowToc = {
|
||||
GestureRange:new{
|
||||
ges = "two_finger_swipe",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
},
|
||||
direction = "east"
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function ReaderToc:cleanUpTocTitle(title)
|
||||
return (title:gsub("\13", ""))
|
||||
return (title:gsub("\13", ""))
|
||||
end
|
||||
|
||||
function ReaderToc:onSetDimensions(dimen)
|
||||
self.dimen = dimen
|
||||
self.dimen = dimen
|
||||
end
|
||||
|
||||
function ReaderToc:onUpdateToc()
|
||||
self.toc = nil
|
||||
return true
|
||||
self.toc = nil
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderToc:fillToc()
|
||||
self.toc = self.ui.document:getToc()
|
||||
self.toc = self.ui.document:getToc()
|
||||
end
|
||||
|
||||
-- _getTocTitleByPage wrapper, so specific reader
|
||||
-- can tranform pageno according its need
|
||||
function ReaderToc:getTocTitleByPage(pn_or_xp)
|
||||
local page = pn_or_xp
|
||||
if type(pn_or_xp) == "string" then
|
||||
page = self.ui.document:getPageFromXPointer(pn_or_xp)
|
||||
end
|
||||
return self:_getTocTitleByPage(page)
|
||||
local page = pn_or_xp
|
||||
if type(pn_or_xp) == "string" then
|
||||
page = self.ui.document:getPageFromXPointer(pn_or_xp)
|
||||
end
|
||||
return self:_getTocTitleByPage(page)
|
||||
end
|
||||
|
||||
function ReaderToc:_getTocTitleByPage(pageno)
|
||||
if not self.toc then
|
||||
-- build toc when needed.
|
||||
self:fillToc()
|
||||
end
|
||||
if not self.toc then
|
||||
-- build toc when needed.
|
||||
self:fillToc()
|
||||
end
|
||||
|
||||
-- no table of content
|
||||
if #self.toc == 0 then
|
||||
return ""
|
||||
end
|
||||
-- no table of content
|
||||
if #self.toc == 0 then
|
||||
return ""
|
||||
end
|
||||
|
||||
local pre_entry = self.toc[1]
|
||||
for _k,_v in ipairs(self.toc) do
|
||||
if _v.page > pageno then
|
||||
break
|
||||
end
|
||||
pre_entry = _v
|
||||
end
|
||||
return self:cleanUpTocTitle(pre_entry.title)
|
||||
local pre_entry = self.toc[1]
|
||||
for _k,_v in ipairs(self.toc) do
|
||||
if _v.page > pageno then
|
||||
break
|
||||
end
|
||||
pre_entry = _v
|
||||
end
|
||||
return self:cleanUpTocTitle(pre_entry.title)
|
||||
end
|
||||
|
||||
function ReaderToc:getTocTitleOfCurrentPage()
|
||||
return self:getTocTitleByPage(self.pageno)
|
||||
return self:getTocTitleByPage(self.pageno)
|
||||
end
|
||||
|
||||
function ReaderToc:onShowToc()
|
||||
if not self.toc then
|
||||
self:fillToc()
|
||||
end
|
||||
-- build menu items
|
||||
if #self.toc > 0 and not self.toc[1].text then
|
||||
for _,v in ipairs(self.toc) do
|
||||
v.text = (" "):rep(v.depth-1)..self:cleanUpTocTitle(v.title)
|
||||
v.mandatory = v.page
|
||||
end
|
||||
end
|
||||
if not self.toc then
|
||||
self:fillToc()
|
||||
end
|
||||
-- build menu items
|
||||
if #self.toc > 0 and not self.toc[1].text then
|
||||
for _,v in ipairs(self.toc) do
|
||||
v.text = (" "):rep(v.depth-1)..self:cleanUpTocTitle(v.title)
|
||||
v.mandatory = v.page
|
||||
end
|
||||
end
|
||||
|
||||
local menu_container = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
}
|
||||
local menu_container = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
}
|
||||
|
||||
local toc_menu = Menu:new{
|
||||
title = _("Table of Contents"),
|
||||
item_table = self.toc,
|
||||
ui = self.ui,
|
||||
width = Screen:getWidth()-50,
|
||||
height = Screen:getHeight()-50,
|
||||
show_parent = menu_container,
|
||||
}
|
||||
local toc_menu = Menu:new{
|
||||
title = _("Table of Contents"),
|
||||
item_table = self.toc,
|
||||
ui = self.ui,
|
||||
width = Screen:getWidth()-50,
|
||||
height = Screen:getHeight()-50,
|
||||
show_parent = menu_container,
|
||||
}
|
||||
|
||||
table.insert(menu_container, toc_menu)
|
||||
table.insert(menu_container, toc_menu)
|
||||
|
||||
function toc_menu:onMenuChoice(item)
|
||||
self.ui:handleEvent(Event:new("PageUpdate", item.page))
|
||||
end
|
||||
function toc_menu:onMenuChoice(item)
|
||||
self.ui:handleEvent(Event:new("PageUpdate", item.page))
|
||||
end
|
||||
|
||||
toc_menu.close_callback = function()
|
||||
UIManager:close(menu_container)
|
||||
end
|
||||
toc_menu.close_callback = function()
|
||||
UIManager:close(menu_container)
|
||||
end
|
||||
|
||||
UIManager:show(menu_container)
|
||||
return true
|
||||
UIManager:show(menu_container)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderToc:addToMainMenu(tab_item_table)
|
||||
-- insert table to main reader menu
|
||||
table.insert(tab_item_table.navi, {
|
||||
text = self.toc_menu_title,
|
||||
callback = function()
|
||||
self:onShowToc()
|
||||
end,
|
||||
})
|
||||
-- insert table to main reader menu
|
||||
table.insert(tab_item_table.navi, {
|
||||
text = self.toc_menu_title,
|
||||
callback = function()
|
||||
self:onShowToc()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
return ReaderToc
|
||||
|
||||
@@ -6,121 +6,121 @@ local _ = require("gettext")
|
||||
-- lfs
|
||||
|
||||
local ReaderTypeset = InputContainer:new{
|
||||
css_menu_title = _("Set render style"),
|
||||
css = nil,
|
||||
internal_css = true,
|
||||
css_menu_title = _("Set render style"),
|
||||
css = nil,
|
||||
internal_css = true,
|
||||
}
|
||||
|
||||
function ReaderTypeset:init()
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function ReaderTypeset:onReadSettings(config)
|
||||
self.css = config:readSetting("css")
|
||||
if self.css and self.css ~= "" then
|
||||
self.ui.document:setStyleSheet(self.css)
|
||||
else
|
||||
self.ui.document:setStyleSheet(self.ui.document.default_css)
|
||||
self.css = self.ui.document.default_css
|
||||
end
|
||||
self.css = config:readSetting("css")
|
||||
if self.css and self.css ~= "" then
|
||||
self.ui.document:setStyleSheet(self.css)
|
||||
else
|
||||
self.ui.document:setStyleSheet(self.ui.document.default_css)
|
||||
self.css = self.ui.document.default_css
|
||||
end
|
||||
|
||||
-- default to enable embedded css
|
||||
self.embedded_css = config:readSetting("embedded_css") or true
|
||||
self.ui.document:setEmbeddedStyleSheet(self.embedded_css and 1 or 0)
|
||||
|
||||
-- set page margins
|
||||
self:onSetPageMargins(config:readSetting("copt_page_margins") or DCREREADER_CONFIG_MARGIN_SIZES_MEDIUM)
|
||||
-- default to enable embedded css
|
||||
self.embedded_css = config:readSetting("embedded_css") or true
|
||||
self.ui.document:setEmbeddedStyleSheet(self.embedded_css and 1 or 0)
|
||||
|
||||
-- set page margins
|
||||
self:onSetPageMargins(config:readSetting("copt_page_margins") or DCREREADER_CONFIG_MARGIN_SIZES_MEDIUM)
|
||||
end
|
||||
|
||||
function ReaderTypeset:onSaveSettings()
|
||||
self.ui.doc_settings:saveSetting("css", self.css)
|
||||
self.ui.doc_settings:saveSetting("embedded_css", self.embedded_css)
|
||||
self.ui.doc_settings:saveSetting("css", self.css)
|
||||
self.ui.doc_settings:saveSetting("embedded_css", self.embedded_css)
|
||||
end
|
||||
|
||||
function ReaderTypeset:onToggleEmbeddedStyleSheet(toggle)
|
||||
self:toggleEmbeddedStyleSheet(toggle)
|
||||
return true
|
||||
self:toggleEmbeddedStyleSheet(toggle)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderTypeset:genStyleSheetMenu()
|
||||
local file_list = {
|
||||
{
|
||||
text = _("clear all external styles"),
|
||||
callback = function()
|
||||
self:setStyleSheet(nil)
|
||||
end
|
||||
},
|
||||
{
|
||||
text = _("Auto"),
|
||||
callback = function()
|
||||
self:setStyleSheet(self.ui.document.default_css)
|
||||
end
|
||||
},
|
||||
}
|
||||
for f in lfs.dir("./data") do
|
||||
if lfs.attributes("./data/"..f, "mode") == "file" and string.match(f, "%.css$") then
|
||||
table.insert(file_list, {
|
||||
text = f,
|
||||
callback = function()
|
||||
self:setStyleSheet("./data/"..f)
|
||||
end
|
||||
})
|
||||
end
|
||||
end
|
||||
return file_list
|
||||
local file_list = {
|
||||
{
|
||||
text = _("clear all external styles"),
|
||||
callback = function()
|
||||
self:setStyleSheet(nil)
|
||||
end
|
||||
},
|
||||
{
|
||||
text = _("Auto"),
|
||||
callback = function()
|
||||
self:setStyleSheet(self.ui.document.default_css)
|
||||
end
|
||||
},
|
||||
}
|
||||
for f in lfs.dir("./data") do
|
||||
if lfs.attributes("./data/"..f, "mode") == "file" and string.match(f, "%.css$") then
|
||||
table.insert(file_list, {
|
||||
text = f,
|
||||
callback = function()
|
||||
self:setStyleSheet("./data/"..f)
|
||||
end
|
||||
})
|
||||
end
|
||||
end
|
||||
return file_list
|
||||
end
|
||||
|
||||
function ReaderTypeset:setStyleSheet(new_css)
|
||||
if new_css ~= self.css then
|
||||
--DEBUG("setting css to ", new_css)
|
||||
self.css = new_css
|
||||
if new_css == nil then
|
||||
new_css = ""
|
||||
end
|
||||
self.ui.document:setStyleSheet(new_css)
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
end
|
||||
if new_css ~= self.css then
|
||||
--DEBUG("setting css to ", new_css)
|
||||
self.css = new_css
|
||||
if new_css == nil then
|
||||
new_css = ""
|
||||
end
|
||||
self.ui.document:setStyleSheet(new_css)
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderTypeset:setEmbededStyleSheetOnly()
|
||||
if self.css ~= nil then
|
||||
-- clear applied css
|
||||
self.ui.document:setStyleSheet("")
|
||||
self.ui.document:setEmbeddedStyleSheet(1)
|
||||
self.css = nil
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
end
|
||||
if self.css ~= nil then
|
||||
-- clear applied css
|
||||
self.ui.document:setStyleSheet("")
|
||||
self.ui.document:setEmbeddedStyleSheet(1)
|
||||
self.css = nil
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderTypeset:toggleEmbeddedStyleSheet(toggle)
|
||||
if not toggle then
|
||||
self.embedded_css = false
|
||||
self:setStyleSheet(self.ui.document.default_css)
|
||||
self.ui.document:setEmbeddedStyleSheet(0)
|
||||
else
|
||||
self.embedded_css = true
|
||||
--self:setStyleSheet(self.ui.document.default_css)
|
||||
self.ui.document:setEmbeddedStyleSheet(1)
|
||||
end
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
if not toggle then
|
||||
self.embedded_css = false
|
||||
self:setStyleSheet(self.ui.document.default_css)
|
||||
self.ui.document:setEmbeddedStyleSheet(0)
|
||||
else
|
||||
self.embedded_css = true
|
||||
--self:setStyleSheet(self.ui.document.default_css)
|
||||
self.ui.document:setEmbeddedStyleSheet(1)
|
||||
end
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
end
|
||||
|
||||
function ReaderTypeset:addToMainMenu(tab_item_table)
|
||||
-- insert table to main reader menu
|
||||
table.insert(tab_item_table.typeset, {
|
||||
text = self.css_menu_title,
|
||||
sub_item_table = self:genStyleSheetMenu(),
|
||||
})
|
||||
-- insert table to main reader menu
|
||||
table.insert(tab_item_table.typeset, {
|
||||
text = self.css_menu_title,
|
||||
sub_item_table = self:genStyleSheetMenu(),
|
||||
})
|
||||
end
|
||||
|
||||
function ReaderTypeset:onSetPageMargins(margins)
|
||||
local left = Screen:scaleByDPI(margins[1])
|
||||
local top = Screen:scaleByDPI(margins[2])
|
||||
local right = Screen:scaleByDPI(margins[3])
|
||||
local bottom = Screen:scaleByDPI(margins[4])
|
||||
self.ui.document:setPageMargins(left, top, right, bottom)
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
return true
|
||||
local left = Screen:scaleByDPI(margins[1])
|
||||
local top = Screen:scaleByDPI(margins[2])
|
||||
local right = Screen:scaleByDPI(margins[3])
|
||||
local bottom = Screen:scaleByDPI(margins[4])
|
||||
self.ui.document:setPageMargins(left, top, right, bottom)
|
||||
self.ui:handleEvent(Event:new("UpdatePos"))
|
||||
return true
|
||||
end
|
||||
|
||||
return ReaderTypeset
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,315 +9,315 @@ local DEBUG = require("dbg")
|
||||
local _ = require("gettext")
|
||||
|
||||
local ReaderZooming = InputContainer:new{
|
||||
zoom = 1.0,
|
||||
-- default to nil so we can trigger ZoomModeUpdate events on start up
|
||||
zoom_mode = nil,
|
||||
DEFAULT_ZOOM_MODE = "page",
|
||||
current_page = 1,
|
||||
rotation = 0
|
||||
zoom = 1.0,
|
||||
-- default to nil so we can trigger ZoomModeUpdate events on start up
|
||||
zoom_mode = nil,
|
||||
DEFAULT_ZOOM_MODE = "page",
|
||||
current_page = 1,
|
||||
rotation = 0
|
||||
}
|
||||
|
||||
function ReaderZooming:init()
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ZoomIn = {
|
||||
{ "Shift", Input.group.PgFwd },
|
||||
doc = _("zoom in"),
|
||||
event = "Zoom", args = "in"
|
||||
},
|
||||
ZoomOut = {
|
||||
{ "Shift", Input.group.PgBack },
|
||||
doc = _("zoom out"),
|
||||
event = "Zoom", args = "out"
|
||||
},
|
||||
ZoomToFitPage = {
|
||||
{ "A" },
|
||||
doc = _("zoom to fit page"),
|
||||
event = "SetZoomMode", args = "page"
|
||||
},
|
||||
ZoomToFitContent = {
|
||||
{ "Shift", "A" },
|
||||
doc = _("zoom to fit content"),
|
||||
event = "SetZoomMode", args = "content"
|
||||
},
|
||||
ZoomToFitPageWidth = {
|
||||
{ "S" },
|
||||
doc = _("zoom to fit page width"),
|
||||
event = "SetZoomMode", args = "pagewidth"
|
||||
},
|
||||
ZoomToFitContentWidth = {
|
||||
{ "Shift", "S" },
|
||||
doc = _("zoom to fit content width"),
|
||||
event = "SetZoomMode", args = "contentwidth"
|
||||
},
|
||||
ZoomToFitPageHeight = {
|
||||
{ "D" },
|
||||
doc = _("zoom to fit page height"),
|
||||
event = "SetZoomMode", args = "pageheight"
|
||||
},
|
||||
ZoomToFitContentHeight = {
|
||||
{ "Shift", "D" },
|
||||
doc = _("zoom to fit content height"),
|
||||
event = "SetZoomMode", args = "contentheight"
|
||||
},
|
||||
}
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
Spread = {
|
||||
GestureRange:new{
|
||||
ges = "spread",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
},
|
||||
Pinch = {
|
||||
GestureRange:new{
|
||||
ges = "pinch",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
},
|
||||
ToggleFreeZoom = {
|
||||
GestureRange:new{
|
||||
ges = "double_tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ZoomIn = {
|
||||
{ "Shift", Input.group.PgFwd },
|
||||
doc = _("zoom in"),
|
||||
event = "Zoom", args = "in"
|
||||
},
|
||||
ZoomOut = {
|
||||
{ "Shift", Input.group.PgBack },
|
||||
doc = _("zoom out"),
|
||||
event = "Zoom", args = "out"
|
||||
},
|
||||
ZoomToFitPage = {
|
||||
{ "A" },
|
||||
doc = _("zoom to fit page"),
|
||||
event = "SetZoomMode", args = "page"
|
||||
},
|
||||
ZoomToFitContent = {
|
||||
{ "Shift", "A" },
|
||||
doc = _("zoom to fit content"),
|
||||
event = "SetZoomMode", args = "content"
|
||||
},
|
||||
ZoomToFitPageWidth = {
|
||||
{ "S" },
|
||||
doc = _("zoom to fit page width"),
|
||||
event = "SetZoomMode", args = "pagewidth"
|
||||
},
|
||||
ZoomToFitContentWidth = {
|
||||
{ "Shift", "S" },
|
||||
doc = _("zoom to fit content width"),
|
||||
event = "SetZoomMode", args = "contentwidth"
|
||||
},
|
||||
ZoomToFitPageHeight = {
|
||||
{ "D" },
|
||||
doc = _("zoom to fit page height"),
|
||||
event = "SetZoomMode", args = "pageheight"
|
||||
},
|
||||
ZoomToFitContentHeight = {
|
||||
{ "Shift", "D" },
|
||||
doc = _("zoom to fit content height"),
|
||||
event = "SetZoomMode", args = "contentheight"
|
||||
},
|
||||
}
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
Spread = {
|
||||
GestureRange:new{
|
||||
ges = "spread",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
},
|
||||
Pinch = {
|
||||
GestureRange:new{
|
||||
ges = "pinch",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
},
|
||||
ToggleFreeZoom = {
|
||||
GestureRange:new{
|
||||
ges = "double_tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function ReaderZooming:onReadSettings(config)
|
||||
-- @TODO config file from old code base uses globalzoom_mode
|
||||
-- instead of zoom_mode, we need to handle this imcompatibility
|
||||
-- 04.12 2012 (houqp)
|
||||
local zoom_mode = config:readSetting("zoom_mode")
|
||||
if not zoom_mode then
|
||||
zoom_mode = self.DEFAULT_ZOOM_MODE
|
||||
end
|
||||
self:setZoomMode(zoom_mode)
|
||||
-- @TODO config file from old code base uses globalzoom_mode
|
||||
-- instead of zoom_mode, we need to handle this imcompatibility
|
||||
-- 04.12 2012 (houqp)
|
||||
local zoom_mode = config:readSetting("zoom_mode")
|
||||
if not zoom_mode then
|
||||
zoom_mode = self.DEFAULT_ZOOM_MODE
|
||||
end
|
||||
self:setZoomMode(zoom_mode)
|
||||
end
|
||||
|
||||
function ReaderZooming:onSaveSettings()
|
||||
self.ui.doc_settings:saveSetting("zoom_mode", self.zoom_mode)
|
||||
self.ui.doc_settings:saveSetting("zoom_mode", self.zoom_mode)
|
||||
end
|
||||
|
||||
function ReaderZooming:onSpread(arg, ges)
|
||||
if ges.direction == "horizontal" then
|
||||
self:genSetZoomModeCallBack("contentwidth")()
|
||||
elseif ges.direction == "vertical" then
|
||||
self:genSetZoomModeCallBack("contentheight")()
|
||||
elseif ges.direction == "diagonal" then
|
||||
self:genSetZoomModeCallBack("content")()
|
||||
end
|
||||
return true
|
||||
if ges.direction == "horizontal" then
|
||||
self:genSetZoomModeCallBack("contentwidth")()
|
||||
elseif ges.direction == "vertical" then
|
||||
self:genSetZoomModeCallBack("contentheight")()
|
||||
elseif ges.direction == "diagonal" then
|
||||
self:genSetZoomModeCallBack("content")()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderZooming:onPinch(arg, ges)
|
||||
if ges.direction == "diagonal" then
|
||||
self:genSetZoomModeCallBack("page")()
|
||||
elseif ges.direction == "horizontal" then
|
||||
self:genSetZoomModeCallBack("pagewidth")()
|
||||
elseif ges.direction == "vertical" then
|
||||
self:genSetZoomModeCallBack("pageheight")()
|
||||
end
|
||||
return true
|
||||
if ges.direction == "diagonal" then
|
||||
self:genSetZoomModeCallBack("page")()
|
||||
elseif ges.direction == "horizontal" then
|
||||
self:genSetZoomModeCallBack("pagewidth")()
|
||||
elseif ges.direction == "vertical" then
|
||||
self:genSetZoomModeCallBack("pageheight")()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderZooming:onToggleFreeZoom(arg, ges)
|
||||
if self.zoom_mode ~= "free" then
|
||||
self.orig_zoom = self.zoom
|
||||
self.orig_zoom_mode = self.zoom_mode
|
||||
local xpos, ypos
|
||||
self.zoom, xpos, ypos = self:getRegionalZoomCenter(self.current_page, ges.pos)
|
||||
DEBUG("zoom center", self.zoom, xpos, ypos)
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", "free"))
|
||||
if xpos == nil or ypos == nil then
|
||||
xpos = ges.pos.x * self.zoom / self.orig_zoom
|
||||
ypos = ges.pos.y * self.zoom / self.orig_zoom
|
||||
end
|
||||
self.view:SetZoomCenter(xpos, ypos)
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", self.orig_zoom_mode or "page"))
|
||||
end
|
||||
if self.zoom_mode ~= "free" then
|
||||
self.orig_zoom = self.zoom
|
||||
self.orig_zoom_mode = self.zoom_mode
|
||||
local xpos, ypos
|
||||
self.zoom, xpos, ypos = self:getRegionalZoomCenter(self.current_page, ges.pos)
|
||||
DEBUG("zoom center", self.zoom, xpos, ypos)
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", "free"))
|
||||
if xpos == nil or ypos == nil then
|
||||
xpos = ges.pos.x * self.zoom / self.orig_zoom
|
||||
ypos = ges.pos.y * self.zoom / self.orig_zoom
|
||||
end
|
||||
self.view:SetZoomCenter(xpos, ypos)
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", self.orig_zoom_mode or "page"))
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderZooming:onSetDimensions(dimensions)
|
||||
-- we were resized
|
||||
self.dimen = dimensions
|
||||
self:setZoom()
|
||||
-- we were resized
|
||||
self.dimen = dimensions
|
||||
self:setZoom()
|
||||
end
|
||||
|
||||
function ReaderZooming:onRestoreDimensions(dimensions)
|
||||
-- we were resized
|
||||
self.dimen = dimensions
|
||||
self:setZoom()
|
||||
-- we were resized
|
||||
self.dimen = dimensions
|
||||
self:setZoom()
|
||||
end
|
||||
|
||||
function ReaderZooming:onRotationUpdate(rotation)
|
||||
self.rotation = rotation
|
||||
self:setZoom()
|
||||
self.rotation = rotation
|
||||
self:setZoom()
|
||||
end
|
||||
|
||||
function ReaderZooming:onZoom(direction)
|
||||
DEBUG("zoom", direction)
|
||||
if direction == "in" then
|
||||
self.zoom = self.zoom * 1.333333
|
||||
elseif direction == "out" then
|
||||
self.zoom = self.zoom * 0.75
|
||||
end
|
||||
DEBUG("zoom is now at", self.zoom)
|
||||
self:onSetZoomMode("free")
|
||||
self.view:onZoomUpdate(self.zoom)
|
||||
return true
|
||||
DEBUG("zoom", direction)
|
||||
if direction == "in" then
|
||||
self.zoom = self.zoom * 1.333333
|
||||
elseif direction == "out" then
|
||||
self.zoom = self.zoom * 0.75
|
||||
end
|
||||
DEBUG("zoom is now at", self.zoom)
|
||||
self:onSetZoomMode("free")
|
||||
self.view:onZoomUpdate(self.zoom)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderZooming:onSetZoomMode(new_mode)
|
||||
self.view.zoom_mode = new_mode
|
||||
if self.zoom_mode ~= new_mode then
|
||||
DEBUG("setting zoom mode to", new_mode)
|
||||
self.ui:handleEvent(Event:new("ZoomModeUpdate", new_mode))
|
||||
self.zoom_mode = new_mode
|
||||
self:setZoom()
|
||||
end
|
||||
self.view.zoom_mode = new_mode
|
||||
if self.zoom_mode ~= new_mode then
|
||||
DEBUG("setting zoom mode to", new_mode)
|
||||
self.ui:handleEvent(Event:new("ZoomModeUpdate", new_mode))
|
||||
self.zoom_mode = new_mode
|
||||
self:setZoom()
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderZooming:onPageUpdate(new_page_no)
|
||||
self.current_page = new_page_no
|
||||
self:setZoom()
|
||||
self.current_page = new_page_no
|
||||
self:setZoom()
|
||||
end
|
||||
|
||||
function ReaderZooming:onReZoom()
|
||||
self:setZoom()
|
||||
self.ui:handleEvent(Event:new("InitScrollPageStates"))
|
||||
return true
|
||||
self:setZoom()
|
||||
self.ui:handleEvent(Event:new("InitScrollPageStates"))
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderZooming:getZoom(pageno)
|
||||
-- check if we're in bbox mode and work on bbox if that's the case
|
||||
local zoom = nil
|
||||
local page_size = {}
|
||||
if self.zoom_mode == "content"
|
||||
or self.zoom_mode == "contentwidth"
|
||||
or self.zoom_mode == "contentheight" then
|
||||
local ubbox_dimen = self.ui.document:getUsedBBoxDimensions(pageno, 1)
|
||||
--self.view:handleEvent(Event:new("BBoxUpdate", page_size))
|
||||
self.view:onBBoxUpdate(ubbox_dimen)
|
||||
page_size = ubbox_dimen
|
||||
else
|
||||
-- otherwise, operate on full page
|
||||
self.view:onBBoxUpdate(nil)
|
||||
page_size = self.ui.document:getNativePageDimensions(pageno)
|
||||
--page_size = self.ui.document:getPageDimensions(pageno, 1, 0)
|
||||
end
|
||||
-- calculate zoom value:
|
||||
local zoom_w = self.dimen.w / page_size.w
|
||||
local zoom_h = self.dimen.h / page_size.h
|
||||
if self.rotation % 180 ~= 0 then
|
||||
-- rotated by 90 or 270 degrees
|
||||
zoom_w = self.dimen.w / page_size.h
|
||||
zoom_h = self.dimen.h / page_size.w
|
||||
end
|
||||
if self.zoom_mode == "content" or self.zoom_mode == "page" then
|
||||
if zoom_w < zoom_h then
|
||||
zoom = zoom_w
|
||||
else
|
||||
zoom = zoom_h
|
||||
end
|
||||
elseif self.zoom_mode == "contentwidth" or self.zoom_mode == "pagewidth" then
|
||||
zoom = zoom_w
|
||||
elseif self.zoom_mode == "contentheight" or self.zoom_mode == "pageheight" then
|
||||
zoom = zoom_h
|
||||
elseif self.zoom_mode == "free" then
|
||||
zoom = self.zoom
|
||||
end
|
||||
return zoom
|
||||
-- check if we're in bbox mode and work on bbox if that's the case
|
||||
local zoom = nil
|
||||
local page_size = {}
|
||||
if self.zoom_mode == "content"
|
||||
or self.zoom_mode == "contentwidth"
|
||||
or self.zoom_mode == "contentheight" then
|
||||
local ubbox_dimen = self.ui.document:getUsedBBoxDimensions(pageno, 1)
|
||||
--self.view:handleEvent(Event:new("BBoxUpdate", page_size))
|
||||
self.view:onBBoxUpdate(ubbox_dimen)
|
||||
page_size = ubbox_dimen
|
||||
else
|
||||
-- otherwise, operate on full page
|
||||
self.view:onBBoxUpdate(nil)
|
||||
page_size = self.ui.document:getNativePageDimensions(pageno)
|
||||
--page_size = self.ui.document:getPageDimensions(pageno, 1, 0)
|
||||
end
|
||||
-- calculate zoom value:
|
||||
local zoom_w = self.dimen.w / page_size.w
|
||||
local zoom_h = self.dimen.h / page_size.h
|
||||
if self.rotation % 180 ~= 0 then
|
||||
-- rotated by 90 or 270 degrees
|
||||
zoom_w = self.dimen.w / page_size.h
|
||||
zoom_h = self.dimen.h / page_size.w
|
||||
end
|
||||
if self.zoom_mode == "content" or self.zoom_mode == "page" then
|
||||
if zoom_w < zoom_h then
|
||||
zoom = zoom_w
|
||||
else
|
||||
zoom = zoom_h
|
||||
end
|
||||
elseif self.zoom_mode == "contentwidth" or self.zoom_mode == "pagewidth" then
|
||||
zoom = zoom_w
|
||||
elseif self.zoom_mode == "contentheight" or self.zoom_mode == "pageheight" then
|
||||
zoom = zoom_h
|
||||
elseif self.zoom_mode == "free" then
|
||||
zoom = self.zoom
|
||||
end
|
||||
return zoom
|
||||
end
|
||||
|
||||
function ReaderZooming:getRegionalZoomCenter(pageno, pos)
|
||||
local p_pos = self.view:getSinglePagePosition(pos)
|
||||
local page_size = self.ui.document:getNativePageDimensions(pageno)
|
||||
local pos_x = p_pos.x / page_size.w / p_pos.zoom
|
||||
local pos_y = p_pos.y / page_size.h / p_pos.zoom
|
||||
local regions = self.ui.document:getPageRegions(pageno)
|
||||
DEBUG("get page regions", regions)
|
||||
local margin = self.ui.document.configurable.page_margin * Screen:getDPI()
|
||||
for i = 1, #regions do
|
||||
if regions[i].x0 <= pos_x and pos_x <= regions[i].x1
|
||||
and regions[i].y0 <= pos_y and pos_y <= regions[i].y1 then
|
||||
local zoom = 1/(regions[i].x1 - regions[i].x0)
|
||||
zoom = zoom/(1 + 3*margin/zoom/page_size.w)
|
||||
local xpos = (regions[i].x0 + regions[i].x1)/2 * zoom * page_size.w
|
||||
local ypos = p_pos.y / p_pos.zoom * zoom
|
||||
return zoom, xpos, ypos
|
||||
end
|
||||
end
|
||||
return 2
|
||||
local p_pos = self.view:getSinglePagePosition(pos)
|
||||
local page_size = self.ui.document:getNativePageDimensions(pageno)
|
||||
local pos_x = p_pos.x / page_size.w / p_pos.zoom
|
||||
local pos_y = p_pos.y / page_size.h / p_pos.zoom
|
||||
local regions = self.ui.document:getPageRegions(pageno)
|
||||
DEBUG("get page regions", regions)
|
||||
local margin = self.ui.document.configurable.page_margin * Screen:getDPI()
|
||||
for i = 1, #regions do
|
||||
if regions[i].x0 <= pos_x and pos_x <= regions[i].x1
|
||||
and regions[i].y0 <= pos_y and pos_y <= regions[i].y1 then
|
||||
local zoom = 1/(regions[i].x1 - regions[i].x0)
|
||||
zoom = zoom/(1 + 3*margin/zoom/page_size.w)
|
||||
local xpos = (regions[i].x0 + regions[i].x1)/2 * zoom * page_size.w
|
||||
local ypos = p_pos.y / p_pos.zoom * zoom
|
||||
return zoom, xpos, ypos
|
||||
end
|
||||
end
|
||||
return 2
|
||||
end
|
||||
|
||||
function ReaderZooming:setZoom()
|
||||
if not self.dimen then
|
||||
self.dimen = self.ui.dimen
|
||||
end
|
||||
self.zoom = self:getZoom(self.current_page)
|
||||
self.ui:handleEvent(Event:new("ZoomUpdate", self.zoom))
|
||||
if not self.dimen then
|
||||
self.dimen = self.ui.dimen
|
||||
end
|
||||
self.zoom = self:getZoom(self.current_page)
|
||||
self.ui:handleEvent(Event:new("ZoomUpdate", self.zoom))
|
||||
end
|
||||
|
||||
function ReaderZooming:genSetZoomModeCallBack(mode)
|
||||
return function()
|
||||
self:setZoomMode(mode)
|
||||
end
|
||||
return function()
|
||||
self:setZoomMode(mode)
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderZooming:setZoomMode(mode)
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", mode))
|
||||
self.ui:handleEvent(Event:new("InitScrollPageStates"))
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", mode))
|
||||
self.ui:handleEvent(Event:new("InitScrollPageStates"))
|
||||
end
|
||||
|
||||
function ReaderZooming:addToMainMenu(tab_item_table)
|
||||
if self.ui.document.info.has_pages then
|
||||
table.insert(tab_item_table.typeset, {
|
||||
text = _("Switch zoom mode"),
|
||||
sub_item_table = {
|
||||
{
|
||||
text = _("Zoom to fit content width"),
|
||||
callback = self:genSetZoomModeCallBack("contentwidth")
|
||||
},
|
||||
{
|
||||
text = _("Zoom to fit content height"),
|
||||
callback = self:genSetZoomModeCallBack("contentheight")
|
||||
},
|
||||
{
|
||||
text = _("Zoom to fit page width"),
|
||||
callback = self:genSetZoomModeCallBack("pagewidth")
|
||||
},
|
||||
{
|
||||
text = _("Zoom to fit page height"),
|
||||
callback = self:genSetZoomModeCallBack("pageheight")
|
||||
},
|
||||
{
|
||||
text = _("Zoom to fit content"),
|
||||
callback = self:genSetZoomModeCallBack("content")
|
||||
},
|
||||
{
|
||||
text = _("Zoom to fit page"),
|
||||
callback = self:genSetZoomModeCallBack("page")
|
||||
},
|
||||
}
|
||||
})
|
||||
end
|
||||
if self.ui.document.info.has_pages then
|
||||
table.insert(tab_item_table.typeset, {
|
||||
text = _("Switch zoom mode"),
|
||||
sub_item_table = {
|
||||
{
|
||||
text = _("Zoom to fit content width"),
|
||||
callback = self:genSetZoomModeCallBack("contentwidth")
|
||||
},
|
||||
{
|
||||
text = _("Zoom to fit content height"),
|
||||
callback = self:genSetZoomModeCallBack("contentheight")
|
||||
},
|
||||
{
|
||||
text = _("Zoom to fit page width"),
|
||||
callback = self:genSetZoomModeCallBack("pagewidth")
|
||||
},
|
||||
{
|
||||
text = _("Zoom to fit page height"),
|
||||
callback = self:genSetZoomModeCallBack("pageheight")
|
||||
},
|
||||
{
|
||||
text = _("Zoom to fit content"),
|
||||
callback = self:genSetZoomModeCallBack("content")
|
||||
},
|
||||
{
|
||||
text = _("Zoom to fit page"),
|
||||
callback = self:genSetZoomModeCallBack("page")
|
||||
},
|
||||
}
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return ReaderZooming
|
||||
|
||||
@@ -39,256 +39,256 @@ it works using data gathered from a document interface
|
||||
]]--
|
||||
|
||||
local ReaderUI = InputContainer:new{
|
||||
key_events = {
|
||||
Close = { { "Home" },
|
||||
doc = _("close document"), event = "Close" },
|
||||
},
|
||||
active_widgets = {},
|
||||
key_events = {
|
||||
Close = { { "Home" },
|
||||
doc = _("close document"), event = "Close" },
|
||||
},
|
||||
active_widgets = {},
|
||||
|
||||
-- our own size
|
||||
dimen = Geom:new{ w = 400, h = 600 },
|
||||
-- if we have a parent container, it must be referenced for now
|
||||
dialog = nil,
|
||||
-- our own size
|
||||
dimen = Geom:new{ w = 400, h = 600 },
|
||||
-- if we have a parent container, it must be referenced for now
|
||||
dialog = nil,
|
||||
|
||||
-- the document interface
|
||||
document = nil,
|
||||
-- the document interface
|
||||
document = nil,
|
||||
|
||||
-- initial page or percent inside document on opening
|
||||
start_pos = nil,
|
||||
-- password for document unlock
|
||||
password = nil,
|
||||
-- initial page or percent inside document on opening
|
||||
start_pos = nil,
|
||||
-- password for document unlock
|
||||
password = nil,
|
||||
|
||||
postInitCallback = nil,
|
||||
postInitCallback = nil,
|
||||
}
|
||||
|
||||
function ReaderUI:init()
|
||||
self.postInitCallback = {}
|
||||
-- if we are not the top level dialog ourselves, it must be given in the table
|
||||
if not self.dialog then
|
||||
self.dialog = self
|
||||
end
|
||||
self.postInitCallback = {}
|
||||
-- if we are not the top level dialog ourselves, it must be given in the table
|
||||
if not self.dialog then
|
||||
self.dialog = self
|
||||
end
|
||||
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events.Back = {
|
||||
{ "Back" }, doc = _("close document"),
|
||||
event = "Close" }
|
||||
end
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events.Back = {
|
||||
{ "Back" }, doc = _("close document"),
|
||||
event = "Close" }
|
||||
end
|
||||
|
||||
self.doc_settings = DocSettings:open(self.document.file)
|
||||
self.doc_settings = DocSettings:open(self.document.file)
|
||||
|
||||
-- a view container (so it must be child #1!)
|
||||
self[1] = ReaderView:new{
|
||||
dialog = self.dialog,
|
||||
dimen = self.dimen,
|
||||
ui = self,
|
||||
document = self.document,
|
||||
}
|
||||
-- reader menu controller
|
||||
-- hold reference to menu widget
|
||||
self.menu = ReaderMenu:new{
|
||||
view = self[1],
|
||||
ui = self
|
||||
}
|
||||
-- link
|
||||
table.insert(self, ReaderLink:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
-- text highlight
|
||||
table.insert(self, ReaderHighlight:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
-- menu widget should be registered after link widget and highlight widget
|
||||
-- so that taps on link and highlight areas won't popup reader menu
|
||||
table.insert(self, self.menu)
|
||||
-- rotation controller
|
||||
table.insert(self, ReaderRotation:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
-- Table of content controller
|
||||
-- hold reference to bm widget
|
||||
self.toc = ReaderToc:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
}
|
||||
table.insert(self, self.toc)
|
||||
-- bookmark controller
|
||||
table.insert(self, ReaderBookmark:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
-- reader goto controller
|
||||
table.insert(self, ReaderGoto:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
-- dictionary
|
||||
table.insert(self, ReaderDictionary:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
-- screenshot controller
|
||||
table.insert(self.active_widgets, ReaderScreenshot:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
-- frontlight controller
|
||||
if Device:hasFrontlight() then
|
||||
table.insert(self, ReaderFrontLight:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
end
|
||||
-- configuable controller
|
||||
if self.document.info.configurable then
|
||||
-- config panel controller
|
||||
table.insert(self, ReaderConfig:new{
|
||||
configurable = self.document.configurable,
|
||||
options = self.document.options,
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
if not self.document.info.has_pages then
|
||||
-- cre option controller
|
||||
table.insert(self, ReaderCoptListener:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
end
|
||||
end
|
||||
-- for page specific controller
|
||||
if self.document.info.has_pages then
|
||||
-- cropping controller
|
||||
table.insert(self, ReaderCropping:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
-- paging controller
|
||||
table.insert(self, ReaderPaging:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
-- zooming controller
|
||||
local zoom = ReaderZooming:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
}
|
||||
table.insert(self, zoom)
|
||||
-- panning controller
|
||||
table.insert(self, ReaderPanning:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
-- hinting controller
|
||||
table.insert(self, ReaderHinting:new{
|
||||
dialog = self.dialog,
|
||||
zoom = zoom,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
else
|
||||
-- make sure we load document first before calling any callback
|
||||
table.insert(self.postInitCallback, function()
|
||||
self.document:loadDocument()
|
||||
end)
|
||||
-- typeset controller
|
||||
table.insert(self, ReaderTypeset:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
-- font menu
|
||||
self.font = ReaderFont:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
}
|
||||
table.insert(self, self.font) -- hold reference to font menu
|
||||
-- hyphenation menu
|
||||
self.hyphenation = ReaderHyphenation:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
}
|
||||
table.insert(self, self.hyphenation) -- hold reference to hyphenation menu
|
||||
-- rolling controller
|
||||
table.insert(self, ReaderRolling:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
end
|
||||
-- configuable controller
|
||||
if self.document.info.configurable then
|
||||
if self.document.info.has_pages then
|
||||
-- kopt option controller
|
||||
table.insert(self, ReaderKoptListener:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
end
|
||||
-- activity indicator
|
||||
table.insert(self, ReaderActivityIndicator:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
end
|
||||
--DEBUG(self.doc_settings)
|
||||
-- we only read settings after all the widgets are initialized
|
||||
self:handleEvent(Event:new("ReadSettings", self.doc_settings))
|
||||
-- a view container (so it must be child #1!)
|
||||
self[1] = ReaderView:new{
|
||||
dialog = self.dialog,
|
||||
dimen = self.dimen,
|
||||
ui = self,
|
||||
document = self.document,
|
||||
}
|
||||
-- reader menu controller
|
||||
-- hold reference to menu widget
|
||||
self.menu = ReaderMenu:new{
|
||||
view = self[1],
|
||||
ui = self
|
||||
}
|
||||
-- link
|
||||
table.insert(self, ReaderLink:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
-- text highlight
|
||||
table.insert(self, ReaderHighlight:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
-- menu widget should be registered after link widget and highlight widget
|
||||
-- so that taps on link and highlight areas won't popup reader menu
|
||||
table.insert(self, self.menu)
|
||||
-- rotation controller
|
||||
table.insert(self, ReaderRotation:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
-- Table of content controller
|
||||
-- hold reference to bm widget
|
||||
self.toc = ReaderToc:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
}
|
||||
table.insert(self, self.toc)
|
||||
-- bookmark controller
|
||||
table.insert(self, ReaderBookmark:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
-- reader goto controller
|
||||
table.insert(self, ReaderGoto:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
-- dictionary
|
||||
table.insert(self, ReaderDictionary:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
-- screenshot controller
|
||||
table.insert(self.active_widgets, ReaderScreenshot:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
-- frontlight controller
|
||||
if Device:hasFrontlight() then
|
||||
table.insert(self, ReaderFrontLight:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
end
|
||||
-- configuable controller
|
||||
if self.document.info.configurable then
|
||||
-- config panel controller
|
||||
table.insert(self, ReaderConfig:new{
|
||||
configurable = self.document.configurable,
|
||||
options = self.document.options,
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
if not self.document.info.has_pages then
|
||||
-- cre option controller
|
||||
table.insert(self, ReaderCoptListener:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
end
|
||||
end
|
||||
-- for page specific controller
|
||||
if self.document.info.has_pages then
|
||||
-- cropping controller
|
||||
table.insert(self, ReaderCropping:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
-- paging controller
|
||||
table.insert(self, ReaderPaging:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
-- zooming controller
|
||||
local zoom = ReaderZooming:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
}
|
||||
table.insert(self, zoom)
|
||||
-- panning controller
|
||||
table.insert(self, ReaderPanning:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
-- hinting controller
|
||||
table.insert(self, ReaderHinting:new{
|
||||
dialog = self.dialog,
|
||||
zoom = zoom,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
else
|
||||
-- make sure we load document first before calling any callback
|
||||
table.insert(self.postInitCallback, function()
|
||||
self.document:loadDocument()
|
||||
end)
|
||||
-- typeset controller
|
||||
table.insert(self, ReaderTypeset:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
-- font menu
|
||||
self.font = ReaderFont:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
}
|
||||
table.insert(self, self.font) -- hold reference to font menu
|
||||
-- hyphenation menu
|
||||
self.hyphenation = ReaderHyphenation:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
}
|
||||
table.insert(self, self.hyphenation) -- hold reference to hyphenation menu
|
||||
-- rolling controller
|
||||
table.insert(self, ReaderRolling:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
})
|
||||
end
|
||||
-- configuable controller
|
||||
if self.document.info.configurable then
|
||||
if self.document.info.has_pages then
|
||||
-- kopt option controller
|
||||
table.insert(self, ReaderKoptListener:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
end
|
||||
-- activity indicator
|
||||
table.insert(self, ReaderActivityIndicator:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self,
|
||||
document = self.document,
|
||||
})
|
||||
end
|
||||
--DEBUG(self.doc_settings)
|
||||
-- we only read settings after all the widgets are initialized
|
||||
self:handleEvent(Event:new("ReadSettings", self.doc_settings))
|
||||
|
||||
for _,v in ipairs(self.postInitCallback) do
|
||||
v()
|
||||
end
|
||||
for _,v in ipairs(self.postInitCallback) do
|
||||
v()
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderUI:onSetDimensions(dimen)
|
||||
self.dimen = dimen
|
||||
self.dimen = dimen
|
||||
end
|
||||
|
||||
function ReaderUI:saveSettings()
|
||||
self:handleEvent(Event:new("SaveSettings"))
|
||||
self.doc_settings:flush()
|
||||
self:handleEvent(Event:new("SaveSettings"))
|
||||
self.doc_settings:flush()
|
||||
end
|
||||
|
||||
function ReaderUI:onClose()
|
||||
DEBUG("closing reader")
|
||||
self:saveSettings()
|
||||
if self.document ~= nil then
|
||||
self.document:close()
|
||||
self.document = nil
|
||||
self.start_pos = nil
|
||||
end
|
||||
UIManager:close(self.dialog)
|
||||
return true
|
||||
DEBUG("closing reader")
|
||||
self:saveSettings()
|
||||
if self.document ~= nil then
|
||||
self.document:close()
|
||||
self.document = nil
|
||||
self.start_pos = nil
|
||||
end
|
||||
UIManager:close(self.dialog)
|
||||
return true
|
||||
end
|
||||
|
||||
return ReaderUI
|
||||
|
||||
@@ -10,170 +10,170 @@ TODO: all these functions should probably be methods on Face objects
|
||||
local RenderText = {}
|
||||
|
||||
local GlyphCache = Cache:new{
|
||||
max_memsize = 512*1024,
|
||||
current_memsize = 0,
|
||||
cache = {},
|
||||
-- this will hold the LRU order of the cache
|
||||
cache_order = {}
|
||||
max_memsize = 512*1024,
|
||||
current_memsize = 0,
|
||||
cache = {},
|
||||
-- this will hold the LRU order of the cache
|
||||
cache_order = {}
|
||||
}
|
||||
|
||||
-- iterator over UTF8 encoded characters in a string
|
||||
local function utf8Chars(input)
|
||||
local function read_next_glyph(input, pos)
|
||||
if string.len(input) < pos then return nil end
|
||||
local value = string.byte(input, pos)
|
||||
if bit.band(value, 0x80) == 0 then
|
||||
-- TODO: check valid ranges
|
||||
return pos+1, value, string.sub(input, pos, pos)
|
||||
elseif bit.band(value, 0xC0) == 0x80 -- invalid, continuation
|
||||
or bit.band(value, 0xF8) == 0xF8 -- 5-or-more byte sequence, illegal due to RFC3629
|
||||
then
|
||||
return pos+1, 0xFFFD, "\xFF\xFD"
|
||||
else
|
||||
local glyph, bytes_left
|
||||
if bit.band(value, 0xE0) == 0xC0 then
|
||||
glyph = bit.band(value, 0x1F)
|
||||
bytes_left = 1
|
||||
elseif bit.band(value, 0xF0) == 0xE0 then
|
||||
glyph = bit.band(value, 0x0F)
|
||||
bytes_left = 2
|
||||
elseif bit.band(value, 0xF8) == 0xF0 then
|
||||
glyph = bit.band(value, 0x07)
|
||||
bytes_left = 3
|
||||
else
|
||||
return pos+1, 0xFFFD, "\xFF\xFD"
|
||||
end
|
||||
if string.len(input) < (pos + bytes_left - 1) then
|
||||
return pos+1, 0xFFFD, "\xFF\xFD"
|
||||
end
|
||||
for i = pos+1, pos + bytes_left do
|
||||
value = string.byte(input, i)
|
||||
if bit.band(value, 0xC0) == 0x80 then
|
||||
glyph = bit.bor(bit.lshift(glyph, 6), bit.band(value, 0x3F))
|
||||
else
|
||||
return i+1, 0xFFFD, "\xFF\xFD"
|
||||
end
|
||||
end
|
||||
-- TODO: check for valid ranges here!
|
||||
return pos+bytes_left+1, glyph, string.sub(input, pos, pos+bytes_left)
|
||||
end
|
||||
end
|
||||
return read_next_glyph, input, 1
|
||||
local function read_next_glyph(input, pos)
|
||||
if string.len(input) < pos then return nil end
|
||||
local value = string.byte(input, pos)
|
||||
if bit.band(value, 0x80) == 0 then
|
||||
-- TODO: check valid ranges
|
||||
return pos+1, value, string.sub(input, pos, pos)
|
||||
elseif bit.band(value, 0xC0) == 0x80 -- invalid, continuation
|
||||
or bit.band(value, 0xF8) == 0xF8 -- 5-or-more byte sequence, illegal due to RFC3629
|
||||
then
|
||||
return pos+1, 0xFFFD, "\xFF\xFD"
|
||||
else
|
||||
local glyph, bytes_left
|
||||
if bit.band(value, 0xE0) == 0xC0 then
|
||||
glyph = bit.band(value, 0x1F)
|
||||
bytes_left = 1
|
||||
elseif bit.band(value, 0xF0) == 0xE0 then
|
||||
glyph = bit.band(value, 0x0F)
|
||||
bytes_left = 2
|
||||
elseif bit.band(value, 0xF8) == 0xF0 then
|
||||
glyph = bit.band(value, 0x07)
|
||||
bytes_left = 3
|
||||
else
|
||||
return pos+1, 0xFFFD, "\xFF\xFD"
|
||||
end
|
||||
if string.len(input) < (pos + bytes_left - 1) then
|
||||
return pos+1, 0xFFFD, "\xFF\xFD"
|
||||
end
|
||||
for i = pos+1, pos + bytes_left do
|
||||
value = string.byte(input, i)
|
||||
if bit.band(value, 0xC0) == 0x80 then
|
||||
glyph = bit.bor(bit.lshift(glyph, 6), bit.band(value, 0x3F))
|
||||
else
|
||||
return i+1, 0xFFFD, "\xFF\xFD"
|
||||
end
|
||||
end
|
||||
-- TODO: check for valid ranges here!
|
||||
return pos+bytes_left+1, glyph, string.sub(input, pos, pos+bytes_left)
|
||||
end
|
||||
end
|
||||
return read_next_glyph, input, 1
|
||||
end
|
||||
|
||||
function RenderText:getGlyph(face, charcode, bold, bgcolor, fgcolor)
|
||||
if bgcolor == nil then bgcolor = 0.0 end
|
||||
if fgcolor == nil then fgcolor = 1.0 end
|
||||
local hash = "glyph|"..face.hash.."|"..charcode.."|"..(bold and 1 or 0).."|"..bgcolor.."|"..fgcolor
|
||||
local glyph = GlyphCache:check(hash)
|
||||
if glyph then
|
||||
-- cache hit
|
||||
return glyph[1]
|
||||
end
|
||||
local rendered_glyph = face.ftface:renderGlyph(charcode, bgcolor, fgcolor, bold)
|
||||
if face.ftface:checkGlyph(charcode) == 0 then
|
||||
for index, font in pairs(Font.fallbacks) do
|
||||
-- rescale face size by DPI since it will be scaled in getFace again
|
||||
local fb_face = Font:getFace(font, Screen:rescaleByDPI(face.size))
|
||||
if fb_face.ftface:checkGlyph(charcode) ~= 0 then
|
||||
rendered_glyph = fb_face.ftface:renderGlyph(charcode, bgcolor, fgcolor, bold)
|
||||
--DEBUG("fallback to font", font)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not rendered_glyph then
|
||||
DEBUG("error rendering glyph (charcode=", charcode, ") for face", face)
|
||||
return
|
||||
end
|
||||
glyph = CacheItem:new{rendered_glyph}
|
||||
glyph.size = glyph[1].bb:getWidth() * glyph[1].bb:getHeight() / 2 + 32
|
||||
GlyphCache:insert(hash, glyph)
|
||||
return rendered_glyph
|
||||
if bgcolor == nil then bgcolor = 0.0 end
|
||||
if fgcolor == nil then fgcolor = 1.0 end
|
||||
local hash = "glyph|"..face.hash.."|"..charcode.."|"..(bold and 1 or 0).."|"..bgcolor.."|"..fgcolor
|
||||
local glyph = GlyphCache:check(hash)
|
||||
if glyph then
|
||||
-- cache hit
|
||||
return glyph[1]
|
||||
end
|
||||
local rendered_glyph = face.ftface:renderGlyph(charcode, bgcolor, fgcolor, bold)
|
||||
if face.ftface:checkGlyph(charcode) == 0 then
|
||||
for index, font in pairs(Font.fallbacks) do
|
||||
-- rescale face size by DPI since it will be scaled in getFace again
|
||||
local fb_face = Font:getFace(font, Screen:rescaleByDPI(face.size))
|
||||
if fb_face.ftface:checkGlyph(charcode) ~= 0 then
|
||||
rendered_glyph = fb_face.ftface:renderGlyph(charcode, bgcolor, fgcolor, bold)
|
||||
--DEBUG("fallback to font", font)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not rendered_glyph then
|
||||
DEBUG("error rendering glyph (charcode=", charcode, ") for face", face)
|
||||
return
|
||||
end
|
||||
glyph = CacheItem:new{rendered_glyph}
|
||||
glyph.size = glyph[1].bb:getWidth() * glyph[1].bb:getHeight() / 2 + 32
|
||||
GlyphCache:insert(hash, glyph)
|
||||
return rendered_glyph
|
||||
end
|
||||
|
||||
function RenderText:getSubTextByWidth(text, face, width, kerning, bold)
|
||||
local pen_x = 0
|
||||
local prevcharcode = 0
|
||||
local char_list = {}
|
||||
for _, charcode, uchar in utf8Chars(text) do
|
||||
if pen_x < width then
|
||||
local glyph = self:getGlyph(face, charcode, bold)
|
||||
if kerning and prevcharcode then
|
||||
local kern = face.ftface:getKerning(prevcharcode, charcode)
|
||||
pen_x = pen_x + kern
|
||||
end
|
||||
pen_x = pen_x + glyph.ax
|
||||
if pen_x <= width then
|
||||
prevcharcode = charcode
|
||||
table.insert(char_list, uchar)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.concat(char_list)
|
||||
local pen_x = 0
|
||||
local prevcharcode = 0
|
||||
local char_list = {}
|
||||
for _, charcode, uchar in utf8Chars(text) do
|
||||
if pen_x < width then
|
||||
local glyph = self:getGlyph(face, charcode, bold)
|
||||
if kerning and prevcharcode then
|
||||
local kern = face.ftface:getKerning(prevcharcode, charcode)
|
||||
pen_x = pen_x + kern
|
||||
end
|
||||
pen_x = pen_x + glyph.ax
|
||||
if pen_x <= width then
|
||||
prevcharcode = charcode
|
||||
table.insert(char_list, uchar)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.concat(char_list)
|
||||
end
|
||||
|
||||
function RenderText:sizeUtf8Text(x, width, face, text, kerning, bold)
|
||||
if not text then
|
||||
DEBUG("sizeUtf8Text called without text");
|
||||
return
|
||||
end
|
||||
if not text then
|
||||
DEBUG("sizeUtf8Text called without text");
|
||||
return
|
||||
end
|
||||
|
||||
-- may still need more adaptive pen placement when kerning,
|
||||
-- see: http://freetype.org/freetype2/docs/glyphs/glyphs-4.html
|
||||
local pen_x = 0
|
||||
local pen_y_top = 0
|
||||
local pen_y_bottom = 0
|
||||
local prevcharcode = 0
|
||||
for _, charcode, uchar in utf8Chars(text) do
|
||||
if pen_x < (width - x) then
|
||||
local glyph = self:getGlyph(face, charcode, bold)
|
||||
if kerning and (prevcharcode ~= 0) then
|
||||
pen_x = pen_x + (face.ftface):getKerning(prevcharcode, charcode)
|
||||
end
|
||||
pen_x = pen_x + glyph.ax
|
||||
pen_y_top = math.max(pen_y_top, glyph.t)
|
||||
pen_y_bottom = math.max(pen_y_bottom, glyph.bb:getHeight() - glyph.t)
|
||||
--DEBUG("ax:"..glyph.ax.." t:"..glyph.t.." r:"..glyph.r.." h:"..glyph.bb:getHeight().." w:"..glyph.bb:getWidth().." yt:"..pen_y_top.." yb:"..pen_y_bottom)
|
||||
prevcharcode = charcode
|
||||
end -- if pen_x < (width - x)
|
||||
end
|
||||
return { x = pen_x, y_top = pen_y_top, y_bottom = pen_y_bottom}
|
||||
-- may still need more adaptive pen placement when kerning,
|
||||
-- see: http://freetype.org/freetype2/docs/glyphs/glyphs-4.html
|
||||
local pen_x = 0
|
||||
local pen_y_top = 0
|
||||
local pen_y_bottom = 0
|
||||
local prevcharcode = 0
|
||||
for _, charcode, uchar in utf8Chars(text) do
|
||||
if pen_x < (width - x) then
|
||||
local glyph = self:getGlyph(face, charcode, bold)
|
||||
if kerning and (prevcharcode ~= 0) then
|
||||
pen_x = pen_x + (face.ftface):getKerning(prevcharcode, charcode)
|
||||
end
|
||||
pen_x = pen_x + glyph.ax
|
||||
pen_y_top = math.max(pen_y_top, glyph.t)
|
||||
pen_y_bottom = math.max(pen_y_bottom, glyph.bb:getHeight() - glyph.t)
|
||||
--DEBUG("ax:"..glyph.ax.." t:"..glyph.t.." r:"..glyph.r.." h:"..glyph.bb:getHeight().." w:"..glyph.bb:getWidth().." yt:"..pen_y_top.." yb:"..pen_y_bottom)
|
||||
prevcharcode = charcode
|
||||
end -- if pen_x < (width - x)
|
||||
end
|
||||
return { x = pen_x, y_top = pen_y_top, y_bottom = pen_y_bottom}
|
||||
end
|
||||
|
||||
function RenderText:renderUtf8Text(buffer, x, y, face, text, kerning, bold, bgcolor, fgcolor, width)
|
||||
if not text then
|
||||
DEBUG("renderUtf8Text called without text");
|
||||
return 0
|
||||
end
|
||||
if not text then
|
||||
DEBUG("renderUtf8Text called without text");
|
||||
return 0
|
||||
end
|
||||
|
||||
-- may still need more adaptive pen placement when kerning,
|
||||
-- see: http://freetype.org/freetype2/docs/glyphs/glyphs-4.html
|
||||
local pen_x = 0
|
||||
local prevcharcode = 0
|
||||
local text_width = buffer:getWidth() - x
|
||||
if width and width < text_width then
|
||||
text_width = width
|
||||
end
|
||||
for _, charcode, uchar in utf8Chars(text) do
|
||||
if pen_x < text_width then
|
||||
local glyph = self:getGlyph(face, charcode, bold, bgcolor, fgcolor)
|
||||
if kerning and (prevcharcode ~= 0) then
|
||||
pen_x = pen_x + face.ftface:getKerning(prevcharcode, charcode)
|
||||
end
|
||||
buffer:addblitFrom(
|
||||
glyph.bb,
|
||||
x + pen_x + glyph.l, y - glyph.t,
|
||||
0, 0,
|
||||
glyph.bb:getWidth(), glyph.bb:getHeight(), 1)
|
||||
pen_x = pen_x + glyph.ax
|
||||
prevcharcode = charcode
|
||||
end -- if pen_x < text_width
|
||||
end
|
||||
-- may still need more adaptive pen placement when kerning,
|
||||
-- see: http://freetype.org/freetype2/docs/glyphs/glyphs-4.html
|
||||
local pen_x = 0
|
||||
local prevcharcode = 0
|
||||
local text_width = buffer:getWidth() - x
|
||||
if width and width < text_width then
|
||||
text_width = width
|
||||
end
|
||||
for _, charcode, uchar in utf8Chars(text) do
|
||||
if pen_x < text_width then
|
||||
local glyph = self:getGlyph(face, charcode, bold, bgcolor, fgcolor)
|
||||
if kerning and (prevcharcode ~= 0) then
|
||||
pen_x = pen_x + face.ftface:getKerning(prevcharcode, charcode)
|
||||
end
|
||||
buffer:addblitFrom(
|
||||
glyph.bb,
|
||||
x + pen_x + glyph.l, y - glyph.t,
|
||||
0, 0,
|
||||
glyph.bb:getWidth(), glyph.bb:getHeight(), 1)
|
||||
pen_x = pen_x + glyph.ax
|
||||
prevcharcode = charcode
|
||||
end -- if pen_x < text_width
|
||||
end
|
||||
|
||||
return pen_x
|
||||
return pen_x
|
||||
end
|
||||
|
||||
return RenderText
|
||||
|
||||
@@ -1,104 +1,104 @@
|
||||
local TimeVal = {
|
||||
sec = 0,
|
||||
usec = 0,
|
||||
sec = 0,
|
||||
usec = 0,
|
||||
}
|
||||
|
||||
function TimeVal:new(o)
|
||||
local o = o or {}
|
||||
if o.sec == nil then
|
||||
o.sec = 0
|
||||
end
|
||||
if o.usec == nil then
|
||||
o.usec = 0
|
||||
elseif o.usec > 1000000 then
|
||||
o.sec = o.sec + maht.floor(o.usec/1000000)
|
||||
o.usec = o.usec % 1000000
|
||||
end
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
local o = o or {}
|
||||
if o.sec == nil then
|
||||
o.sec = 0
|
||||
end
|
||||
if o.usec == nil then
|
||||
o.usec = 0
|
||||
elseif o.usec > 1000000 then
|
||||
o.sec = o.sec + maht.floor(o.usec/1000000)
|
||||
o.usec = o.usec % 1000000
|
||||
end
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
|
||||
function TimeVal:__lt(time_b)
|
||||
if self.sec < time_b.sec then
|
||||
return true
|
||||
elseif self.sec > time_b.sec then
|
||||
return false
|
||||
else
|
||||
-- self.sec == time_b.sec
|
||||
if self.usec < time_b.usec then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
if self.sec < time_b.sec then
|
||||
return true
|
||||
elseif self.sec > time_b.sec then
|
||||
return false
|
||||
else
|
||||
-- self.sec == time_b.sec
|
||||
if self.usec < time_b.usec then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function TimeVal:__le(time_b)
|
||||
if self.sec < time_b.sec then
|
||||
return true
|
||||
elseif self.sec > time_b.sec then
|
||||
return false
|
||||
else
|
||||
-- self.sec == time_b.sec
|
||||
if self.usec > time_b.usec then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
if self.sec < time_b.sec then
|
||||
return true
|
||||
elseif self.sec > time_b.sec then
|
||||
return false
|
||||
else
|
||||
-- self.sec == time_b.sec
|
||||
if self.usec > time_b.usec then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function TimeVal:__eq(time_b)
|
||||
if self.sec == time_b.sec and self.usec == time_b.usec then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
if self.sec == time_b.sec and self.usec == time_b.usec then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function TimeVal:__sub(time_b)
|
||||
local diff = TimeVal:new{}
|
||||
local diff = TimeVal:new{}
|
||||
|
||||
diff.sec = self.sec - time_b.sec
|
||||
diff.usec = self.usec - time_b.usec
|
||||
diff.sec = self.sec - time_b.sec
|
||||
diff.usec = self.usec - time_b.usec
|
||||
|
||||
if diff.sec < 0 and diff.usec > 0 then
|
||||
diff.sec = diff.sec + 1
|
||||
diff.usec = diff.usec - 1000000
|
||||
elseif diff.sec > 0 and diff.usec < 0 then
|
||||
diff.sec = diff.sec - 1
|
||||
diff.usec = diff.usec + 1000000
|
||||
end
|
||||
if diff.sec < 0 and diff.usec > 0 then
|
||||
diff.sec = diff.sec + 1
|
||||
diff.usec = diff.usec - 1000000
|
||||
elseif diff.sec > 0 and diff.usec < 0 then
|
||||
diff.sec = diff.sec - 1
|
||||
diff.usec = diff.usec + 1000000
|
||||
end
|
||||
|
||||
return diff
|
||||
return diff
|
||||
end
|
||||
|
||||
function TimeVal:__add(time_b)
|
||||
local sum = TimeVal:new{}
|
||||
local sum = TimeVal:new{}
|
||||
|
||||
sum.sec = self.sec + time_b.sec
|
||||
sum.usec = self.usec + time_b.usec
|
||||
if sum.usec > 1000000 then
|
||||
sum.usec = sum.usec - 1000000
|
||||
sum.sec = sum.sec + 1
|
||||
end
|
||||
sum.sec = self.sec + time_b.sec
|
||||
sum.usec = self.usec + time_b.usec
|
||||
if sum.usec > 1000000 then
|
||||
sum.usec = sum.usec - 1000000
|
||||
sum.sec = sum.sec + 1
|
||||
end
|
||||
|
||||
if sum.sec < 0 and sum.usec > 0 then
|
||||
sum.sec = sum.sec + 1
|
||||
sum.usec = sum.usec - 1000000
|
||||
elseif sum.sec > 0 and sum.usec < 0 then
|
||||
sum.sec = sum.sec - 1
|
||||
sum.usec = sum.usec + 1000000
|
||||
end
|
||||
if sum.sec < 0 and sum.usec > 0 then
|
||||
sum.sec = sum.sec + 1
|
||||
sum.usec = sum.usec - 1000000
|
||||
elseif sum.sec > 0 and sum.usec < 0 then
|
||||
sum.sec = sum.sec - 1
|
||||
sum.usec = sum.usec + 1000000
|
||||
end
|
||||
|
||||
return sum
|
||||
return sum
|
||||
end
|
||||
|
||||
function TimeVal:now()
|
||||
local sec, usec = util.gettime()
|
||||
return TimeVal:new{sec = sec, usec = usec}
|
||||
local sec, usec = util.gettime()
|
||||
return TimeVal:new{sec = sec, usec = usec}
|
||||
end
|
||||
|
||||
return TimeVal
|
||||
|
||||
@@ -10,304 +10,304 @@ Screen:init()
|
||||
-- initialize the input handling
|
||||
Input:init()
|
||||
|
||||
local WAVEFORM_MODE_INIT = 0x0 -- Screen goes to white (clears)
|
||||
local WAVEFORM_MODE_DU = 0x1 -- Grey->white/grey->black
|
||||
local WAVEFORM_MODE_GC16 = 0x2 -- High fidelity (flashing)
|
||||
local WAVEFORM_MODE_GC4 = WAVEFORM_MODE_GC16 -- For compatibility
|
||||
local WAVEFORM_MODE_GC16_FAST = 0x3 -- Medium fidelity
|
||||
local WAVEFORM_MODE_A2 = 0x4 -- Faster but even lower fidelity
|
||||
local WAVEFORM_MODE_GL16 = 0x5 -- High fidelity from white transition
|
||||
local WAVEFORM_MODE_GL16_FAST = 0x6 -- Medium fidelity from white transition
|
||||
local WAVEFORM_MODE_AUTO = 0x101
|
||||
local WAVEFORM_MODE_INIT = 0x0 -- Screen goes to white (clears)
|
||||
local WAVEFORM_MODE_DU = 0x1 -- Grey->white/grey->black
|
||||
local WAVEFORM_MODE_GC16 = 0x2 -- High fidelity (flashing)
|
||||
local WAVEFORM_MODE_GC4 = WAVEFORM_MODE_GC16 -- For compatibility
|
||||
local WAVEFORM_MODE_GC16_FAST = 0x3 -- Medium fidelity
|
||||
local WAVEFORM_MODE_A2 = 0x4 -- Faster but even lower fidelity
|
||||
local WAVEFORM_MODE_GL16 = 0x5 -- High fidelity from white transition
|
||||
local WAVEFORM_MODE_GL16_FAST = 0x6 -- Medium fidelity from white transition
|
||||
local WAVEFORM_MODE_AUTO = 0x101
|
||||
|
||||
-- there is only one instance of this
|
||||
local UIManager = {
|
||||
default_refresh_type = 0, -- 0 for partial refresh, 1 for full refresh
|
||||
default_waveform_mode = WAVEFORM_MODE_GC16, -- high fidelity waveform
|
||||
fast_waveform_mode = WAVEFORM_MODE_A2,
|
||||
-- force to repaint all the widget is stack, will be reset to false
|
||||
-- after each ui loop
|
||||
repaint_all = false,
|
||||
-- force to do full refresh, will be reset to false
|
||||
-- after each ui loop
|
||||
full_refresh = false,
|
||||
-- force to do patial refresh, will be reset to false
|
||||
-- after each ui loop
|
||||
patial_refresh = false,
|
||||
-- trigger a full refresh when counter reaches FULL_REFRESH_COUNT
|
||||
FULL_REFRESH_COUNT = DRCOUNTMAX,
|
||||
refresh_count = 0,
|
||||
default_refresh_type = 0, -- 0 for partial refresh, 1 for full refresh
|
||||
default_waveform_mode = WAVEFORM_MODE_GC16, -- high fidelity waveform
|
||||
fast_waveform_mode = WAVEFORM_MODE_A2,
|
||||
-- force to repaint all the widget is stack, will be reset to false
|
||||
-- after each ui loop
|
||||
repaint_all = false,
|
||||
-- force to do full refresh, will be reset to false
|
||||
-- after each ui loop
|
||||
full_refresh = false,
|
||||
-- force to do patial refresh, will be reset to false
|
||||
-- after each ui loop
|
||||
patial_refresh = false,
|
||||
-- trigger a full refresh when counter reaches FULL_REFRESH_COUNT
|
||||
FULL_REFRESH_COUNT = DRCOUNTMAX,
|
||||
refresh_count = 0,
|
||||
|
||||
_running = true,
|
||||
_window_stack = {},
|
||||
_execution_stack = {},
|
||||
_dirty = {}
|
||||
_running = true,
|
||||
_window_stack = {},
|
||||
_execution_stack = {},
|
||||
_dirty = {}
|
||||
}
|
||||
|
||||
-- register & show a widget
|
||||
function UIManager:show(widget, x, y)
|
||||
-- put widget on top of stack
|
||||
table.insert(self._window_stack, {x = x or 0, y = y or 0, widget = widget})
|
||||
-- and schedule it to be painted
|
||||
self:setDirty(widget)
|
||||
-- tell the widget that it is shown now
|
||||
widget:handleEvent(Event:new("Show"))
|
||||
-- check if this widget disables double tap gesture
|
||||
if widget.disable_double_tap then
|
||||
Input.disable_double_tap = true
|
||||
end
|
||||
-- put widget on top of stack
|
||||
table.insert(self._window_stack, {x = x or 0, y = y or 0, widget = widget})
|
||||
-- and schedule it to be painted
|
||||
self:setDirty(widget)
|
||||
-- tell the widget that it is shown now
|
||||
widget:handleEvent(Event:new("Show"))
|
||||
-- check if this widget disables double tap gesture
|
||||
if widget.disable_double_tap then
|
||||
Input.disable_double_tap = true
|
||||
end
|
||||
end
|
||||
|
||||
-- unregister a widget
|
||||
function UIManager:close(widget)
|
||||
Input.disable_double_tap = DGESDETECT_DISABLE_DOUBLE_TAP
|
||||
local dirty = false
|
||||
for i = #self._window_stack, 1, -1 do
|
||||
if self._window_stack[i].widget == widget then
|
||||
table.remove(self._window_stack, i)
|
||||
dirty = true
|
||||
elseif self._window_stack[i].widget.disable_double_tap then
|
||||
Input.disable_double_tap = true
|
||||
end
|
||||
end
|
||||
if dirty then
|
||||
-- schedule remaining widgets to be painted
|
||||
for i = 1, #self._window_stack do
|
||||
self:setDirty(self._window_stack[i].widget)
|
||||
end
|
||||
end
|
||||
Input.disable_double_tap = DGESDETECT_DISABLE_DOUBLE_TAP
|
||||
local dirty = false
|
||||
for i = #self._window_stack, 1, -1 do
|
||||
if self._window_stack[i].widget == widget then
|
||||
table.remove(self._window_stack, i)
|
||||
dirty = true
|
||||
elseif self._window_stack[i].widget.disable_double_tap then
|
||||
Input.disable_double_tap = true
|
||||
end
|
||||
end
|
||||
if dirty then
|
||||
-- schedule remaining widgets to be painted
|
||||
for i = 1, #self._window_stack do
|
||||
self:setDirty(self._window_stack[i].widget)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- schedule an execution task
|
||||
function UIManager:schedule(time, action)
|
||||
table.insert(self._execution_stack, { time = time, action = action })
|
||||
table.insert(self._execution_stack, { time = time, action = action })
|
||||
end
|
||||
|
||||
-- schedule task in a certain amount of seconds (fractions allowed) from now
|
||||
function UIManager:scheduleIn(seconds, action)
|
||||
local when = { util.gettime() }
|
||||
local s = math.floor(seconds)
|
||||
local usecs = (seconds - s) * 1000000
|
||||
when[1] = when[1] + s
|
||||
when[2] = when[2] + usecs
|
||||
if when[2] > 1000000 then
|
||||
when[1] = when[1] + 1
|
||||
when[2] = when[2] - 1000000
|
||||
end
|
||||
self:schedule(when, action)
|
||||
local when = { util.gettime() }
|
||||
local s = math.floor(seconds)
|
||||
local usecs = (seconds - s) * 1000000
|
||||
when[1] = when[1] + s
|
||||
when[2] = when[2] + usecs
|
||||
if when[2] > 1000000 then
|
||||
when[1] = when[1] + 1
|
||||
when[2] = when[2] - 1000000
|
||||
end
|
||||
self:schedule(when, action)
|
||||
end
|
||||
|
||||
-- register a widget to be repainted
|
||||
function UIManager:setDirty(widget, refresh_type)
|
||||
-- "auto": request full refresh
|
||||
-- "full": force full refresh
|
||||
-- "partial": partial refresh
|
||||
if not refresh_type then
|
||||
refresh_type = "auto"
|
||||
end
|
||||
self._dirty[widget] = refresh_type
|
||||
-- "auto": request full refresh
|
||||
-- "full": force full refresh
|
||||
-- "partial": partial refresh
|
||||
if not refresh_type then
|
||||
refresh_type = "auto"
|
||||
end
|
||||
self._dirty[widget] = refresh_type
|
||||
end
|
||||
|
||||
-- signal to quit
|
||||
function UIManager:quit()
|
||||
self._running = false
|
||||
self._running = false
|
||||
end
|
||||
|
||||
-- transmit an event to registered widgets
|
||||
function UIManager:sendEvent(event)
|
||||
-- top level widget has first access to the event
|
||||
if self._window_stack[#self._window_stack].widget:handleEvent(event) then
|
||||
return
|
||||
end
|
||||
-- top level widget has first access to the event
|
||||
if self._window_stack[#self._window_stack].widget:handleEvent(event) then
|
||||
return
|
||||
end
|
||||
|
||||
-- if the event is not consumed, active widgets can access it
|
||||
for _, widget in ipairs(self._window_stack) do
|
||||
if widget.widget.is_always_active then
|
||||
if widget.widget:handleEvent(event) then return end
|
||||
end
|
||||
if widget.widget.active_widgets then
|
||||
for _, active_widget in ipairs(widget.widget.active_widgets) do
|
||||
if active_widget:handleEvent(event) then return end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- if the event is not consumed, active widgets can access it
|
||||
for _, widget in ipairs(self._window_stack) do
|
||||
if widget.widget.is_always_active then
|
||||
if widget.widget:handleEvent(event) then return end
|
||||
end
|
||||
if widget.widget.active_widgets then
|
||||
for _, active_widget in ipairs(widget.widget.active_widgets) do
|
||||
if active_widget:handleEvent(event) then return end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function UIManager:checkTasks()
|
||||
local now = { util.gettime() }
|
||||
local now = { util.gettime() }
|
||||
|
||||
-- check if we have timed events in our queue and search next one
|
||||
local wait_until = nil
|
||||
local all_tasks_checked
|
||||
repeat
|
||||
all_tasks_checked = true
|
||||
for i = #self._execution_stack, 1, -1 do
|
||||
local task = self._execution_stack[i]
|
||||
if not task.time
|
||||
or task.time[1] < now[1]
|
||||
or task.time[1] == now[1] and task.time[2] < now[2] then
|
||||
-- task is pending to be executed right now. do it.
|
||||
task.action()
|
||||
-- and remove from table
|
||||
table.remove(self._execution_stack, i)
|
||||
-- start loop again, since new tasks might be on the
|
||||
-- queue now
|
||||
all_tasks_checked = false
|
||||
elseif not wait_until
|
||||
or wait_until[1] > task.time[1]
|
||||
or wait_until[1] == task.time[1] and wait_until[2] > task.time[2] then
|
||||
-- task is to be run in the future _and_ is scheduled
|
||||
-- earlier than the tasks we looked at already
|
||||
-- so adjust to the currently examined task instead.
|
||||
wait_until = task.time
|
||||
end
|
||||
end
|
||||
until all_tasks_checked
|
||||
return wait_until
|
||||
-- check if we have timed events in our queue and search next one
|
||||
local wait_until = nil
|
||||
local all_tasks_checked
|
||||
repeat
|
||||
all_tasks_checked = true
|
||||
for i = #self._execution_stack, 1, -1 do
|
||||
local task = self._execution_stack[i]
|
||||
if not task.time
|
||||
or task.time[1] < now[1]
|
||||
or task.time[1] == now[1] and task.time[2] < now[2] then
|
||||
-- task is pending to be executed right now. do it.
|
||||
task.action()
|
||||
-- and remove from table
|
||||
table.remove(self._execution_stack, i)
|
||||
-- start loop again, since new tasks might be on the
|
||||
-- queue now
|
||||
all_tasks_checked = false
|
||||
elseif not wait_until
|
||||
or wait_until[1] > task.time[1]
|
||||
or wait_until[1] == task.time[1] and wait_until[2] > task.time[2] then
|
||||
-- task is to be run in the future _and_ is scheduled
|
||||
-- earlier than the tasks we looked at already
|
||||
-- so adjust to the currently examined task instead.
|
||||
wait_until = task.time
|
||||
end
|
||||
end
|
||||
until all_tasks_checked
|
||||
return wait_until
|
||||
end
|
||||
|
||||
-- this is the main loop of the UI controller
|
||||
-- it is intended to manage input events and delegate
|
||||
-- them to dialogs
|
||||
function UIManager:run()
|
||||
self._running = true
|
||||
while self._running do
|
||||
local now = { util.gettime() }
|
||||
local wait_until = self:checkTasks()
|
||||
self._running = true
|
||||
while self._running do
|
||||
local now = { util.gettime() }
|
||||
local wait_until = self:checkTasks()
|
||||
|
||||
--DEBUG("---------------------------------------------------")
|
||||
--DEBUG("exec stack", self._execution_stack)
|
||||
--DEBUG("window stack", self._window_stack)
|
||||
--DEBUG("dirty stack", self._dirty)
|
||||
--DEBUG("---------------------------------------------------")
|
||||
--DEBUG("---------------------------------------------------")
|
||||
--DEBUG("exec stack", self._execution_stack)
|
||||
--DEBUG("window stack", self._window_stack)
|
||||
--DEBUG("dirty stack", self._dirty)
|
||||
--DEBUG("---------------------------------------------------")
|
||||
|
||||
-- stop when we have no window to show
|
||||
if #self._window_stack == 0 then
|
||||
DEBUG("no dialog left to show, would loop endlessly")
|
||||
return nil
|
||||
end
|
||||
-- stop when we have no window to show
|
||||
if #self._window_stack == 0 then
|
||||
DEBUG("no dialog left to show, would loop endlessly")
|
||||
return nil
|
||||
end
|
||||
|
||||
-- repaint dirty widgets
|
||||
local dirty = false
|
||||
local request_full_refresh = false
|
||||
local force_full_refresh = false
|
||||
local force_patial_refresh = false
|
||||
local force_fast_refresh = false
|
||||
for _, widget in ipairs(self._window_stack) do
|
||||
if self.repaint_all or self._dirty[widget.widget] then
|
||||
widget.widget:paintTo(Screen.bb, widget.x, widget.y)
|
||||
if self._dirty[widget.widget] == "auto" then
|
||||
request_full_refresh = true
|
||||
end
|
||||
if self._dirty[widget.widget] == "full" then
|
||||
force_full_refresh = true
|
||||
end
|
||||
if self._dirty[widget.widget] == "partial" then
|
||||
force_patial_refresh = true
|
||||
end
|
||||
if self._dirty[widget.widget] == "fast" then
|
||||
force_fast_refresh = true
|
||||
end
|
||||
-- and remove from list after painting
|
||||
self._dirty[widget.widget] = nil
|
||||
-- trigger repaint
|
||||
dirty = true
|
||||
end
|
||||
end
|
||||
|
||||
if self.full_refresh then
|
||||
dirty = true
|
||||
force_full_refresh = true
|
||||
end
|
||||
-- repaint dirty widgets
|
||||
local dirty = false
|
||||
local request_full_refresh = false
|
||||
local force_full_refresh = false
|
||||
local force_patial_refresh = false
|
||||
local force_fast_refresh = false
|
||||
for _, widget in ipairs(self._window_stack) do
|
||||
if self.repaint_all or self._dirty[widget.widget] then
|
||||
widget.widget:paintTo(Screen.bb, widget.x, widget.y)
|
||||
if self._dirty[widget.widget] == "auto" then
|
||||
request_full_refresh = true
|
||||
end
|
||||
if self._dirty[widget.widget] == "full" then
|
||||
force_full_refresh = true
|
||||
end
|
||||
if self._dirty[widget.widget] == "partial" then
|
||||
force_patial_refresh = true
|
||||
end
|
||||
if self._dirty[widget.widget] == "fast" then
|
||||
force_fast_refresh = true
|
||||
end
|
||||
-- and remove from list after painting
|
||||
self._dirty[widget.widget] = nil
|
||||
-- trigger repaint
|
||||
dirty = true
|
||||
end
|
||||
end
|
||||
|
||||
if self.full_refresh then
|
||||
dirty = true
|
||||
force_full_refresh = true
|
||||
end
|
||||
|
||||
if self.patial_refresh then
|
||||
dirty = true
|
||||
force_patial_refresh = true
|
||||
end
|
||||
|
||||
self.repaint_all = false
|
||||
self.full_refresh = false
|
||||
self.patial_refresh = false
|
||||
|
||||
local refresh_type = self.default_refresh_type
|
||||
local waveform_mode = self.default_waveform_mode
|
||||
if dirty then
|
||||
if force_patial_refresh or force_fast_refresh then
|
||||
refresh_type = 0
|
||||
elseif force_full_refresh or self.refresh_count == self.FULL_REFRESH_COUNT - 1 then
|
||||
refresh_type = 1
|
||||
end
|
||||
if force_fast_refresh then
|
||||
waveform_mode = self.fast_waveform_mode
|
||||
end
|
||||
if self.update_region_func then
|
||||
local update_region = self.update_region_func()
|
||||
-- in some rare cases update region has 1 pixel offset
|
||||
Screen:refresh(refresh_type, waveform_mode,
|
||||
update_region.x-1, update_region.y-1,
|
||||
update_region.w+2, update_region.h+2)
|
||||
else
|
||||
Screen:refresh(refresh_type, waveform_mode)
|
||||
end
|
||||
if self.refresh_type == 1 then
|
||||
self.refresh_count = 0
|
||||
elseif not force_patial_refresh and not force_full_refresh then
|
||||
self.refresh_count = (self.refresh_count + 1)%self.FULL_REFRESH_COUNT
|
||||
end
|
||||
self.update_region_func = nil
|
||||
end
|
||||
if self.patial_refresh then
|
||||
dirty = true
|
||||
force_patial_refresh = true
|
||||
end
|
||||
|
||||
self.repaint_all = false
|
||||
self.full_refresh = false
|
||||
self.patial_refresh = false
|
||||
|
||||
local refresh_type = self.default_refresh_type
|
||||
local waveform_mode = self.default_waveform_mode
|
||||
if dirty then
|
||||
if force_patial_refresh or force_fast_refresh then
|
||||
refresh_type = 0
|
||||
elseif force_full_refresh or self.refresh_count == self.FULL_REFRESH_COUNT - 1 then
|
||||
refresh_type = 1
|
||||
end
|
||||
if force_fast_refresh then
|
||||
waveform_mode = self.fast_waveform_mode
|
||||
end
|
||||
if self.update_region_func then
|
||||
local update_region = self.update_region_func()
|
||||
-- in some rare cases update region has 1 pixel offset
|
||||
Screen:refresh(refresh_type, waveform_mode,
|
||||
update_region.x-1, update_region.y-1,
|
||||
update_region.w+2, update_region.h+2)
|
||||
else
|
||||
Screen:refresh(refresh_type, waveform_mode)
|
||||
end
|
||||
if self.refresh_type == 1 then
|
||||
self.refresh_count = 0
|
||||
elseif not force_patial_refresh and not force_full_refresh then
|
||||
self.refresh_count = (self.refresh_count + 1)%self.FULL_REFRESH_COUNT
|
||||
end
|
||||
self.update_region_func = nil
|
||||
end
|
||||
|
||||
self:checkTasks()
|
||||
self:checkTasks()
|
||||
|
||||
-- wait for next event
|
||||
-- note that we will skip that if in the meantime we have tasks that are ready to run
|
||||
local input_event = nil
|
||||
if not wait_until then
|
||||
-- no pending task, wait endlessly
|
||||
input_event = Input:waitEvent()
|
||||
elseif wait_until[1] > now[1]
|
||||
or wait_until[1] == now[1] and wait_until[2] > now[2] then
|
||||
local wait_for = { s = wait_until[1] - now[1], us = wait_until[2] - now[2] }
|
||||
if wait_for.us < 0 then
|
||||
wait_for.s = wait_for.s - 1
|
||||
wait_for.us = 1000000 + wait_for.us
|
||||
end
|
||||
-- wait until next task is pending
|
||||
input_event = Input:waitEvent(wait_for.us, wait_for.s)
|
||||
end
|
||||
-- wait for next event
|
||||
-- note that we will skip that if in the meantime we have tasks that are ready to run
|
||||
local input_event = nil
|
||||
if not wait_until then
|
||||
-- no pending task, wait endlessly
|
||||
input_event = Input:waitEvent()
|
||||
elseif wait_until[1] > now[1]
|
||||
or wait_until[1] == now[1] and wait_until[2] > now[2] then
|
||||
local wait_for = { s = wait_until[1] - now[1], us = wait_until[2] - now[2] }
|
||||
if wait_for.us < 0 then
|
||||
wait_for.s = wait_for.s - 1
|
||||
wait_for.us = 1000000 + wait_for.us
|
||||
end
|
||||
-- wait until next task is pending
|
||||
input_event = Input:waitEvent(wait_for.us, wait_for.s)
|
||||
end
|
||||
|
||||
-- delegate input_event to handler
|
||||
if input_event then
|
||||
--DEBUG("in ui.lua:", input_event)
|
||||
if input_event == "IntoSS" then
|
||||
Device:intoScreenSaver()
|
||||
elseif input_event == "OutOfSS" then
|
||||
Device:outofScreenSaver()
|
||||
elseif input_event == "Charging" then
|
||||
Device:usbPlugIn()
|
||||
elseif input_event == "NotCharging" then
|
||||
Device:usbPlugOut()
|
||||
self:sendEvent(Event:new("NotCharging"))
|
||||
elseif input_event == "Light" then
|
||||
Device:getPowerDevice():toggleFrontlight()
|
||||
elseif (input_event == "Power" and not Device.screen_saver_mode)
|
||||
or input_event == "Suspend" then
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
self:show(InfoMessage:new{
|
||||
text = _("Standby"),
|
||||
timeout = 1,
|
||||
})
|
||||
Device:prepareSuspend()
|
||||
self:scheduleIn(0.5, function() Device:Suspend() end)
|
||||
elseif (input_event == "Power" and Device.screen_saver_mode)
|
||||
or input_event == "Resume" then
|
||||
Device:Resume()
|
||||
self:sendEvent(Event:new("Resume"))
|
||||
else
|
||||
self:sendEvent(input_event)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- delegate input_event to handler
|
||||
if input_event then
|
||||
--DEBUG("in ui.lua:", input_event)
|
||||
if input_event == "IntoSS" then
|
||||
Device:intoScreenSaver()
|
||||
elseif input_event == "OutOfSS" then
|
||||
Device:outofScreenSaver()
|
||||
elseif input_event == "Charging" then
|
||||
Device:usbPlugIn()
|
||||
elseif input_event == "NotCharging" then
|
||||
Device:usbPlugOut()
|
||||
self:sendEvent(Event:new("NotCharging"))
|
||||
elseif input_event == "Light" then
|
||||
Device:getPowerDevice():toggleFrontlight()
|
||||
elseif (input_event == "Power" and not Device.screen_saver_mode)
|
||||
or input_event == "Suspend" then
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
self:show(InfoMessage:new{
|
||||
text = _("Standby"),
|
||||
timeout = 1,
|
||||
})
|
||||
Device:prepareSuspend()
|
||||
self:scheduleIn(0.5, function() Device:Suspend() end)
|
||||
elseif (input_event == "Power" and Device.screen_saver_mode)
|
||||
or input_event == "Resume" then
|
||||
Device:Resume()
|
||||
self:sendEvent(Event:new("Resume"))
|
||||
else
|
||||
self:sendEvent(input_event)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return UIManager
|
||||
|
||||
@@ -11,212 +11,212 @@ local DEBUG = require("dbg")
|
||||
BBoxWidget shows a bbox for page cropping
|
||||
]]
|
||||
local BBoxWidget = InputContainer:new{
|
||||
page_bbox = nil,
|
||||
screen_bbox = nil,
|
||||
linesize = 2,
|
||||
fine_factor = 10,
|
||||
page_bbox = nil,
|
||||
screen_bbox = nil,
|
||||
linesize = 2,
|
||||
fine_factor = 10,
|
||||
}
|
||||
|
||||
function BBoxWidget:init()
|
||||
self.page_bbox = self.document:getPageBBox(self.view.state.page)
|
||||
--DEBUG("used page bbox on page", self.view.state.page, self.page_bbox)
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapAdjust = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.view.dimen,
|
||||
}
|
||||
},
|
||||
SwipeAdjust = {
|
||||
GestureRange:new{
|
||||
ges = "swipe",
|
||||
range = self.view.dimen,
|
||||
}
|
||||
},
|
||||
HoldAdjust = {
|
||||
GestureRange:new{
|
||||
ges = "hold",
|
||||
range = self.view.dimen,
|
||||
}
|
||||
},
|
||||
ConfirmAdjust = {
|
||||
GestureRange:new{
|
||||
ges = "double_tap",
|
||||
range = self.view.dimen,
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
self.page_bbox = self.document:getPageBBox(self.view.state.page)
|
||||
--DEBUG("used page bbox on page", self.view.state.page, self.page_bbox)
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapAdjust = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.view.dimen,
|
||||
}
|
||||
},
|
||||
SwipeAdjust = {
|
||||
GestureRange:new{
|
||||
ges = "swipe",
|
||||
range = self.view.dimen,
|
||||
}
|
||||
},
|
||||
HoldAdjust = {
|
||||
GestureRange:new{
|
||||
ges = "hold",
|
||||
range = self.view.dimen,
|
||||
}
|
||||
},
|
||||
ConfirmAdjust = {
|
||||
GestureRange:new{
|
||||
ges = "double_tap",
|
||||
range = self.view.dimen,
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function BBoxWidget:getSize()
|
||||
return self.view.dimen
|
||||
return self.view.dimen
|
||||
end
|
||||
|
||||
function BBoxWidget:paintTo(bb, x, y)
|
||||
-- As getScreenBBox uses view states, screen_bbox initialization is postponed.
|
||||
self.screen_bbox = self.screen_bbox or self:getScreenBBox(self.page_bbox)
|
||||
local bbox = self.screen_bbox
|
||||
-- top edge
|
||||
bb:invertRect(bbox.x0 + self.linesize, bbox.y0, bbox.x1 - bbox.x0, self.linesize)
|
||||
-- bottom edge
|
||||
bb:invertRect(bbox.x0 + self.linesize, bbox.y1, bbox.x1 - bbox.x0 - self.linesize, self.linesize)
|
||||
-- left edge
|
||||
bb:invertRect(bbox.x0, bbox.y0, self.linesize, bbox.y1 - bbox.y0 + self.linesize)
|
||||
-- right edge
|
||||
bb:invertRect(bbox.x1, bbox.y0 + self.linesize, self.linesize, bbox.y1 - bbox.y0)
|
||||
-- As getScreenBBox uses view states, screen_bbox initialization is postponed.
|
||||
self.screen_bbox = self.screen_bbox or self:getScreenBBox(self.page_bbox)
|
||||
local bbox = self.screen_bbox
|
||||
-- top edge
|
||||
bb:invertRect(bbox.x0 + self.linesize, bbox.y0, bbox.x1 - bbox.x0, self.linesize)
|
||||
-- bottom edge
|
||||
bb:invertRect(bbox.x0 + self.linesize, bbox.y1, bbox.x1 - bbox.x0 - self.linesize, self.linesize)
|
||||
-- left edge
|
||||
bb:invertRect(bbox.x0, bbox.y0, self.linesize, bbox.y1 - bbox.y0 + self.linesize)
|
||||
-- right edge
|
||||
bb:invertRect(bbox.x1, bbox.y0 + self.linesize, self.linesize, bbox.y1 - bbox.y0)
|
||||
end
|
||||
|
||||
-- transform page bbox to screen bbox
|
||||
function BBoxWidget:getScreenBBox(page_bbox)
|
||||
local bbox = {}
|
||||
local scale = self.view.state.zoom
|
||||
local screen_offset = self.view.state.offset
|
||||
--DEBUG("screen offset in page_to_screen", screen_offset)
|
||||
bbox.x0 = Math.round(page_bbox.x0 * scale + screen_offset.x)
|
||||
bbox.y0 = Math.round(page_bbox.y0 * scale + screen_offset.y)
|
||||
bbox.x1 = Math.round(page_bbox.x1 * scale + screen_offset.x)
|
||||
bbox.y1 = Math.round(page_bbox.y1 * scale + screen_offset.y)
|
||||
return bbox
|
||||
local bbox = {}
|
||||
local scale = self.view.state.zoom
|
||||
local screen_offset = self.view.state.offset
|
||||
--DEBUG("screen offset in page_to_screen", screen_offset)
|
||||
bbox.x0 = Math.round(page_bbox.x0 * scale + screen_offset.x)
|
||||
bbox.y0 = Math.round(page_bbox.y0 * scale + screen_offset.y)
|
||||
bbox.x1 = Math.round(page_bbox.x1 * scale + screen_offset.x)
|
||||
bbox.y1 = Math.round(page_bbox.y1 * scale + screen_offset.y)
|
||||
return bbox
|
||||
end
|
||||
|
||||
-- transform screen bbox to page bbox
|
||||
function BBoxWidget:getPageBBox(screen_bbox)
|
||||
local bbox = {}
|
||||
local scale = self.view.state.zoom
|
||||
local screen_offset = self.view.state.offset
|
||||
--DEBUG("screen offset in screen_to_page", screen_offset)
|
||||
bbox.x0 = Math.round((screen_bbox.x0 - screen_offset.x) / scale)
|
||||
bbox.y0 = Math.round((screen_bbox.y0 - screen_offset.y) / scale)
|
||||
bbox.x1 = Math.round((screen_bbox.x1 - screen_offset.x) / scale)
|
||||
bbox.y1 = Math.round((screen_bbox.y1 - screen_offset.y) / scale)
|
||||
return bbox
|
||||
local bbox = {}
|
||||
local scale = self.view.state.zoom
|
||||
local screen_offset = self.view.state.offset
|
||||
--DEBUG("screen offset in screen_to_page", screen_offset)
|
||||
bbox.x0 = Math.round((screen_bbox.x0 - screen_offset.x) / scale)
|
||||
bbox.y0 = Math.round((screen_bbox.y0 - screen_offset.y) / scale)
|
||||
bbox.x1 = Math.round((screen_bbox.x1 - screen_offset.x) / scale)
|
||||
bbox.y1 = Math.round((screen_bbox.y1 - screen_offset.y) / scale)
|
||||
return bbox
|
||||
end
|
||||
|
||||
function BBoxWidget:inPageArea(ges)
|
||||
local offset = self.view.state.offset
|
||||
local page_area = self.view.page_area
|
||||
local page_dimen = Geom:new{ x = offset.x, y = offset.y, h = page_area.h, w = page_area.w}
|
||||
return not ges.pos:notIntersectWith(page_dimen)
|
||||
local offset = self.view.state.offset
|
||||
local page_area = self.view.page_area
|
||||
local page_dimen = Geom:new{ x = offset.x, y = offset.y, h = page_area.h, w = page_area.w}
|
||||
return not ges.pos:notIntersectWith(page_dimen)
|
||||
end
|
||||
|
||||
function BBoxWidget:adjustScreenBBox(ges, relative)
|
||||
--DEBUG("adjusting crop bbox with pos", ges.pos)
|
||||
if not self:inPageArea(ges) then return end
|
||||
local bbox = self.screen_bbox
|
||||
local upper_left = Geom:new{ x = bbox.x0, y = bbox.y0}
|
||||
local upper_right = Geom:new{ x = bbox.x1, y = bbox.y0}
|
||||
local bottom_left = Geom:new{ x = bbox.x0, y = bbox.y1}
|
||||
local bottom_right = Geom:new{ x = bbox.x1, y = bbox.y1}
|
||||
local upper_center = Geom:new{ x = (bbox.x0 + bbox.x1) / 2, y = bbox.y0}
|
||||
local bottom_center = Geom:new{ x = (bbox.x0 + bbox.x1) / 2, y = bbox.y1}
|
||||
local right_center = Geom:new{ x = bbox.x1, y = (bbox.y0 + bbox.y1) / 2}
|
||||
local left_center = Geom:new{ x = bbox.x0, y = (bbox.y0 + bbox.y1) / 2}
|
||||
local anchors = {
|
||||
upper_left, upper_center, upper_right,
|
||||
left_center, right_center,
|
||||
bottom_left, bottom_center, bottom_right,
|
||||
}
|
||||
local _, nearest = Math.tmin(anchors, function(a,b)
|
||||
return a:distance(ges.pos) > b:distance(ges.pos)
|
||||
end)
|
||||
--DEBUG("nearest anchor", nearest)
|
||||
if nearest == upper_left then
|
||||
upper_left.x = ges.pos.x
|
||||
upper_left.y = ges.pos.y
|
||||
elseif nearest == bottom_right then
|
||||
bottom_right.x = ges.pos.x
|
||||
bottom_right.y = ges.pos.y
|
||||
elseif nearest == upper_right then
|
||||
bottom_right.x = ges.pos.x
|
||||
upper_left.y = ges.pos.y
|
||||
elseif nearest == bottom_left then
|
||||
upper_left.x = ges.pos.x
|
||||
bottom_right.y = ges.pos.y
|
||||
elseif nearest == upper_center then
|
||||
if relative then
|
||||
local delta = 0
|
||||
if ges.direction == "north" then
|
||||
delta = -ges.distance / self.fine_factor
|
||||
elseif ges.direction == "south" then
|
||||
delta = ges.distance / self.fine_factor
|
||||
end
|
||||
upper_left.y = upper_left.y + delta
|
||||
else
|
||||
upper_left.y = ges.pos.y
|
||||
end
|
||||
elseif nearest == right_center then
|
||||
if relative then
|
||||
local delta = 0
|
||||
if ges.direction == "west" then
|
||||
delta = -ges.distance / self.fine_factor
|
||||
elseif ges.direction == "east" then
|
||||
delta = ges.distance / self.fine_factor
|
||||
end
|
||||
bottom_right.x = bottom_right.x + delta
|
||||
else
|
||||
bottom_right.x = ges.pos.x
|
||||
end
|
||||
elseif nearest == bottom_center then
|
||||
if relative then
|
||||
local delta = 0
|
||||
if ges.direction == "north" then
|
||||
delta = -ges.distance / self.fine_factor
|
||||
elseif ges.direction == "south" then
|
||||
delta = ges.distance / self.fine_factor
|
||||
end
|
||||
bottom_right.y = bottom_right.y + delta
|
||||
else
|
||||
bottom_right.y = ges.pos.y
|
||||
end
|
||||
elseif nearest == left_center then
|
||||
if relative then
|
||||
local delta = 0
|
||||
if ges.direction == "west" then
|
||||
delta = -ges.distance / self.fine_factor
|
||||
elseif ges.direction == "east" then
|
||||
delta = ges.distance / self.fine_factor
|
||||
end
|
||||
upper_left.x = upper_left.x + delta
|
||||
else
|
||||
upper_left.x = ges.pos.x
|
||||
end
|
||||
end
|
||||
self.screen_bbox = {
|
||||
x0 = Math.round(upper_left.x),
|
||||
y0 = Math.round(upper_left.y),
|
||||
x1 = Math.round(bottom_right.x),
|
||||
y1 = Math.round(bottom_right.y)
|
||||
}
|
||||
--DEBUG("adjusting crop bbox with pos", ges.pos)
|
||||
if not self:inPageArea(ges) then return end
|
||||
local bbox = self.screen_bbox
|
||||
local upper_left = Geom:new{ x = bbox.x0, y = bbox.y0}
|
||||
local upper_right = Geom:new{ x = bbox.x1, y = bbox.y0}
|
||||
local bottom_left = Geom:new{ x = bbox.x0, y = bbox.y1}
|
||||
local bottom_right = Geom:new{ x = bbox.x1, y = bbox.y1}
|
||||
local upper_center = Geom:new{ x = (bbox.x0 + bbox.x1) / 2, y = bbox.y0}
|
||||
local bottom_center = Geom:new{ x = (bbox.x0 + bbox.x1) / 2, y = bbox.y1}
|
||||
local right_center = Geom:new{ x = bbox.x1, y = (bbox.y0 + bbox.y1) / 2}
|
||||
local left_center = Geom:new{ x = bbox.x0, y = (bbox.y0 + bbox.y1) / 2}
|
||||
local anchors = {
|
||||
upper_left, upper_center, upper_right,
|
||||
left_center, right_center,
|
||||
bottom_left, bottom_center, bottom_right,
|
||||
}
|
||||
local _, nearest = Math.tmin(anchors, function(a,b)
|
||||
return a:distance(ges.pos) > b:distance(ges.pos)
|
||||
end)
|
||||
--DEBUG("nearest anchor", nearest)
|
||||
if nearest == upper_left then
|
||||
upper_left.x = ges.pos.x
|
||||
upper_left.y = ges.pos.y
|
||||
elseif nearest == bottom_right then
|
||||
bottom_right.x = ges.pos.x
|
||||
bottom_right.y = ges.pos.y
|
||||
elseif nearest == upper_right then
|
||||
bottom_right.x = ges.pos.x
|
||||
upper_left.y = ges.pos.y
|
||||
elseif nearest == bottom_left then
|
||||
upper_left.x = ges.pos.x
|
||||
bottom_right.y = ges.pos.y
|
||||
elseif nearest == upper_center then
|
||||
if relative then
|
||||
local delta = 0
|
||||
if ges.direction == "north" then
|
||||
delta = -ges.distance / self.fine_factor
|
||||
elseif ges.direction == "south" then
|
||||
delta = ges.distance / self.fine_factor
|
||||
end
|
||||
upper_left.y = upper_left.y + delta
|
||||
else
|
||||
upper_left.y = ges.pos.y
|
||||
end
|
||||
elseif nearest == right_center then
|
||||
if relative then
|
||||
local delta = 0
|
||||
if ges.direction == "west" then
|
||||
delta = -ges.distance / self.fine_factor
|
||||
elseif ges.direction == "east" then
|
||||
delta = ges.distance / self.fine_factor
|
||||
end
|
||||
bottom_right.x = bottom_right.x + delta
|
||||
else
|
||||
bottom_right.x = ges.pos.x
|
||||
end
|
||||
elseif nearest == bottom_center then
|
||||
if relative then
|
||||
local delta = 0
|
||||
if ges.direction == "north" then
|
||||
delta = -ges.distance / self.fine_factor
|
||||
elseif ges.direction == "south" then
|
||||
delta = ges.distance / self.fine_factor
|
||||
end
|
||||
bottom_right.y = bottom_right.y + delta
|
||||
else
|
||||
bottom_right.y = ges.pos.y
|
||||
end
|
||||
elseif nearest == left_center then
|
||||
if relative then
|
||||
local delta = 0
|
||||
if ges.direction == "west" then
|
||||
delta = -ges.distance / self.fine_factor
|
||||
elseif ges.direction == "east" then
|
||||
delta = ges.distance / self.fine_factor
|
||||
end
|
||||
upper_left.x = upper_left.x + delta
|
||||
else
|
||||
upper_left.x = ges.pos.x
|
||||
end
|
||||
end
|
||||
self.screen_bbox = {
|
||||
x0 = Math.round(upper_left.x),
|
||||
y0 = Math.round(upper_left.y),
|
||||
x1 = Math.round(bottom_right.x),
|
||||
y1 = Math.round(bottom_right.y)
|
||||
}
|
||||
|
||||
UIManager.repaint_all = true
|
||||
UIManager.repaint_all = true
|
||||
end
|
||||
|
||||
function BBoxWidget:getModifiedPageBBox()
|
||||
return self:getPageBBox(self.screen_bbox)
|
||||
return self:getPageBBox(self.screen_bbox)
|
||||
end
|
||||
|
||||
function BBoxWidget:onTapAdjust(arg, ges)
|
||||
self:adjustScreenBBox(ges)
|
||||
return true
|
||||
self:adjustScreenBBox(ges)
|
||||
return true
|
||||
end
|
||||
|
||||
function BBoxWidget:onSwipeAdjust(arg, ges)
|
||||
self:adjustScreenBBox(ges, true)
|
||||
return true
|
||||
self:adjustScreenBBox(ges, true)
|
||||
return true
|
||||
end
|
||||
|
||||
function BBoxWidget:onHoldAdjust(arg, ges)
|
||||
self:adjustScreenBBox(ges)
|
||||
return true
|
||||
self:adjustScreenBBox(ges)
|
||||
return true
|
||||
end
|
||||
|
||||
function BBoxWidget:onConfirmAdjust(arg, ges)
|
||||
if self:inPageArea(ges) then
|
||||
self.ui:handleEvent(Event:new("ConfirmPageCrop"))
|
||||
end
|
||||
return true
|
||||
if self:inPageArea(ges) then
|
||||
self.ui:handleEvent(Event:new("ConfirmPageCrop"))
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
return BBoxWidget
|
||||
|
||||
@@ -13,135 +13,135 @@ local _ = require("gettext")
|
||||
a button widget that shows text or a icon and handles callback when tapped
|
||||
--]]
|
||||
local Button = InputContainer:new{
|
||||
text = nil, -- mandatory
|
||||
icon = nil,
|
||||
preselect = false,
|
||||
callback = nil,
|
||||
enabled = true,
|
||||
margin = 0,
|
||||
bordersize = 3,
|
||||
background = 0,
|
||||
radius = 15,
|
||||
padding = 2,
|
||||
width = nil,
|
||||
text_font_face = "cfont",
|
||||
text_font_size = 20,
|
||||
text = nil, -- mandatory
|
||||
icon = nil,
|
||||
preselect = false,
|
||||
callback = nil,
|
||||
enabled = true,
|
||||
margin = 0,
|
||||
bordersize = 3,
|
||||
background = 0,
|
||||
radius = 15,
|
||||
padding = 2,
|
||||
width = nil,
|
||||
text_font_face = "cfont",
|
||||
text_font_size = 20,
|
||||
}
|
||||
|
||||
function Button:init()
|
||||
if self.text then
|
||||
self.label_widget = TextWidget:new{
|
||||
text = self.text,
|
||||
bgcolor = 0.0,
|
||||
fgcolor = self.enabled and 1.0 or 0.5,
|
||||
bold = true,
|
||||
face = Font:getFace(self.text_font_face, self.text_font_size)
|
||||
}
|
||||
else
|
||||
self.label_widget = ImageWidget:new{
|
||||
file = self.icon,
|
||||
dim = self.enabled,
|
||||
}
|
||||
end
|
||||
local widget_size = self.label_widget:getSize()
|
||||
if self.width == nil then
|
||||
self.width = widget_size.w
|
||||
end
|
||||
-- set FrameContainer content
|
||||
self[1] = FrameContainer:new{
|
||||
margin = self.margin,
|
||||
bordersize = self.bordersize,
|
||||
background = self.background,
|
||||
radius = self.radius,
|
||||
padding = self.padding,
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = self.width,
|
||||
h = widget_size.h
|
||||
},
|
||||
self.label_widget,
|
||||
}
|
||||
}
|
||||
if self.preselect then
|
||||
self[1].color = 15
|
||||
else
|
||||
self[1].color = 5
|
||||
end
|
||||
self.dimen = self[1]:getSize()
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapSelect = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
},
|
||||
doc = _("Tap Button"),
|
||||
},
|
||||
}
|
||||
end
|
||||
if self.text then
|
||||
self.label_widget = TextWidget:new{
|
||||
text = self.text,
|
||||
bgcolor = 0.0,
|
||||
fgcolor = self.enabled and 1.0 or 0.5,
|
||||
bold = true,
|
||||
face = Font:getFace(self.text_font_face, self.text_font_size)
|
||||
}
|
||||
else
|
||||
self.label_widget = ImageWidget:new{
|
||||
file = self.icon,
|
||||
dim = self.enabled,
|
||||
}
|
||||
end
|
||||
local widget_size = self.label_widget:getSize()
|
||||
if self.width == nil then
|
||||
self.width = widget_size.w
|
||||
end
|
||||
-- set FrameContainer content
|
||||
self[1] = FrameContainer:new{
|
||||
margin = self.margin,
|
||||
bordersize = self.bordersize,
|
||||
background = self.background,
|
||||
radius = self.radius,
|
||||
padding = self.padding,
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = self.width,
|
||||
h = widget_size.h
|
||||
},
|
||||
self.label_widget,
|
||||
}
|
||||
}
|
||||
if self.preselect then
|
||||
self[1].color = 15
|
||||
else
|
||||
self[1].color = 5
|
||||
end
|
||||
self.dimen = self[1]:getSize()
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapSelect = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
},
|
||||
doc = _("Tap Button"),
|
||||
},
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function Button:onFocus()
|
||||
self[1].color = 15
|
||||
return true
|
||||
self[1].color = 15
|
||||
return true
|
||||
end
|
||||
|
||||
function Button:onUnfocus()
|
||||
self[1].color = 5
|
||||
return true
|
||||
self[1].color = 5
|
||||
return true
|
||||
end
|
||||
|
||||
function Button:enable()
|
||||
self.enabled = true
|
||||
if self.text then
|
||||
self.label_widget.fgcolor = self.enabled and 1.0 or 0.5
|
||||
else
|
||||
self.label_widget.dim = not self.enabled
|
||||
end
|
||||
self.enabled = true
|
||||
if self.text then
|
||||
self.label_widget.fgcolor = self.enabled and 1.0 or 0.5
|
||||
else
|
||||
self.label_widget.dim = not self.enabled
|
||||
end
|
||||
end
|
||||
|
||||
function Button:disable()
|
||||
self.enabled = false
|
||||
if self.text then
|
||||
self.label_widget.fgcolor = self.enabled and 1.0 or 0.5
|
||||
else
|
||||
self.label_widget.dim = not self.enabled
|
||||
end
|
||||
self.enabled = false
|
||||
if self.text then
|
||||
self.label_widget.fgcolor = self.enabled and 1.0 or 0.5
|
||||
else
|
||||
self.label_widget.dim = not self.enabled
|
||||
end
|
||||
end
|
||||
|
||||
function Button:enableDisable(enable)
|
||||
if enable then
|
||||
self:enable()
|
||||
else
|
||||
self:disable()
|
||||
end
|
||||
if enable then
|
||||
self:enable()
|
||||
else
|
||||
self:disable()
|
||||
end
|
||||
end
|
||||
|
||||
function Button:hide()
|
||||
if self.icon then
|
||||
self.label_widget.hide = true
|
||||
end
|
||||
if self.icon then
|
||||
self.label_widget.hide = true
|
||||
end
|
||||
end
|
||||
|
||||
function Button:show()
|
||||
if self.icon then
|
||||
self.label_widget.hide = false
|
||||
end
|
||||
if self.icon then
|
||||
self.label_widget.hide = false
|
||||
end
|
||||
end
|
||||
|
||||
function Button:showHide(show)
|
||||
if show then
|
||||
self:show()
|
||||
else
|
||||
self:hide()
|
||||
end
|
||||
if show then
|
||||
self:show()
|
||||
else
|
||||
self:hide()
|
||||
end
|
||||
end
|
||||
|
||||
function Button:onTapSelect()
|
||||
if self.enabled then
|
||||
self.callback()
|
||||
end
|
||||
return true
|
||||
if self.enabled then
|
||||
self.callback()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
return Button
|
||||
|
||||
@@ -11,49 +11,49 @@ local UIManager = require("ui/uimanager")
|
||||
local _ = require("gettext")
|
||||
|
||||
local ButtonDialog = InputContainer:new{
|
||||
buttons = nil,
|
||||
tap_close_callback = nil,
|
||||
buttons = nil,
|
||||
tap_close_callback = nil,
|
||||
}
|
||||
|
||||
function ButtonDialog:init()
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
AnyKeyPressed = { { Input.group.Any },
|
||||
seqtext = "any key", doc = _("close dialog") }
|
||||
}
|
||||
else
|
||||
self.ges_events.TapClose = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
FrameContainer:new{
|
||||
ButtonTable:new{
|
||||
width = Screen:getWidth()*0.9,
|
||||
buttons = self.buttons,
|
||||
},
|
||||
background = 0,
|
||||
bordersize = 2,
|
||||
radius = 7,
|
||||
padding = 2,
|
||||
}
|
||||
}
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
AnyKeyPressed = { { Input.group.Any },
|
||||
seqtext = "any key", doc = _("close dialog") }
|
||||
}
|
||||
else
|
||||
self.ges_events.TapClose = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
FrameContainer:new{
|
||||
ButtonTable:new{
|
||||
width = Screen:getWidth()*0.9,
|
||||
buttons = self.buttons,
|
||||
},
|
||||
background = 0,
|
||||
bordersize = 2,
|
||||
radius = 7,
|
||||
padding = 2,
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function ButtonDialog:onTapClose()
|
||||
UIManager:close(self)
|
||||
if self.tap_close_callback then
|
||||
self.tap_close_callback()
|
||||
end
|
||||
return true
|
||||
UIManager:close(self)
|
||||
if self.tap_close_callback then
|
||||
self.tap_close_callback()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
return ButtonDialog
|
||||
|
||||
@@ -7,72 +7,72 @@ local Screen = require("ui/screen")
|
||||
local Geom = require("ui/geometry")
|
||||
|
||||
local ButtonTable = VerticalGroup:new{
|
||||
width = Screen:getWidth(),
|
||||
buttons = {
|
||||
{
|
||||
{text="OK", enabled=true, callback=nil},
|
||||
{text="Cancel", enabled=false, callback=nil},
|
||||
},
|
||||
},
|
||||
sep_width = Screen:scaleByDPI(1),
|
||||
padding = Screen:scaleByDPI(2),
|
||||
width = Screen:getWidth(),
|
||||
buttons = {
|
||||
{
|
||||
{text="OK", enabled=true, callback=nil},
|
||||
{text="Cancel", enabled=false, callback=nil},
|
||||
},
|
||||
},
|
||||
sep_width = Screen:scaleByDPI(1),
|
||||
padding = Screen:scaleByDPI(2),
|
||||
|
||||
zero_sep = false,
|
||||
button_font_face = "cfont",
|
||||
button_font_size = 20,
|
||||
zero_sep = false,
|
||||
button_font_face = "cfont",
|
||||
button_font_size = 20,
|
||||
}
|
||||
|
||||
function ButtonTable:init()
|
||||
--local vertical_group = VerticalGroup:new{}
|
||||
if self.zero_sep then
|
||||
self:addHorizontalSep()
|
||||
end
|
||||
for i = 1, #self.buttons do
|
||||
local horizontal_group = HorizontalGroup:new{}
|
||||
local line = self.buttons[i]
|
||||
local sizer_space = self.sep_width * (#line - 1) + 2
|
||||
for j = 1, #line do
|
||||
local button = Button:new{
|
||||
text = line[j].text,
|
||||
enabled = line[j].enabled,
|
||||
callback = line[j].callback,
|
||||
width = (self.width - sizer_space)/#line,
|
||||
bordersize = 0,
|
||||
margin = 0,
|
||||
padding = 0,
|
||||
text_font_face = self.button_font_face,
|
||||
text_font_size = self.button_font_size,
|
||||
}
|
||||
local button_dim = button:getSize()
|
||||
local vertical_sep = LineWidget:new{
|
||||
background = 8,
|
||||
dimen = Geom:new{
|
||||
w = self.sep_width,
|
||||
h = button_dim.h,
|
||||
}
|
||||
}
|
||||
table.insert(horizontal_group, button)
|
||||
if j < #line then
|
||||
table.insert(horizontal_group, vertical_sep)
|
||||
end
|
||||
end -- end for each button
|
||||
table.insert(self, horizontal_group)
|
||||
if i < #self.buttons then
|
||||
self:addHorizontalSep()
|
||||
end
|
||||
end -- end for each button line
|
||||
--local vertical_group = VerticalGroup:new{}
|
||||
if self.zero_sep then
|
||||
self:addHorizontalSep()
|
||||
end
|
||||
for i = 1, #self.buttons do
|
||||
local horizontal_group = HorizontalGroup:new{}
|
||||
local line = self.buttons[i]
|
||||
local sizer_space = self.sep_width * (#line - 1) + 2
|
||||
for j = 1, #line do
|
||||
local button = Button:new{
|
||||
text = line[j].text,
|
||||
enabled = line[j].enabled,
|
||||
callback = line[j].callback,
|
||||
width = (self.width - sizer_space)/#line,
|
||||
bordersize = 0,
|
||||
margin = 0,
|
||||
padding = 0,
|
||||
text_font_face = self.button_font_face,
|
||||
text_font_size = self.button_font_size,
|
||||
}
|
||||
local button_dim = button:getSize()
|
||||
local vertical_sep = LineWidget:new{
|
||||
background = 8,
|
||||
dimen = Geom:new{
|
||||
w = self.sep_width,
|
||||
h = button_dim.h,
|
||||
}
|
||||
}
|
||||
table.insert(horizontal_group, button)
|
||||
if j < #line then
|
||||
table.insert(horizontal_group, vertical_sep)
|
||||
end
|
||||
end -- end for each button
|
||||
table.insert(self, horizontal_group)
|
||||
if i < #self.buttons then
|
||||
self:addHorizontalSep()
|
||||
end
|
||||
end -- end for each button line
|
||||
end
|
||||
|
||||
function ButtonTable:addHorizontalSep()
|
||||
table.insert(self, VerticalSpan:new{ width = Screen:scaleByDPI(2) })
|
||||
table.insert(self, LineWidget:new{
|
||||
background = 8,
|
||||
dimen = Geom:new{
|
||||
w = self.width,
|
||||
h = self.sep_width,
|
||||
}
|
||||
})
|
||||
table.insert(self, VerticalSpan:new{ width = Screen:scaleByDPI(2) })
|
||||
table.insert(self, VerticalSpan:new{ width = Screen:scaleByDPI(2) })
|
||||
table.insert(self, LineWidget:new{
|
||||
background = 8,
|
||||
dimen = Geom:new{
|
||||
w = self.width,
|
||||
h = self.sep_width,
|
||||
}
|
||||
})
|
||||
table.insert(self, VerticalSpan:new{ width = Screen:scaleByDPI(2) })
|
||||
end
|
||||
|
||||
return ButtonTable
|
||||
|
||||
@@ -11,35 +11,35 @@ local Font = require("ui/font")
|
||||
a button widget that shows an "×" and handles closing window when tapped
|
||||
--]]
|
||||
local CloseButton = InputContainer:new{
|
||||
align = "right",
|
||||
window = nil,
|
||||
align = "right",
|
||||
window = nil,
|
||||
}
|
||||
|
||||
function CloseButton:init()
|
||||
local text_widget = TextWidget:new{
|
||||
text = "×",
|
||||
face = Font:getFace("cfont", 32),
|
||||
}
|
||||
self[1] = FrameContainer:new{
|
||||
bordersize = 0,
|
||||
padding = 0,
|
||||
text_widget
|
||||
}
|
||||
|
||||
self.dimen = text_widget:getSize():copy()
|
||||
local text_widget = TextWidget:new{
|
||||
text = "×",
|
||||
face = Font:getFace("cfont", 32),
|
||||
}
|
||||
self[1] = FrameContainer:new{
|
||||
bordersize = 0,
|
||||
padding = 0,
|
||||
text_widget
|
||||
}
|
||||
|
||||
self.dimen = text_widget:getSize():copy()
|
||||
|
||||
self.ges_events.Close = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
},
|
||||
doc = "Tap on close button",
|
||||
}
|
||||
self.ges_events.Close = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
},
|
||||
doc = "Tap on close button",
|
||||
}
|
||||
end
|
||||
|
||||
function CloseButton:onClose()
|
||||
self.window:onClose()
|
||||
return true
|
||||
self.window:onClose()
|
||||
return true
|
||||
end
|
||||
|
||||
return CloseButton
|
||||
|
||||
@@ -26,363 +26,363 @@ local _ = require("gettext")
|
||||
|
||||
local MenuBarItem = InputContainer:new{}
|
||||
function MenuBarItem:init()
|
||||
self.dimen = self[1]:getSize()
|
||||
-- we need this table per-instance, so we declare it here
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapSelect = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
},
|
||||
doc = _("Select Menu Item"),
|
||||
},
|
||||
}
|
||||
else
|
||||
self.active_key_events = {
|
||||
Select = { {"Press"}, doc = _("chose selected item") },
|
||||
}
|
||||
end
|
||||
self.dimen = self[1]:getSize()
|
||||
-- we need this table per-instance, so we declare it here
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapSelect = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
},
|
||||
doc = _("Select Menu Item"),
|
||||
},
|
||||
}
|
||||
else
|
||||
self.active_key_events = {
|
||||
Select = { {"Press"}, doc = _("chose selected item") },
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function MenuBarItem:onTapSelect()
|
||||
UIManager:scheduleIn(0.0, function() self:invert(true) end)
|
||||
UIManager:scheduleIn(0.1, function()
|
||||
UIManager:sendEvent(Event:new("ShowConfigPanel", self.index))
|
||||
end)
|
||||
UIManager:scheduleIn(0.5, function() self:invert(false) end)
|
||||
return true
|
||||
UIManager:scheduleIn(0.0, function() self:invert(true) end)
|
||||
UIManager:scheduleIn(0.1, function()
|
||||
UIManager:sendEvent(Event:new("ShowConfigPanel", self.index))
|
||||
end)
|
||||
UIManager:scheduleIn(0.5, function() self:invert(false) end)
|
||||
return true
|
||||
end
|
||||
|
||||
function MenuBarItem:invert(invert)
|
||||
self[1].invert = invert
|
||||
UIManager.update_region_func = function()
|
||||
DEBUG("update icon region", self[1].dimen)
|
||||
return self[1].dimen
|
||||
end
|
||||
UIManager:setDirty(self.config, "full")
|
||||
self[1].invert = invert
|
||||
UIManager.update_region_func = function()
|
||||
DEBUG("update icon region", self[1].dimen)
|
||||
return self[1].dimen
|
||||
end
|
||||
UIManager:setDirty(self.config, "full")
|
||||
end
|
||||
|
||||
local OptionTextItem = InputContainer:new{}
|
||||
function OptionTextItem:init()
|
||||
local text_widget = self[1]
|
||||
|
||||
self[1] = UnderlineContainer:new{
|
||||
text_widget,
|
||||
padding = self.padding,
|
||||
color = self.color,
|
||||
}
|
||||
self.dimen = self[1]:getSize()
|
||||
-- we need this table per-instance, so we declare it here
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapSelect = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
},
|
||||
doc = _("Select Option Item"),
|
||||
},
|
||||
}
|
||||
else
|
||||
self.active_key_events = {
|
||||
Select = { {"Press"}, doc = _("chose selected item") },
|
||||
}
|
||||
end
|
||||
local text_widget = self[1]
|
||||
|
||||
self[1] = UnderlineContainer:new{
|
||||
text_widget,
|
||||
padding = self.padding,
|
||||
color = self.color,
|
||||
}
|
||||
self.dimen = self[1]:getSize()
|
||||
-- we need this table per-instance, so we declare it here
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapSelect = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
},
|
||||
doc = _("Select Option Item"),
|
||||
},
|
||||
}
|
||||
else
|
||||
self.active_key_events = {
|
||||
Select = { {"Press"}, doc = _("chose selected item") },
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function OptionTextItem:onTapSelect()
|
||||
for _, item in pairs(self.items) do
|
||||
item[1].color = 0
|
||||
end
|
||||
self[1].color = 15
|
||||
self.config:onConfigChoose(self.values, self.name, self.event, self.args, self.events, self.current_item)
|
||||
UIManager:setDirty(self.config, "partial")
|
||||
return true
|
||||
for _, item in pairs(self.items) do
|
||||
item[1].color = 0
|
||||
end
|
||||
self[1].color = 15
|
||||
self.config:onConfigChoose(self.values, self.name, self.event, self.args, self.events, self.current_item)
|
||||
UIManager:setDirty(self.config, "partial")
|
||||
return true
|
||||
end
|
||||
|
||||
local OptionIconItem = InputContainer:new{}
|
||||
function OptionIconItem:init()
|
||||
self.dimen = self.icon:getSize()
|
||||
self[1] = UnderlineContainer:new{
|
||||
self.icon,
|
||||
padding = self.padding,
|
||||
color = self.color,
|
||||
}
|
||||
-- we need this table per-instance, so we declare it here
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapSelect = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
},
|
||||
doc = _("Select Option Item"),
|
||||
},
|
||||
}
|
||||
end
|
||||
self.dimen = self.icon:getSize()
|
||||
self[1] = UnderlineContainer:new{
|
||||
self.icon,
|
||||
padding = self.padding,
|
||||
color = self.color,
|
||||
}
|
||||
-- we need this table per-instance, so we declare it here
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapSelect = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
},
|
||||
doc = _("Select Option Item"),
|
||||
},
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function OptionIconItem:onTapSelect()
|
||||
for _, item in pairs(self.items) do
|
||||
--item[1][1].invert = false
|
||||
item[1].color = 0
|
||||
end
|
||||
--self[1][1].invert = true
|
||||
self[1].color = 15
|
||||
self.config:onConfigChoose(self.values, self.name, self.event, self.args, self.events, self.current_item)
|
||||
UIManager:setDirty(self.config, "partial")
|
||||
return true
|
||||
for _, item in pairs(self.items) do
|
||||
--item[1][1].invert = false
|
||||
item[1].color = 0
|
||||
end
|
||||
--self[1][1].invert = true
|
||||
self[1].color = 15
|
||||
self.config:onConfigChoose(self.values, self.name, self.event, self.args, self.events, self.current_item)
|
||||
UIManager:setDirty(self.config, "partial")
|
||||
return true
|
||||
end
|
||||
|
||||
local ConfigOption = CenterContainer:new{}
|
||||
function ConfigOption:init()
|
||||
local default_name_font_size = 20
|
||||
local default_item_font_size = 16
|
||||
local default_items_spacing = 30
|
||||
local default_option_height = 50
|
||||
local default_option_padding = 15
|
||||
local vertical_group = VerticalGroup:new{}
|
||||
table.insert(vertical_group, VerticalSpan:new{
|
||||
width = Screen:scaleByDPI(default_option_padding),
|
||||
})
|
||||
for c = 1, #self.options do
|
||||
if self.options[c].show ~= false then
|
||||
local name_align = self.options[c].name_align_right and self.options[c].name_align_right or 0.33
|
||||
local item_align = self.options[c].item_align_center and self.options[c].item_align_center or 0.66
|
||||
local name_font_face = self.options[c].name_font_face and self.options[c].name_font_face or "cfont"
|
||||
local name_font_size = self.options[c].name_font_size and self.options[c].name_font_size or default_name_font_size
|
||||
local item_font_face = self.options[c].item_font_face and self.options[c].item_font_face or "cfont"
|
||||
local item_font_size = self.options[c].item_font_size and self.options[c].item_font_size or default_item_font_size
|
||||
local option_height = Screen:scaleByDPI(self.options[c].height and self.options[c].height or default_option_height)
|
||||
local items_spacing = HorizontalSpan:new{
|
||||
width = Screen:scaleByDPI(self.options[c].spacing and self.options[c].spacing or default_items_spacing)
|
||||
}
|
||||
local horizontal_group = HorizontalGroup:new{}
|
||||
if self.options[c].name_text then
|
||||
local option_name_container = RightContainer:new{
|
||||
dimen = Geom:new{ w = Screen:getWidth()*name_align, h = option_height},
|
||||
}
|
||||
local option_name = TextWidget:new{
|
||||
text = self.options[c].name_text,
|
||||
face = Font:getFace(name_font_face, name_font_size),
|
||||
}
|
||||
table.insert(option_name_container, option_name)
|
||||
table.insert(horizontal_group, option_name_container)
|
||||
end
|
||||
local default_name_font_size = 20
|
||||
local default_item_font_size = 16
|
||||
local default_items_spacing = 30
|
||||
local default_option_height = 50
|
||||
local default_option_padding = 15
|
||||
local vertical_group = VerticalGroup:new{}
|
||||
table.insert(vertical_group, VerticalSpan:new{
|
||||
width = Screen:scaleByDPI(default_option_padding),
|
||||
})
|
||||
for c = 1, #self.options do
|
||||
if self.options[c].show ~= false then
|
||||
local name_align = self.options[c].name_align_right and self.options[c].name_align_right or 0.33
|
||||
local item_align = self.options[c].item_align_center and self.options[c].item_align_center or 0.66
|
||||
local name_font_face = self.options[c].name_font_face and self.options[c].name_font_face or "cfont"
|
||||
local name_font_size = self.options[c].name_font_size and self.options[c].name_font_size or default_name_font_size
|
||||
local item_font_face = self.options[c].item_font_face and self.options[c].item_font_face or "cfont"
|
||||
local item_font_size = self.options[c].item_font_size and self.options[c].item_font_size or default_item_font_size
|
||||
local option_height = Screen:scaleByDPI(self.options[c].height and self.options[c].height or default_option_height)
|
||||
local items_spacing = HorizontalSpan:new{
|
||||
width = Screen:scaleByDPI(self.options[c].spacing and self.options[c].spacing or default_items_spacing)
|
||||
}
|
||||
local horizontal_group = HorizontalGroup:new{}
|
||||
if self.options[c].name_text then
|
||||
local option_name_container = RightContainer:new{
|
||||
dimen = Geom:new{ w = Screen:getWidth()*name_align, h = option_height},
|
||||
}
|
||||
local option_name = TextWidget:new{
|
||||
text = self.options[c].name_text,
|
||||
face = Font:getFace(name_font_face, name_font_size),
|
||||
}
|
||||
table.insert(option_name_container, option_name)
|
||||
table.insert(horizontal_group, option_name_container)
|
||||
end
|
||||
|
||||
if self.options[c].widget == "ProgressWidget" then
|
||||
local widget_container = CenterContainer:new{
|
||||
dimen = Geom:new{w = Screen:getWidth()*self.options[c].widget_align_center, h = option_height}
|
||||
}
|
||||
local widget = ProgressWidget:new{
|
||||
width = self.options[c].width,
|
||||
height = self.options[c].height,
|
||||
percentage = self.options[c].percentage,
|
||||
}
|
||||
table.insert(widget_container, widget)
|
||||
table.insert(horizontal_group, widget_container)
|
||||
end
|
||||
if self.options[c].widget == "ProgressWidget" then
|
||||
local widget_container = CenterContainer:new{
|
||||
dimen = Geom:new{w = Screen:getWidth()*self.options[c].widget_align_center, h = option_height}
|
||||
}
|
||||
local widget = ProgressWidget:new{
|
||||
width = self.options[c].width,
|
||||
height = self.options[c].height,
|
||||
percentage = self.options[c].percentage,
|
||||
}
|
||||
table.insert(widget_container, widget)
|
||||
table.insert(horizontal_group, widget_container)
|
||||
end
|
||||
|
||||
local option_items_container = CenterContainer:new{
|
||||
dimen = Geom:new{w = Screen:getWidth()*item_align, h = option_height}
|
||||
}
|
||||
local option_items_group = HorizontalGroup:new{}
|
||||
local option_items_fixed = false
|
||||
local option_items = {}
|
||||
if type(self.options[c].item_font_size) == "table" then
|
||||
option_items_group.align = "bottom"
|
||||
option_items_fixed = true
|
||||
end
|
||||
-- make current index according to configurable table
|
||||
local current_item = nil
|
||||
local function value_diff(val1, val2, name)
|
||||
if type(val1) ~= type(val2) then
|
||||
error("different data types in option", name)
|
||||
end
|
||||
if type(val1) == "number" then
|
||||
return math.abs(val1 - val2)
|
||||
elseif type(val1) == "string" then
|
||||
return val1 == val2 and 0 or 1
|
||||
end
|
||||
end
|
||||
if self.options[c].name then
|
||||
if self.options[c].values then
|
||||
-- check if current value is stored in configurable or calculated in runtime
|
||||
local val = self.options[c].current_func and self.options[c].current_func()
|
||||
or self.config.configurable[self.options[c].name]
|
||||
local min_diff = nil
|
||||
if type(val) == "table" then
|
||||
min_diff = value_diff(val[1], self.options[c].values[1][1])
|
||||
else
|
||||
min_diff = value_diff(val, self.options[c].values[1])
|
||||
end
|
||||
|
||||
local diff = nil
|
||||
for index, val_ in pairs(self.options[c].values) do
|
||||
local diff = nil
|
||||
if type(val) == "table" then
|
||||
diff = value_diff(val[1], val_[1])
|
||||
else
|
||||
diff = value_diff(val, val_)
|
||||
end
|
||||
if val == val_ then
|
||||
current_item = index
|
||||
break
|
||||
end
|
||||
if diff <= min_diff then
|
||||
min_diff = diff
|
||||
current_item = index
|
||||
end
|
||||
end
|
||||
elseif self.options[c].args then
|
||||
-- check if current arg is stored in configurable or calculated in runtime
|
||||
local arg = self.options[c].current_func and self.options[c].current_func()
|
||||
or self.config.configurable[self.options[c].name]
|
||||
for idx, arg_ in pairs(self.options[c].args) do
|
||||
if arg_ == arg then
|
||||
current_item = idx
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.options[c].item_text then
|
||||
for d = 1, #self.options[c].item_text do
|
||||
local option_item = nil
|
||||
if option_items_fixed then
|
||||
option_item = OptionTextItem:new{
|
||||
FixedTextWidget:new{
|
||||
text = self.options[c].item_text[d],
|
||||
face = Font:getFace(item_font_face, item_font_size[d]),
|
||||
},
|
||||
padding = 3,
|
||||
color = d == current_item and 15 or 0,
|
||||
}
|
||||
else
|
||||
option_item = OptionTextItem:new{
|
||||
TextWidget:new{
|
||||
text = self.options[c].item_text[d],
|
||||
face = Font:getFace(item_font_face, item_font_size),
|
||||
},
|
||||
padding = -3,
|
||||
color = d == current_item and 15 or 0,
|
||||
}
|
||||
end
|
||||
option_items[d] = option_item
|
||||
option_item.items = option_items
|
||||
option_item.name = self.options[c].name
|
||||
option_item.values = self.options[c].values
|
||||
option_item.args = self.options[c].args
|
||||
option_item.event = self.options[c].event
|
||||
option_item.current_item = d
|
||||
option_item.config = self.config
|
||||
table.insert(option_items_group, option_item)
|
||||
if d ~= #self.options[c].item_text then
|
||||
table.insert(option_items_group, items_spacing)
|
||||
end
|
||||
end
|
||||
end
|
||||
local option_items_container = CenterContainer:new{
|
||||
dimen = Geom:new{w = Screen:getWidth()*item_align, h = option_height}
|
||||
}
|
||||
local option_items_group = HorizontalGroup:new{}
|
||||
local option_items_fixed = false
|
||||
local option_items = {}
|
||||
if type(self.options[c].item_font_size) == "table" then
|
||||
option_items_group.align = "bottom"
|
||||
option_items_fixed = true
|
||||
end
|
||||
-- make current index according to configurable table
|
||||
local current_item = nil
|
||||
local function value_diff(val1, val2, name)
|
||||
if type(val1) ~= type(val2) then
|
||||
error("different data types in option", name)
|
||||
end
|
||||
if type(val1) == "number" then
|
||||
return math.abs(val1 - val2)
|
||||
elseif type(val1) == "string" then
|
||||
return val1 == val2 and 0 or 1
|
||||
end
|
||||
end
|
||||
if self.options[c].name then
|
||||
if self.options[c].values then
|
||||
-- check if current value is stored in configurable or calculated in runtime
|
||||
local val = self.options[c].current_func and self.options[c].current_func()
|
||||
or self.config.configurable[self.options[c].name]
|
||||
local min_diff = nil
|
||||
if type(val) == "table" then
|
||||
min_diff = value_diff(val[1], self.options[c].values[1][1])
|
||||
else
|
||||
min_diff = value_diff(val, self.options[c].values[1])
|
||||
end
|
||||
|
||||
local diff = nil
|
||||
for index, val_ in pairs(self.options[c].values) do
|
||||
local diff = nil
|
||||
if type(val) == "table" then
|
||||
diff = value_diff(val[1], val_[1])
|
||||
else
|
||||
diff = value_diff(val, val_)
|
||||
end
|
||||
if val == val_ then
|
||||
current_item = index
|
||||
break
|
||||
end
|
||||
if diff <= min_diff then
|
||||
min_diff = diff
|
||||
current_item = index
|
||||
end
|
||||
end
|
||||
elseif self.options[c].args then
|
||||
-- check if current arg is stored in configurable or calculated in runtime
|
||||
local arg = self.options[c].current_func and self.options[c].current_func()
|
||||
or self.config.configurable[self.options[c].name]
|
||||
for idx, arg_ in pairs(self.options[c].args) do
|
||||
if arg_ == arg then
|
||||
current_item = idx
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.options[c].item_text then
|
||||
for d = 1, #self.options[c].item_text do
|
||||
local option_item = nil
|
||||
if option_items_fixed then
|
||||
option_item = OptionTextItem:new{
|
||||
FixedTextWidget:new{
|
||||
text = self.options[c].item_text[d],
|
||||
face = Font:getFace(item_font_face, item_font_size[d]),
|
||||
},
|
||||
padding = 3,
|
||||
color = d == current_item and 15 or 0,
|
||||
}
|
||||
else
|
||||
option_item = OptionTextItem:new{
|
||||
TextWidget:new{
|
||||
text = self.options[c].item_text[d],
|
||||
face = Font:getFace(item_font_face, item_font_size),
|
||||
},
|
||||
padding = -3,
|
||||
color = d == current_item and 15 or 0,
|
||||
}
|
||||
end
|
||||
option_items[d] = option_item
|
||||
option_item.items = option_items
|
||||
option_item.name = self.options[c].name
|
||||
option_item.values = self.options[c].values
|
||||
option_item.args = self.options[c].args
|
||||
option_item.event = self.options[c].event
|
||||
option_item.current_item = d
|
||||
option_item.config = self.config
|
||||
table.insert(option_items_group, option_item)
|
||||
if d ~= #self.options[c].item_text then
|
||||
table.insert(option_items_group, items_spacing)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.options[c].item_icons then
|
||||
for d = 1, #self.options[c].item_icons do
|
||||
local option_item = OptionIconItem:new{
|
||||
icon = ImageWidget:new{
|
||||
file = self.options[c].item_icons[d]
|
||||
},
|
||||
padding = -2,
|
||||
color = d == current_item and 15 or 0,
|
||||
}
|
||||
option_items[d] = option_item
|
||||
option_item.items = option_items
|
||||
option_item.name = self.options[c].name
|
||||
option_item.values = self.options[c].values
|
||||
option_item.args = self.options[c].args
|
||||
option_item.event = self.options[c].event
|
||||
option_item.current_item = d
|
||||
option_item.config = self.config
|
||||
table.insert(option_items_group, option_item)
|
||||
if d ~= #self.options[c].item_icons then
|
||||
table.insert(option_items_group, items_spacing)
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.options[c].item_icons then
|
||||
for d = 1, #self.options[c].item_icons do
|
||||
local option_item = OptionIconItem:new{
|
||||
icon = ImageWidget:new{
|
||||
file = self.options[c].item_icons[d]
|
||||
},
|
||||
padding = -2,
|
||||
color = d == current_item and 15 or 0,
|
||||
}
|
||||
option_items[d] = option_item
|
||||
option_item.items = option_items
|
||||
option_item.name = self.options[c].name
|
||||
option_item.values = self.options[c].values
|
||||
option_item.args = self.options[c].args
|
||||
option_item.event = self.options[c].event
|
||||
option_item.current_item = d
|
||||
option_item.config = self.config
|
||||
table.insert(option_items_group, option_item)
|
||||
if d ~= #self.options[c].item_icons then
|
||||
table.insert(option_items_group, items_spacing)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.options[c].toggle then
|
||||
local switch = ToggleSwitch:new{
|
||||
width = Screen:scaleByDPI(self.options[c].width or 216),
|
||||
name = self.options[c].name,
|
||||
toggle = self.options[c].toggle,
|
||||
alternate = self.options[c].alternate,
|
||||
values = self.options[c].values,
|
||||
args = self.options[c].args,
|
||||
event = self.options[c].event,
|
||||
events = self.options[c].events,
|
||||
config = self.config,
|
||||
}
|
||||
local position = current_item
|
||||
switch:setPosition(position)
|
||||
table.insert(option_items_group, switch)
|
||||
end
|
||||
if self.options[c].toggle then
|
||||
local switch = ToggleSwitch:new{
|
||||
width = Screen:scaleByDPI(self.options[c].width or 216),
|
||||
name = self.options[c].name,
|
||||
toggle = self.options[c].toggle,
|
||||
alternate = self.options[c].alternate,
|
||||
values = self.options[c].values,
|
||||
args = self.options[c].args,
|
||||
event = self.options[c].event,
|
||||
events = self.options[c].events,
|
||||
config = self.config,
|
||||
}
|
||||
local position = current_item
|
||||
switch:setPosition(position)
|
||||
table.insert(option_items_group, switch)
|
||||
end
|
||||
|
||||
table.insert(option_items_container, option_items_group)
|
||||
table.insert(horizontal_group, option_items_container)
|
||||
table.insert(vertical_group, horizontal_group)
|
||||
end -- if
|
||||
end -- for
|
||||
table.insert(vertical_group, VerticalSpan:new{ width = default_option_padding })
|
||||
self[1] = vertical_group
|
||||
self.dimen = vertical_group:getSize()
|
||||
table.insert(option_items_container, option_items_group)
|
||||
table.insert(horizontal_group, option_items_container)
|
||||
table.insert(vertical_group, horizontal_group)
|
||||
end -- if
|
||||
end -- for
|
||||
table.insert(vertical_group, VerticalSpan:new{ width = default_option_padding })
|
||||
self[1] = vertical_group
|
||||
self.dimen = vertical_group:getSize()
|
||||
end
|
||||
|
||||
local ConfigPanel = FrameContainer:new{ background = 0, bordersize = 0, }
|
||||
function ConfigPanel:init()
|
||||
local config_options = self.config_dialog.config_options
|
||||
local default_option = config_options.default_options and config_options.default_options
|
||||
or config_options[1].options
|
||||
local panel = ConfigOption:new{
|
||||
options = self.index and config_options[self.index].options or default_option,
|
||||
config = self.config_dialog,
|
||||
}
|
||||
self.dimen = panel:getSize()
|
||||
table.insert(self, panel)
|
||||
local config_options = self.config_dialog.config_options
|
||||
local default_option = config_options.default_options and config_options.default_options
|
||||
or config_options[1].options
|
||||
local panel = ConfigOption:new{
|
||||
options = self.index and config_options[self.index].options or default_option,
|
||||
config = self.config_dialog,
|
||||
}
|
||||
self.dimen = panel:getSize()
|
||||
table.insert(self, panel)
|
||||
end
|
||||
|
||||
local MenuBar = FrameContainer:new{ background = 0, }
|
||||
function MenuBar:init()
|
||||
local config_options = self.config_dialog.config_options
|
||||
local menu_items = {}
|
||||
local icons_width = 0
|
||||
local icons_height = 0
|
||||
for c = 1, #config_options do
|
||||
local menu_icon = ImageWidget:new{
|
||||
file = config_options[c].icon
|
||||
}
|
||||
local icon_dimen = menu_icon:getSize()
|
||||
icons_width = icons_width + icon_dimen.w
|
||||
icons_height = icon_dimen.h > icons_height and icon_dimen.h or icons_height
|
||||
local config_options = self.config_dialog.config_options
|
||||
local menu_items = {}
|
||||
local icons_width = 0
|
||||
local icons_height = 0
|
||||
for c = 1, #config_options do
|
||||
local menu_icon = ImageWidget:new{
|
||||
file = config_options[c].icon
|
||||
}
|
||||
local icon_dimen = menu_icon:getSize()
|
||||
icons_width = icons_width + icon_dimen.w
|
||||
icons_height = icon_dimen.h > icons_height and icon_dimen.h or icons_height
|
||||
|
||||
menu_items[c] = MenuBarItem:new{
|
||||
menu_icon,
|
||||
index = c,
|
||||
config = self.config_dialog,
|
||||
}
|
||||
end
|
||||
menu_items[c] = MenuBarItem:new{
|
||||
menu_icon,
|
||||
index = c,
|
||||
config = self.config_dialog,
|
||||
}
|
||||
end
|
||||
|
||||
local spacing = HorizontalSpan:new{
|
||||
width = (Screen:getWidth() - icons_width) / (#menu_items+1)
|
||||
}
|
||||
local spacing = HorizontalSpan:new{
|
||||
width = (Screen:getWidth() - icons_width) / (#menu_items+1)
|
||||
}
|
||||
|
||||
local menu_bar = HorizontalGroup:new{}
|
||||
local menu_bar = HorizontalGroup:new{}
|
||||
|
||||
for c = 1, #menu_items do
|
||||
table.insert(menu_bar, spacing)
|
||||
table.insert(menu_bar, menu_items[c])
|
||||
end
|
||||
table.insert(menu_bar, spacing)
|
||||
for c = 1, #menu_items do
|
||||
table.insert(menu_bar, spacing)
|
||||
table.insert(menu_bar, menu_items[c])
|
||||
end
|
||||
table.insert(menu_bar, spacing)
|
||||
|
||||
self.dimen = Geom:new{ w = Screen:getWidth(), h = icons_height}
|
||||
table.insert(self, menu_bar)
|
||||
self.dimen = Geom:new{ w = Screen:getWidth(), h = icons_height}
|
||||
table.insert(self, menu_bar)
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -405,122 +405,122 @@ Widget that displays config menubar and config panel
|
||||
--]]
|
||||
|
||||
local ConfigDialog = InputContainer:new{
|
||||
--is_borderless = false,
|
||||
panel_index = 1,
|
||||
--is_borderless = false,
|
||||
panel_index = 1,
|
||||
}
|
||||
|
||||
function ConfigDialog:init()
|
||||
------------------------------------------
|
||||
-- start to set up widget layout ---------
|
||||
------------------------------------------
|
||||
self.config_menubar = MenuBar:new{
|
||||
config_dialog = self,
|
||||
}
|
||||
self:update()
|
||||
------------------------------------------
|
||||
-- start to set up input event callback --
|
||||
------------------------------------------
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events.TapCloseMenu = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
-- set up keyboard events
|
||||
self.key_events.Close = { {"Back"}, doc = _("close config menu") }
|
||||
-- we won't catch presses to "Right"
|
||||
self.key_events.FocusRight = nil
|
||||
end
|
||||
self.key_events.Select = { {"Press"}, doc = _("select current menu item") }
|
||||
------------------------------------------
|
||||
-- start to set up widget layout ---------
|
||||
------------------------------------------
|
||||
self.config_menubar = MenuBar:new{
|
||||
config_dialog = self,
|
||||
}
|
||||
self:update()
|
||||
------------------------------------------
|
||||
-- start to set up input event callback --
|
||||
------------------------------------------
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events.TapCloseMenu = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
-- set up keyboard events
|
||||
self.key_events.Close = { {"Back"}, doc = _("close config menu") }
|
||||
-- we won't catch presses to "Right"
|
||||
self.key_events.FocusRight = nil
|
||||
end
|
||||
self.key_events.Select = { {"Press"}, doc = _("select current menu item") }
|
||||
end
|
||||
|
||||
function ConfigDialog:updateConfigPanel(index)
|
||||
|
||||
|
||||
end
|
||||
|
||||
function ConfigDialog:update()
|
||||
self.config_panel = ConfigPanel:new{
|
||||
index = self.panel_index,
|
||||
config_dialog = self,
|
||||
}
|
||||
self.dialog_frame = FrameContainer:new{
|
||||
background = 0,
|
||||
VerticalGroup:new{
|
||||
self.config_panel,
|
||||
self.config_menubar,
|
||||
},
|
||||
}
|
||||
self.config_panel = ConfigPanel:new{
|
||||
index = self.panel_index,
|
||||
config_dialog = self,
|
||||
}
|
||||
self.dialog_frame = FrameContainer:new{
|
||||
background = 0,
|
||||
VerticalGroup:new{
|
||||
self.config_panel,
|
||||
self.config_menubar,
|
||||
},
|
||||
}
|
||||
|
||||
self[1] = BottomContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
self.dialog_frame,
|
||||
}
|
||||
self[1] = BottomContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
self.dialog_frame,
|
||||
}
|
||||
end
|
||||
|
||||
function ConfigDialog:onShowConfigPanel(index)
|
||||
self.panel_index = index
|
||||
self:update()
|
||||
UIManager.repaint_all = true
|
||||
return true
|
||||
self.panel_index = index
|
||||
self:update()
|
||||
UIManager.repaint_all = true
|
||||
return true
|
||||
end
|
||||
|
||||
function ConfigDialog:onConfigChoice(option_name, option_value)
|
||||
--DEBUG("config option value", option_name, option_value)
|
||||
self.configurable[option_name] = option_value
|
||||
self.ui:handleEvent(Event:new("StartActivityIndicator"))
|
||||
return true
|
||||
--DEBUG("config option value", option_name, option_value)
|
||||
self.configurable[option_name] = option_value
|
||||
self.ui:handleEvent(Event:new("StartActivityIndicator"))
|
||||
return true
|
||||
end
|
||||
|
||||
function ConfigDialog:onConfigEvent(option_event, option_arg)
|
||||
--DEBUG("config option event", option_event, option_arg)
|
||||
self.ui:handleEvent(Event:new(option_event, option_arg))
|
||||
return true
|
||||
--DEBUG("config option event", option_event, option_arg)
|
||||
self.ui:handleEvent(Event:new(option_event, option_arg))
|
||||
return true
|
||||
end
|
||||
|
||||
function ConfigDialog:onConfigEvents(option_events, arg_index)
|
||||
--DEBUG("config option events", option_events, arg_index)
|
||||
for i=1, #option_events do
|
||||
option_events[i].args = option_events[i].args or {}
|
||||
self.ui:handleEvent(Event:new(option_events[i].event, option_events[i].args[arg_index]))
|
||||
end
|
||||
return true
|
||||
--DEBUG("config option events", option_events, arg_index)
|
||||
for i=1, #option_events do
|
||||
option_events[i].args = option_events[i].args or {}
|
||||
self.ui:handleEvent(Event:new(option_events[i].event, option_events[i].args[arg_index]))
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ConfigDialog:onConfigChoose(values, name, event, args, events, position)
|
||||
UIManager:scheduleIn(0.05, function()
|
||||
if values then
|
||||
self:onConfigChoice(name, values[position])
|
||||
end
|
||||
if event then
|
||||
args = args or {}
|
||||
self:onConfigEvent(event, args[position])
|
||||
end
|
||||
if events then
|
||||
self:onConfigEvents(events, position)
|
||||
end
|
||||
UIManager.repaint_all = true
|
||||
end)
|
||||
UIManager:scheduleIn(0.05, function()
|
||||
if values then
|
||||
self:onConfigChoice(name, values[position])
|
||||
end
|
||||
if event then
|
||||
args = args or {}
|
||||
self:onConfigEvent(event, args[position])
|
||||
end
|
||||
if events then
|
||||
self:onConfigEvents(events, position)
|
||||
end
|
||||
UIManager.repaint_all = true
|
||||
end)
|
||||
end
|
||||
|
||||
function ConfigDialog:closeDialog()
|
||||
UIManager:close(self)
|
||||
if self.close_callback then
|
||||
self.close_callback()
|
||||
end
|
||||
return true
|
||||
UIManager:close(self)
|
||||
if self.close_callback then
|
||||
self.close_callback()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ConfigDialog:onTapCloseMenu(arg, ges_ev)
|
||||
if ges_ev.pos:notIntersectWith(self.dialog_frame.dimen) then
|
||||
self:closeDialog()
|
||||
return true
|
||||
end
|
||||
if ges_ev.pos:notIntersectWith(self.dialog_frame.dimen) then
|
||||
self:closeDialog()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return ConfigDialog
|
||||
|
||||
@@ -20,86 +20,86 @@ local _ = require("gettext")
|
||||
Widget that shows a message and OK/Cancel buttons
|
||||
]]
|
||||
local ConfirmBox = FocusManager:new{
|
||||
text = _("no text"),
|
||||
width = nil,
|
||||
ok_text = _("OK"),
|
||||
cancel_text = _("Cancel"),
|
||||
ok_callback = function() end,
|
||||
cancel_callback = function() end,
|
||||
text = _("no text"),
|
||||
width = nil,
|
||||
ok_text = _("OK"),
|
||||
cancel_text = _("Cancel"),
|
||||
ok_callback = function() end,
|
||||
cancel_callback = function() end,
|
||||
}
|
||||
|
||||
function ConfirmBox:init()
|
||||
-- calculate box width on the fly if not given
|
||||
if not self.width then
|
||||
self.width = Screen:getWidth() - 200
|
||||
end
|
||||
-- build bottons
|
||||
self.key_events.Close = { {{"Home","Back"}}, doc = _("cancel") }
|
||||
self.key_events.Select = { {{"Enter","Press"}}, doc = _("chose selected option") }
|
||||
-- calculate box width on the fly if not given
|
||||
if not self.width then
|
||||
self.width = Screen:getWidth() - 200
|
||||
end
|
||||
-- build bottons
|
||||
self.key_events.Close = { {{"Home","Back"}}, doc = _("cancel") }
|
||||
self.key_events.Select = { {{"Enter","Press"}}, doc = _("chose selected option") }
|
||||
|
||||
local ok_button = Button:new{
|
||||
text = self.ok_text,
|
||||
callback = function()
|
||||
self.ok_callback()
|
||||
UIManager:close(self)
|
||||
end,
|
||||
}
|
||||
local cancel_button = Button:new{
|
||||
text = self.cancel_text,
|
||||
preselect = true,
|
||||
callback = function()
|
||||
self.cancel_callback()
|
||||
UIManager:close(self)
|
||||
end,
|
||||
}
|
||||
local ok_button = Button:new{
|
||||
text = self.ok_text,
|
||||
callback = function()
|
||||
self.ok_callback()
|
||||
UIManager:close(self)
|
||||
end,
|
||||
}
|
||||
local cancel_button = Button:new{
|
||||
text = self.cancel_text,
|
||||
preselect = true,
|
||||
callback = function()
|
||||
self.cancel_callback()
|
||||
UIManager:close(self)
|
||||
end,
|
||||
}
|
||||
|
||||
self.layout = { { ok_button, cancel_button } }
|
||||
self.selected.x = 2 -- Cancel is default
|
||||
self.layout = { { ok_button, cancel_button } }
|
||||
self.selected.x = 2 -- Cancel is default
|
||||
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
FrameContainer:new{
|
||||
margin = 2,
|
||||
background = 0,
|
||||
padding = 10,
|
||||
HorizontalGroup:new{
|
||||
ImageWidget:new{
|
||||
file = "resources/info-i.png"
|
||||
},
|
||||
HorizontalSpan:new{ width = 10 },
|
||||
VerticalGroup:new{
|
||||
align = "left",
|
||||
TextBoxWidget:new{
|
||||
text = self.text,
|
||||
face = Font:getFace("cfont", 30),
|
||||
width = self.width,
|
||||
},
|
||||
VerticalSpan:new{ width = 10 },
|
||||
HorizontalGroup:new{
|
||||
ok_button,
|
||||
HorizontalSpan:new{ width = 10 },
|
||||
cancel_button,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
FrameContainer:new{
|
||||
margin = 2,
|
||||
background = 0,
|
||||
padding = 10,
|
||||
HorizontalGroup:new{
|
||||
ImageWidget:new{
|
||||
file = "resources/info-i.png"
|
||||
},
|
||||
HorizontalSpan:new{ width = 10 },
|
||||
VerticalGroup:new{
|
||||
align = "left",
|
||||
TextBoxWidget:new{
|
||||
text = self.text,
|
||||
face = Font:getFace("cfont", 30),
|
||||
width = self.width,
|
||||
},
|
||||
VerticalSpan:new{ width = 10 },
|
||||
HorizontalGroup:new{
|
||||
ok_button,
|
||||
HorizontalSpan:new{ width = 10 },
|
||||
cancel_button,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function ConfirmBox:onClose()
|
||||
UIManager:close(self)
|
||||
return true
|
||||
UIManager:close(self)
|
||||
return true
|
||||
end
|
||||
|
||||
function ConfirmBox:onSelect()
|
||||
DEBUG("selected:", self.selected.x)
|
||||
if self.selected.x == 1 then
|
||||
self:ok_callback()
|
||||
else
|
||||
self:cancel_callback()
|
||||
end
|
||||
UIManager:close(self)
|
||||
return true
|
||||
DEBUG("selected:", self.selected.x)
|
||||
if self.selected.x == 1 then
|
||||
self:ok_callback()
|
||||
else
|
||||
self:cancel_callback()
|
||||
end
|
||||
UIManager:close(self)
|
||||
return true
|
||||
end
|
||||
|
||||
return ConfirmBox
|
||||
|
||||
@@ -8,24 +8,24 @@ dimensions
|
||||
local BottomContainer = WidgetContainer:new()
|
||||
|
||||
function BottomContainer:paintTo(bb, x, y)
|
||||
local contentSize = self[1]:getSize()
|
||||
if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
|
||||
-- throw error? paint to scrap buffer and blit partially?
|
||||
-- for now, we ignore this
|
||||
end
|
||||
self[1]:paintTo(bb,
|
||||
x + math.floor((self.dimen.w - contentSize.w)/2),
|
||||
y + (self.dimen.h - contentSize.h))
|
||||
local contentSize = self[1]:getSize()
|
||||
if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
|
||||
-- throw error? paint to scrap buffer and blit partially?
|
||||
-- for now, we ignore this
|
||||
end
|
||||
self[1]:paintTo(bb,
|
||||
x + math.floor((self.dimen.w - contentSize.w)/2),
|
||||
y + (self.dimen.h - contentSize.h))
|
||||
end
|
||||
|
||||
function BottomContainer:contentRange()
|
||||
local contentSize = self[1]:getSize()
|
||||
return Geom:new{
|
||||
x = (self.dimen.x or 0) + math.floor((self.dimen.w - contentSize.w)/2),
|
||||
y = (self.dimen.y or 0) + self.dimen.h - contentSize.h,
|
||||
w = contentSize.w,
|
||||
h = contentSize.h
|
||||
}
|
||||
local contentSize = self[1]:getSize()
|
||||
return Geom:new{
|
||||
x = (self.dimen.x or 0) + math.floor((self.dimen.w - contentSize.w)/2),
|
||||
y = (self.dimen.y or 0) + self.dimen.h - contentSize.h,
|
||||
w = contentSize.w,
|
||||
h = contentSize.h
|
||||
}
|
||||
end
|
||||
|
||||
return BottomContainer
|
||||
|
||||
@@ -6,20 +6,20 @@ CenterContainer centers its content (1 widget) within its own dimensions
|
||||
local CenterContainer = WidgetContainer:new()
|
||||
|
||||
function CenterContainer:paintTo(bb, x, y)
|
||||
local contentSize = self[1]:getSize()
|
||||
if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
|
||||
-- throw error? paint to scrap buffer and blit partially?
|
||||
-- for now, we ignore this
|
||||
end
|
||||
local x_pos = x
|
||||
local y_pos = y
|
||||
if self.ignore ~= "height" then
|
||||
y_pos = y + math.floor((self.dimen.h - contentSize.h)/2)
|
||||
end
|
||||
if self.ignore ~= "width" then
|
||||
x_pos = x + math.floor((self.dimen.w - contentSize.w)/2)
|
||||
end
|
||||
self[1]:paintTo(bb, x_pos, y_pos)
|
||||
local contentSize = self[1]:getSize()
|
||||
if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
|
||||
-- throw error? paint to scrap buffer and blit partially?
|
||||
-- for now, we ignore this
|
||||
end
|
||||
local x_pos = x
|
||||
local y_pos = y
|
||||
if self.ignore ~= "height" then
|
||||
y_pos = y + math.floor((self.dimen.h - contentSize.h)/2)
|
||||
end
|
||||
if self.ignore ~= "width" then
|
||||
x_pos = x + math.floor((self.dimen.w - contentSize.w)/2)
|
||||
end
|
||||
self[1]:paintTo(bb, x_pos, y_pos)
|
||||
end
|
||||
|
||||
return CenterContainer
|
||||
|
||||
@@ -6,56 +6,56 @@ A FrameContainer is some graphics content (1 widget) that is surrounded by a
|
||||
frame
|
||||
--]]
|
||||
local FrameContainer = WidgetContainer:new{
|
||||
background = nil,
|
||||
color = 15,
|
||||
margin = 0,
|
||||
radius = 0,
|
||||
bordersize = 2,
|
||||
padding = 5,
|
||||
width = nil,
|
||||
height = nil,
|
||||
invert = false,
|
||||
background = nil,
|
||||
color = 15,
|
||||
margin = 0,
|
||||
radius = 0,
|
||||
bordersize = 2,
|
||||
padding = 5,
|
||||
width = nil,
|
||||
height = nil,
|
||||
invert = false,
|
||||
}
|
||||
|
||||
function FrameContainer:getSize()
|
||||
local content_size = self[1]:getSize()
|
||||
return Geom:new{
|
||||
w = content_size.w + ( self.margin + self.bordersize + self.padding ) * 2,
|
||||
h = content_size.h + ( self.margin + self.bordersize + self.padding ) * 2
|
||||
}
|
||||
local content_size = self[1]:getSize()
|
||||
return Geom:new{
|
||||
w = content_size.w + ( self.margin + self.bordersize + self.padding ) * 2,
|
||||
h = content_size.h + ( self.margin + self.bordersize + self.padding ) * 2
|
||||
}
|
||||
end
|
||||
|
||||
function FrameContainer:paintTo(bb, x, y)
|
||||
local my_size = self:getSize()
|
||||
self.dimen = Geom:new{
|
||||
x = x, y = y,
|
||||
w = my_size.w,
|
||||
h = my_size.h
|
||||
}
|
||||
local container_width = self.width or my_size.w
|
||||
local container_height = self.height or my_size.h
|
||||
local my_size = self:getSize()
|
||||
self.dimen = Geom:new{
|
||||
x = x, y = y,
|
||||
w = my_size.w,
|
||||
h = my_size.h
|
||||
}
|
||||
local container_width = self.width or my_size.w
|
||||
local container_height = self.height or my_size.h
|
||||
|
||||
--@TODO get rid of margin here? 13.03 2013 (houqp)
|
||||
if self.background then
|
||||
bb:paintRoundedRect(x, y, container_width, container_height,
|
||||
self.background, self.radius)
|
||||
end
|
||||
if self.bordersize > 0 then
|
||||
bb:paintBorder(x + self.margin, y + self.margin,
|
||||
container_width - self.margin * 2,
|
||||
container_height - self.margin * 2,
|
||||
self.bordersize, self.color, self.radius)
|
||||
end
|
||||
if self[1] then
|
||||
self[1]:paintTo(bb,
|
||||
x + self.margin + self.bordersize + self.padding,
|
||||
y + self.margin + self.bordersize + self.padding)
|
||||
end
|
||||
if self.invert then
|
||||
bb:invertRect(x + self.bordersize, y + self.bordersize,
|
||||
container_width - 2*self.bordersize,
|
||||
container_height - 2*self.bordersize)
|
||||
end
|
||||
--@TODO get rid of margin here? 13.03 2013 (houqp)
|
||||
if self.background then
|
||||
bb:paintRoundedRect(x, y, container_width, container_height,
|
||||
self.background, self.radius)
|
||||
end
|
||||
if self.bordersize > 0 then
|
||||
bb:paintBorder(x + self.margin, y + self.margin,
|
||||
container_width - self.margin * 2,
|
||||
container_height - self.margin * 2,
|
||||
self.bordersize, self.color, self.radius)
|
||||
end
|
||||
if self[1] then
|
||||
self[1]:paintTo(bb,
|
||||
x + self.margin + self.bordersize + self.padding,
|
||||
y + self.margin + self.bordersize + self.padding)
|
||||
end
|
||||
if self.invert then
|
||||
bb:invertRect(x + self.bordersize, y + self.bordersize,
|
||||
container_width - 2*self.bordersize,
|
||||
container_height - 2*self.bordersize)
|
||||
end
|
||||
end
|
||||
|
||||
return FrameContainer
|
||||
|
||||
@@ -8,60 +8,60 @@ an InputContainer is an WidgetContainer that handles input events
|
||||
|
||||
an example for a key_event is this:
|
||||
|
||||
PanBy20 = {
|
||||
{ "Shift", Input.group.Cursor },
|
||||
seqtext = "Shift+Cursor",
|
||||
doc = "pan by 20px",
|
||||
event = "Pan", args = 20, is_inactive = true,
|
||||
},
|
||||
PanNormal = {
|
||||
{ Input.group.Cursor },
|
||||
seqtext = "Cursor",
|
||||
doc = "pan by 10 px", event = "Pan", args = 10,
|
||||
},
|
||||
Quit = { {"Home"} },
|
||||
PanBy20 = {
|
||||
{ "Shift", Input.group.Cursor },
|
||||
seqtext = "Shift+Cursor",
|
||||
doc = "pan by 20px",
|
||||
event = "Pan", args = 20, is_inactive = true,
|
||||
},
|
||||
PanNormal = {
|
||||
{ Input.group.Cursor },
|
||||
seqtext = "Cursor",
|
||||
doc = "pan by 10 px", event = "Pan", args = 10,
|
||||
},
|
||||
Quit = { {"Home"} },
|
||||
|
||||
it is suggested to reference configurable sequences from another table
|
||||
and store that table as configuration setting
|
||||
--]]
|
||||
local InputContainer = WidgetContainer:new{
|
||||
vertical_align = "top",
|
||||
vertical_align = "top",
|
||||
}
|
||||
|
||||
function InputContainer:_init()
|
||||
-- we need to do deep copy here
|
||||
local new_key_events = {}
|
||||
if self.key_events then
|
||||
for k,v in pairs(self.key_events) do
|
||||
new_key_events[k] = v
|
||||
end
|
||||
end
|
||||
self.key_events = new_key_events
|
||||
-- we need to do deep copy here
|
||||
local new_key_events = {}
|
||||
if self.key_events then
|
||||
for k,v in pairs(self.key_events) do
|
||||
new_key_events[k] = v
|
||||
end
|
||||
end
|
||||
self.key_events = new_key_events
|
||||
|
||||
local new_ges_events = {}
|
||||
if self.ges_events then
|
||||
for k,v in pairs(self.ges_events) do
|
||||
new_ges_events[k] = v
|
||||
end
|
||||
end
|
||||
self.ges_events = new_ges_events
|
||||
local new_ges_events = {}
|
||||
if self.ges_events then
|
||||
for k,v in pairs(self.ges_events) do
|
||||
new_ges_events[k] = v
|
||||
end
|
||||
end
|
||||
self.ges_events = new_ges_events
|
||||
|
||||
if not self.dimen then
|
||||
self.dimen = Geom:new{}
|
||||
end
|
||||
if not self.dimen then
|
||||
self.dimen = Geom:new{}
|
||||
end
|
||||
end
|
||||
|
||||
function InputContainer:paintTo(bb, x, y)
|
||||
self.dimen.x = x
|
||||
self.dimen.y = y
|
||||
if self[1] then
|
||||
if self.vertical_align == "center" then
|
||||
local content_size = self[1]:getSize()
|
||||
self[1]:paintTo(bb, x, y + math.floor((self.dimen.h - content_size.h)/2))
|
||||
else
|
||||
self[1]:paintTo(bb, x, y)
|
||||
end
|
||||
end
|
||||
self.dimen.x = x
|
||||
self.dimen.y = y
|
||||
if self[1] then
|
||||
if self.vertical_align == "center" then
|
||||
local content_size = self[1]:getSize()
|
||||
self[1]:paintTo(bb, x, y + math.floor((self.dimen.h - content_size.h)/2))
|
||||
else
|
||||
self[1]:paintTo(bb, x, y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -69,28 +69,28 @@ the following handler handles keypresses and checks if they lead to a command.
|
||||
if this is the case, we retransmit another event within ourselves
|
||||
--]]
|
||||
function InputContainer:onKeyPress(key)
|
||||
for name, seq in pairs(self.key_events) do
|
||||
if not seq.is_inactive then
|
||||
for _, oneseq in ipairs(seq) do
|
||||
if key:match(oneseq) then
|
||||
local eventname = seq.event or name
|
||||
return self:handleEvent(Event:new(eventname, seq.args, key))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for name, seq in pairs(self.key_events) do
|
||||
if not seq.is_inactive then
|
||||
for _, oneseq in ipairs(seq) do
|
||||
if key:match(oneseq) then
|
||||
local eventname = seq.event or name
|
||||
return self:handleEvent(Event:new(eventname, seq.args, key))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function InputContainer:onGesture(ev)
|
||||
for name, gsseq in pairs(self.ges_events) do
|
||||
for _, gs_range in ipairs(gsseq) do
|
||||
--DEBUG("gs_range", gs_range)
|
||||
if gs_range:match(ev) then
|
||||
local eventname = gsseq.event or name
|
||||
return self:handleEvent(Event:new(eventname, gsseq.args, ev))
|
||||
end
|
||||
end
|
||||
end
|
||||
for name, gsseq in pairs(self.ges_events) do
|
||||
for _, gs_range in ipairs(gsseq) do
|
||||
--DEBUG("gs_range", gs_range)
|
||||
if gs_range:match(ev) then
|
||||
local eventname = gsseq.event or name
|
||||
return self:handleEvent(Event:new(eventname, gsseq.args, ev))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return InputContainer
|
||||
|
||||
@@ -6,12 +6,12 @@ LeftContainer aligns its content (1 widget) at the left of its own dimensions
|
||||
local LeftContainer = WidgetContainer:new()
|
||||
|
||||
function LeftContainer:paintTo(bb, x, y)
|
||||
local contentSize = self[1]:getSize()
|
||||
if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
|
||||
-- throw error? paint to scrap buffer and blit partially?
|
||||
-- for now, we ignore this
|
||||
end
|
||||
self[1]:paintTo(bb, x , y + math.floor((self.dimen.h - contentSize.h)/2))
|
||||
local contentSize = self[1]:getSize()
|
||||
if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
|
||||
-- throw error? paint to scrap buffer and blit partially?
|
||||
-- for now, we ignore this
|
||||
end
|
||||
self[1]:paintTo(bb, x , y + math.floor((self.dimen.h - contentSize.h)/2))
|
||||
end
|
||||
|
||||
return LeftContainer
|
||||
|
||||
@@ -6,14 +6,14 @@ RightContainer aligns its content (1 widget) at the right of its own dimensions
|
||||
local RightContainer = WidgetContainer:new()
|
||||
|
||||
function RightContainer:paintTo(bb, x, y)
|
||||
local contentSize = self[1]:getSize()
|
||||
if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
|
||||
-- throw error? paint to scrap buffer and blit partially?
|
||||
-- for now, we ignore this
|
||||
end
|
||||
self[1]:paintTo(bb,
|
||||
x + (self.dimen.w - contentSize.w),
|
||||
y + math.floor((self.dimen.h - contentSize.h)/2))
|
||||
local contentSize = self[1]:getSize()
|
||||
if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
|
||||
-- throw error? paint to scrap buffer and blit partially?
|
||||
-- for now, we ignore this
|
||||
end
|
||||
self[1]:paintTo(bb,
|
||||
x + (self.dimen.w - contentSize.w),
|
||||
y + math.floor((self.dimen.h - contentSize.h)/2))
|
||||
end
|
||||
|
||||
return RightContainer
|
||||
|
||||
@@ -7,36 +7,36 @@ a line under its child node
|
||||
--]]
|
||||
|
||||
local UnderlineContainer = WidgetContainer:new{
|
||||
linesize = 2,
|
||||
padding = 1,
|
||||
color = 0,
|
||||
vertical_align = "top",
|
||||
linesize = 2,
|
||||
padding = 1,
|
||||
color = 0,
|
||||
vertical_align = "top",
|
||||
}
|
||||
|
||||
function UnderlineContainer:getSize()
|
||||
return self:getContentSize()
|
||||
return self:getContentSize()
|
||||
end
|
||||
|
||||
function UnderlineContainer:getContentSize()
|
||||
local contentSize = self[1]:getSize()
|
||||
return Geom:new{
|
||||
w = contentSize.w,
|
||||
h = contentSize.h + self.linesize + self.padding
|
||||
}
|
||||
local contentSize = self[1]:getSize()
|
||||
return Geom:new{
|
||||
w = contentSize.w,
|
||||
h = contentSize.h + self.linesize + self.padding
|
||||
}
|
||||
end
|
||||
|
||||
function UnderlineContainer:paintTo(bb, x, y)
|
||||
local container_size = self:getSize()
|
||||
local content_size = self:getContentSize()
|
||||
local p_y = y
|
||||
if self.vertical_align == "center" then
|
||||
p_y = math.floor((container_size.h - content_size.h) / 2) + y
|
||||
elseif self.vertical_align == "bottom" then
|
||||
p_y = (container_size.h - content_size.h) + y
|
||||
end
|
||||
self[1]:paintTo(bb, x, p_y)
|
||||
bb:paintRect(x, y + container_size.h - self.linesize,
|
||||
container_size.w, self.linesize, self.color)
|
||||
local container_size = self:getSize()
|
||||
local content_size = self:getContentSize()
|
||||
local p_y = y
|
||||
if self.vertical_align == "center" then
|
||||
p_y = math.floor((container_size.h - content_size.h) / 2) + y
|
||||
elseif self.vertical_align == "bottom" then
|
||||
p_y = (container_size.h - content_size.h) + y
|
||||
end
|
||||
self[1]:paintTo(bb, x, p_y)
|
||||
bb:paintRect(x, y + container_size.h - self.linesize,
|
||||
container_size.w, self.linesize, self.color)
|
||||
end
|
||||
|
||||
return UnderlineContainer
|
||||
|
||||
@@ -7,83 +7,83 @@ WidgetContainer is a container for another Widget
|
||||
local WidgetContainer = Widget:new()
|
||||
|
||||
function WidgetContainer:init()
|
||||
if not self.dimen then
|
||||
self.dimen = Geom:new{}
|
||||
end
|
||||
if not self.dimen.w then
|
||||
self.dimen.w = self[1].getSize().w
|
||||
end
|
||||
if not self.dimen.h then
|
||||
self.dimen.h = self[1].getSize().h
|
||||
end
|
||||
if not self.dimen then
|
||||
self.dimen = Geom:new{}
|
||||
end
|
||||
if not self.dimen.w then
|
||||
self.dimen.w = self[1].getSize().w
|
||||
end
|
||||
if not self.dimen.h then
|
||||
self.dimen.h = self[1].getSize().h
|
||||
end
|
||||
end
|
||||
|
||||
function WidgetContainer:getSize()
|
||||
if self.dimen then
|
||||
-- fixed size
|
||||
return self.dimen
|
||||
elseif self[1] then
|
||||
-- return size of first child widget
|
||||
return self[1]:getSize()
|
||||
else
|
||||
return Geom:new{ w = 0, h = 0 }
|
||||
end
|
||||
if self.dimen then
|
||||
-- fixed size
|
||||
return self.dimen
|
||||
elseif self[1] then
|
||||
-- return size of first child widget
|
||||
return self[1]:getSize()
|
||||
else
|
||||
return Geom:new{ w = 0, h = 0 }
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
delete all child widgets
|
||||
--]]
|
||||
function WidgetContainer:clear()
|
||||
while table.remove(self) do end
|
||||
while table.remove(self) do end
|
||||
end
|
||||
|
||||
function WidgetContainer:paintTo(bb, x, y)
|
||||
-- default to pass request to first child widget
|
||||
if self[1] then
|
||||
x = x + (self.dimen.x or 0)
|
||||
y = y + (self.dimen.y or 0)
|
||||
if self.align == "top" then
|
||||
local contentSize = self[1]:getSize()
|
||||
self[1]:paintTo(bb,
|
||||
x + math.floor((self.dimen.w - contentSize.w)/2), y)
|
||||
elseif self.align == "bottom" then
|
||||
local contentSize = self[1]:getSize()
|
||||
self[1]:paintTo(bb,
|
||||
x + math.floor((self.dimen.w - contentSize.w)/2),
|
||||
y + (self.dimen.h - contentSize.h))
|
||||
else
|
||||
return self[1]:paintTo(bb, x, y)
|
||||
end
|
||||
end
|
||||
-- default to pass request to first child widget
|
||||
if self[1] then
|
||||
x = x + (self.dimen.x or 0)
|
||||
y = y + (self.dimen.y or 0)
|
||||
if self.align == "top" then
|
||||
local contentSize = self[1]:getSize()
|
||||
self[1]:paintTo(bb,
|
||||
x + math.floor((self.dimen.w - contentSize.w)/2), y)
|
||||
elseif self.align == "bottom" then
|
||||
local contentSize = self[1]:getSize()
|
||||
self[1]:paintTo(bb,
|
||||
x + math.floor((self.dimen.w - contentSize.w)/2),
|
||||
y + (self.dimen.h - contentSize.h))
|
||||
else
|
||||
return self[1]:paintTo(bb, x, y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function WidgetContainer:propagateEvent(event)
|
||||
-- propagate to children
|
||||
for _, widget in ipairs(self) do
|
||||
if widget:handleEvent(event) then
|
||||
-- stop propagating when an event handler returns true
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
-- propagate to children
|
||||
for _, widget in ipairs(self) do
|
||||
if widget:handleEvent(event) then
|
||||
-- stop propagating when an event handler returns true
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[
|
||||
Containers will pass events to children or react on them themselves
|
||||
--]]
|
||||
function WidgetContainer:handleEvent(event)
|
||||
if not self:propagateEvent(event) then
|
||||
-- call our own standard event handler
|
||||
return Widget.handleEvent(self, event)
|
||||
else
|
||||
return true
|
||||
end
|
||||
if not self:propagateEvent(event) then
|
||||
-- call our own standard event handler
|
||||
return Widget.handleEvent(self, event)
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function WidgetContainer:free()
|
||||
for _, widget in ipairs(self) do
|
||||
if widget.free then widget:free() end
|
||||
end
|
||||
for _, widget in ipairs(self) do
|
||||
if widget.free then widget:free() end
|
||||
end
|
||||
end
|
||||
|
||||
return WidgetContainer
|
||||
|
||||
@@ -24,280 +24,280 @@ local _ = require("gettext")
|
||||
Display quick lookup word definition
|
||||
]]
|
||||
local DictQuickLookup = InputContainer:new{
|
||||
results = nil,
|
||||
lookupword = nil,
|
||||
dictionary = nil,
|
||||
definition = nil,
|
||||
dict_index = 1,
|
||||
title_face = Font:getFace("tfont", 22),
|
||||
word_face = Font:getFace("tfont", 22),
|
||||
content_face = Font:getFace("cfont", DDICT_FONT_SIZE),
|
||||
width = nil,
|
||||
height = nil,
|
||||
|
||||
title_padding = Screen:scaleByDPI(5),
|
||||
title_margin = Screen:scaleByDPI(2),
|
||||
word_padding = Screen:scaleByDPI(2),
|
||||
word_margin = Screen:scaleByDPI(2),
|
||||
definition_padding = Screen:scaleByDPI(2),
|
||||
definition_margin = Screen:scaleByDPI(2),
|
||||
button_padding = Screen:scaleByDPI(14),
|
||||
results = nil,
|
||||
lookupword = nil,
|
||||
dictionary = nil,
|
||||
definition = nil,
|
||||
dict_index = 1,
|
||||
title_face = Font:getFace("tfont", 22),
|
||||
word_face = Font:getFace("tfont", 22),
|
||||
content_face = Font:getFace("cfont", DDICT_FONT_SIZE),
|
||||
width = nil,
|
||||
height = nil,
|
||||
|
||||
title_padding = Screen:scaleByDPI(5),
|
||||
title_margin = Screen:scaleByDPI(2),
|
||||
word_padding = Screen:scaleByDPI(2),
|
||||
word_margin = Screen:scaleByDPI(2),
|
||||
definition_padding = Screen:scaleByDPI(2),
|
||||
definition_margin = Screen:scaleByDPI(2),
|
||||
button_padding = Screen:scaleByDPI(14),
|
||||
}
|
||||
|
||||
function DictQuickLookup:init()
|
||||
self:changeToDefaultDict()
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapCloseDict = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
},
|
||||
},
|
||||
Swipe = {
|
||||
GestureRange:new{
|
||||
ges = "swipe",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
table.insert(self.dict_bar,
|
||||
CloseButton:new{
|
||||
window = self,
|
||||
})
|
||||
end
|
||||
self:changeToDefaultDict()
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapCloseDict = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
},
|
||||
},
|
||||
Swipe = {
|
||||
GestureRange:new{
|
||||
ges = "swipe",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
table.insert(self.dict_bar,
|
||||
CloseButton:new{
|
||||
window = self,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function DictQuickLookup:update()
|
||||
-- dictionary title
|
||||
self.dict_title = FrameContainer:new{
|
||||
padding = self.title_padding,
|
||||
margin = self.title_margin,
|
||||
bordersize = 0,
|
||||
TextWidget:new{
|
||||
text = self.dictionary,
|
||||
face = self.title_face,
|
||||
bold = true,
|
||||
width = self.width - self.button_padding,
|
||||
}
|
||||
}
|
||||
-- lookup word
|
||||
local lookup_word = FrameContainer:new{
|
||||
padding = self.word_padding,
|
||||
margin = self.word_margin,
|
||||
bordersize = 0,
|
||||
TextBoxWidget:new{
|
||||
text = self.lookupword,
|
||||
face = self.word_face,
|
||||
bold = true,
|
||||
width = self.width,
|
||||
},
|
||||
}
|
||||
-- word definition
|
||||
local definition = FrameContainer:new{
|
||||
padding = self.definition_padding,
|
||||
margin = self.definition_margin,
|
||||
bordersize = 0,
|
||||
ScrollTextWidget:new{
|
||||
text = self.definition,
|
||||
face = self.content_face,
|
||||
width = self.width,
|
||||
height = self.height*0.7,
|
||||
dialog = self,
|
||||
},
|
||||
}
|
||||
local button_table = ButtonTable:new{
|
||||
width = math.max(self.width, definition:getSize().w),
|
||||
button_font_face = "cfont",
|
||||
button_font_size = 20,
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("<<"),
|
||||
enabled = self:isPrevDictAvaiable(),
|
||||
callback = function()
|
||||
self:changeToPrevDict()
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _(">>"),
|
||||
enabled = self:isNextDictAvaiable(),
|
||||
callback = function()
|
||||
self:changeToNextDict()
|
||||
end,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
text = _("Highlight"),
|
||||
enabled = false,
|
||||
callback = function()
|
||||
self.ui:handleEvent(Event:new("Highlight"))
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Add Note"),
|
||||
enabled = false,
|
||||
callback = function()
|
||||
self.ui:handleEvent(Event:new("AddNote"))
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
zero_sep = true,
|
||||
}
|
||||
local title_bar = LineWidget:new{
|
||||
--background = 8,
|
||||
dimen = Geom:new{
|
||||
w = button_table:getSize().w + self.button_padding,
|
||||
h = Screen:scaleByDPI(2),
|
||||
}
|
||||
}
|
||||
|
||||
self.dict_bar = OverlapGroup:new{
|
||||
dimen = {w = button_table:getSize().w, h = self.dict_title:getSize().h},
|
||||
self.dict_title,
|
||||
}
|
||||
|
||||
self.dict_frame = FrameContainer:new{
|
||||
radius = 8,
|
||||
bordersize = 3,
|
||||
padding = 0,
|
||||
margin = 0,
|
||||
background = 0,
|
||||
VerticalGroup:new{
|
||||
align = "left",
|
||||
self.dict_bar,
|
||||
title_bar,
|
||||
-- word
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = title_bar:getSize().w,
|
||||
h = lookup_word:getSize().h,
|
||||
},
|
||||
lookup_word,
|
||||
},
|
||||
-- definition
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = title_bar:getSize().w,
|
||||
h = definition:getSize().h,
|
||||
},
|
||||
definition,
|
||||
},
|
||||
-- buttons
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = title_bar:getSize().w,
|
||||
h = button_table:getSize().h,
|
||||
},
|
||||
button_table,
|
||||
}
|
||||
}
|
||||
}
|
||||
self[1] = WidgetContainer:new{
|
||||
align = self.align,
|
||||
dimen = self.region:copy(),
|
||||
FrameContainer:new{
|
||||
bordersize = 0,
|
||||
padding = Screen:scaleByDPI(5),
|
||||
self.dict_frame,
|
||||
}
|
||||
}
|
||||
UIManager.repaint_all = true
|
||||
UIManager.full_refresh = true
|
||||
-- dictionary title
|
||||
self.dict_title = FrameContainer:new{
|
||||
padding = self.title_padding,
|
||||
margin = self.title_margin,
|
||||
bordersize = 0,
|
||||
TextWidget:new{
|
||||
text = self.dictionary,
|
||||
face = self.title_face,
|
||||
bold = true,
|
||||
width = self.width - self.button_padding,
|
||||
}
|
||||
}
|
||||
-- lookup word
|
||||
local lookup_word = FrameContainer:new{
|
||||
padding = self.word_padding,
|
||||
margin = self.word_margin,
|
||||
bordersize = 0,
|
||||
TextBoxWidget:new{
|
||||
text = self.lookupword,
|
||||
face = self.word_face,
|
||||
bold = true,
|
||||
width = self.width,
|
||||
},
|
||||
}
|
||||
-- word definition
|
||||
local definition = FrameContainer:new{
|
||||
padding = self.definition_padding,
|
||||
margin = self.definition_margin,
|
||||
bordersize = 0,
|
||||
ScrollTextWidget:new{
|
||||
text = self.definition,
|
||||
face = self.content_face,
|
||||
width = self.width,
|
||||
height = self.height*0.7,
|
||||
dialog = self,
|
||||
},
|
||||
}
|
||||
local button_table = ButtonTable:new{
|
||||
width = math.max(self.width, definition:getSize().w),
|
||||
button_font_face = "cfont",
|
||||
button_font_size = 20,
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("<<"),
|
||||
enabled = self:isPrevDictAvaiable(),
|
||||
callback = function()
|
||||
self:changeToPrevDict()
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _(">>"),
|
||||
enabled = self:isNextDictAvaiable(),
|
||||
callback = function()
|
||||
self:changeToNextDict()
|
||||
end,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
text = _("Highlight"),
|
||||
enabled = false,
|
||||
callback = function()
|
||||
self.ui:handleEvent(Event:new("Highlight"))
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Add Note"),
|
||||
enabled = false,
|
||||
callback = function()
|
||||
self.ui:handleEvent(Event:new("AddNote"))
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
zero_sep = true,
|
||||
}
|
||||
local title_bar = LineWidget:new{
|
||||
--background = 8,
|
||||
dimen = Geom:new{
|
||||
w = button_table:getSize().w + self.button_padding,
|
||||
h = Screen:scaleByDPI(2),
|
||||
}
|
||||
}
|
||||
|
||||
self.dict_bar = OverlapGroup:new{
|
||||
dimen = {w = button_table:getSize().w, h = self.dict_title:getSize().h},
|
||||
self.dict_title,
|
||||
}
|
||||
|
||||
self.dict_frame = FrameContainer:new{
|
||||
radius = 8,
|
||||
bordersize = 3,
|
||||
padding = 0,
|
||||
margin = 0,
|
||||
background = 0,
|
||||
VerticalGroup:new{
|
||||
align = "left",
|
||||
self.dict_bar,
|
||||
title_bar,
|
||||
-- word
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = title_bar:getSize().w,
|
||||
h = lookup_word:getSize().h,
|
||||
},
|
||||
lookup_word,
|
||||
},
|
||||
-- definition
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = title_bar:getSize().w,
|
||||
h = definition:getSize().h,
|
||||
},
|
||||
definition,
|
||||
},
|
||||
-- buttons
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = title_bar:getSize().w,
|
||||
h = button_table:getSize().h,
|
||||
},
|
||||
button_table,
|
||||
}
|
||||
}
|
||||
}
|
||||
self[1] = WidgetContainer:new{
|
||||
align = self.align,
|
||||
dimen = self.region:copy(),
|
||||
FrameContainer:new{
|
||||
bordersize = 0,
|
||||
padding = Screen:scaleByDPI(5),
|
||||
self.dict_frame,
|
||||
}
|
||||
}
|
||||
UIManager.repaint_all = true
|
||||
UIManager.full_refresh = true
|
||||
end
|
||||
|
||||
function DictQuickLookup:isPrevDictAvaiable()
|
||||
return self.dict_index > 1
|
||||
return self.dict_index > 1
|
||||
end
|
||||
|
||||
function DictQuickLookup:isNextDictAvaiable()
|
||||
return self.dict_index < #self.results
|
||||
return self.dict_index < #self.results
|
||||
end
|
||||
|
||||
function DictQuickLookup:changeToPrevDict()
|
||||
self:changeDictionary(self.dict_index - 1)
|
||||
self:changeDictionary(self.dict_index - 1)
|
||||
end
|
||||
|
||||
function DictQuickLookup:changeToNextDict()
|
||||
self:changeDictionary(self.dict_index + 1)
|
||||
self:changeDictionary(self.dict_index + 1)
|
||||
end
|
||||
|
||||
function DictQuickLookup:changeDictionary(index)
|
||||
self.dict_index = index
|
||||
self.dictionary = self.results[index].dict
|
||||
self.lookupword = self.results[index].word
|
||||
self.definition = self.results[index].definition
|
||||
|
||||
local orig_dimen = self.dict_frame and self.dict_frame.dimen or Geom:new{}
|
||||
self:update()
|
||||
self.dict_index = index
|
||||
self.dictionary = self.results[index].dict
|
||||
self.lookupword = self.results[index].word
|
||||
self.definition = self.results[index].definition
|
||||
|
||||
local orig_dimen = self.dict_frame and self.dict_frame.dimen or Geom:new{}
|
||||
self:update()
|
||||
|
||||
UIManager.update_region_func = function()
|
||||
local update_region = self.dict_frame.dimen:combine(orig_dimen)
|
||||
DEBUG("update region", update_region)
|
||||
return update_region
|
||||
end
|
||||
UIManager.update_region_func = function()
|
||||
local update_region = self.dict_frame.dimen:combine(orig_dimen)
|
||||
DEBUG("update region", update_region)
|
||||
return update_region
|
||||
end
|
||||
end
|
||||
|
||||
function DictQuickLookup:changeToDefaultDict()
|
||||
if self.dictionary then
|
||||
-- dictionaries that have definition of the first word(accurate word)
|
||||
-- excluding Fuzzy queries.
|
||||
local n_accurate_dicts = nil
|
||||
local default_word = self.results[1].word
|
||||
for i=1, #self.results do
|
||||
if self.results[i].word == default_word then
|
||||
n_accurate_dicts = i
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
-- change to dictionary specified by self.dictionary
|
||||
for i=1, n_accurate_dicts do
|
||||
if self.results[i].dict == self.dictionary then
|
||||
self:changeDictionary(i)
|
||||
break
|
||||
end
|
||||
-- cannot find definition in default dictionary
|
||||
if i == n_accurate_dicts then
|
||||
self:changeDictionary(1)
|
||||
end
|
||||
end
|
||||
else
|
||||
self:changeDictionary(1)
|
||||
end
|
||||
function DictQuickLookup:changeToDefaultDict()
|
||||
if self.dictionary then
|
||||
-- dictionaries that have definition of the first word(accurate word)
|
||||
-- excluding Fuzzy queries.
|
||||
local n_accurate_dicts = nil
|
||||
local default_word = self.results[1].word
|
||||
for i=1, #self.results do
|
||||
if self.results[i].word == default_word then
|
||||
n_accurate_dicts = i
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
-- change to dictionary specified by self.dictionary
|
||||
for i=1, n_accurate_dicts do
|
||||
if self.results[i].dict == self.dictionary then
|
||||
self:changeDictionary(i)
|
||||
break
|
||||
end
|
||||
-- cannot find definition in default dictionary
|
||||
if i == n_accurate_dicts then
|
||||
self:changeDictionary(1)
|
||||
end
|
||||
end
|
||||
else
|
||||
self:changeDictionary(1)
|
||||
end
|
||||
end
|
||||
|
||||
function DictQuickLookup:onAnyKeyPressed()
|
||||
-- triggered by our defined key events
|
||||
UIManager:close(self)
|
||||
return true
|
||||
-- triggered by our defined key events
|
||||
UIManager:close(self)
|
||||
return true
|
||||
end
|
||||
|
||||
function DictQuickLookup:onTapCloseDict(arg, ges_ev)
|
||||
if ges_ev.pos:notIntersectWith(self.dict_frame.dimen) then
|
||||
self:onClose()
|
||||
return true
|
||||
elseif not ges_ev.pos:notIntersectWith(self.dict_title.dimen) then
|
||||
self.ui:handleEvent(Event:new("UpdateDefaultDict", self.dictionary))
|
||||
return true
|
||||
end
|
||||
return true
|
||||
if ges_ev.pos:notIntersectWith(self.dict_frame.dimen) then
|
||||
self:onClose()
|
||||
return true
|
||||
elseif not ges_ev.pos:notIntersectWith(self.dict_title.dimen) then
|
||||
self.ui:handleEvent(Event:new("UpdateDefaultDict", self.dictionary))
|
||||
return true
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function DictQuickLookup:onClose()
|
||||
UIManager:close(self)
|
||||
self.highlight:handleEvent(Event:new("Tap"))
|
||||
return true
|
||||
UIManager:close(self)
|
||||
self.highlight:handleEvent(Event:new("Tap"))
|
||||
return true
|
||||
end
|
||||
|
||||
return DictQuickLookup
|
||||
|
||||
@@ -8,17 +8,17 @@ will call a method "onEventName" for an event with name
|
||||
local EventListener = {}
|
||||
|
||||
function EventListener:new(o)
|
||||
local o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
if o.init then o:init() end
|
||||
return o
|
||||
local o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
if o.init then o:init() end
|
||||
return o
|
||||
end
|
||||
|
||||
function EventListener:handleEvent(event)
|
||||
if self[event.handler] then
|
||||
return self[event.handler](self, unpack(event.args))
|
||||
end
|
||||
if self[event.handler] then
|
||||
return self[event.handler](self, unpack(event.args))
|
||||
end
|
||||
end
|
||||
|
||||
return EventListener
|
||||
|
||||
@@ -5,97 +5,97 @@ local DEBUG = require("dbg")
|
||||
-- lfs
|
||||
|
||||
local FileChooser = Menu:extend{
|
||||
height = Screen:getHeight(),
|
||||
width = Screen:getWidth(),
|
||||
no_title = true,
|
||||
path = lfs.currentdir(),
|
||||
parent = nil,
|
||||
show_hidden = nil,
|
||||
show_filesize = DSHOWFILESIZE,
|
||||
filter = function(filename) return true end,
|
||||
height = Screen:getHeight(),
|
||||
width = Screen:getWidth(),
|
||||
no_title = true,
|
||||
path = lfs.currentdir(),
|
||||
parent = nil,
|
||||
show_hidden = nil,
|
||||
show_filesize = DSHOWFILESIZE,
|
||||
filter = function(filename) return true end,
|
||||
}
|
||||
|
||||
function FileChooser:init()
|
||||
self.item_table = self:genItemTableFromPath(self.path)
|
||||
Menu.init(self) -- call parent's init()
|
||||
self.item_table = self:genItemTableFromPath(self.path)
|
||||
Menu.init(self) -- call parent's init()
|
||||
end
|
||||
|
||||
function FileChooser:genItemTableFromPath(path)
|
||||
local dirs = {}
|
||||
local files = {}
|
||||
local dirs = {}
|
||||
local files = {}
|
||||
|
||||
for f in lfs.dir(self.path) do
|
||||
if self.show_hidden or not string.match(f, "^%.[^.]") then
|
||||
local filename = self.path.."/"..f
|
||||
local filemode = lfs.attributes(filename, "mode")
|
||||
if filemode == "directory" and f ~= "." and f~=".." then
|
||||
if self.dir_filter(filename) then
|
||||
table.insert(dirs, f)
|
||||
end
|
||||
elseif filemode == "file" then
|
||||
if self.file_filter(filename) then
|
||||
table.insert(files, f)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
table.sort(dirs)
|
||||
if path ~= "/" then table.insert(dirs, 1, "..") end
|
||||
table.sort(files)
|
||||
for f in lfs.dir(self.path) do
|
||||
if self.show_hidden or not string.match(f, "^%.[^.]") then
|
||||
local filename = self.path.."/"..f
|
||||
local filemode = lfs.attributes(filename, "mode")
|
||||
if filemode == "directory" and f ~= "." and f~=".." then
|
||||
if self.dir_filter(filename) then
|
||||
table.insert(dirs, f)
|
||||
end
|
||||
elseif filemode == "file" then
|
||||
if self.file_filter(filename) then
|
||||
table.insert(files, f)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
table.sort(dirs)
|
||||
if path ~= "/" then table.insert(dirs, 1, "..") end
|
||||
table.sort(files)
|
||||
|
||||
local item_table = {}
|
||||
for _, dir in ipairs(dirs) do
|
||||
table.insert(item_table, { text = dir.."/", path = self.path.."/"..dir })
|
||||
end
|
||||
for _, file in ipairs(files) do
|
||||
local full_path = self.path.."/"..file
|
||||
if self.show_filesize then
|
||||
local sstr = string.format("%4.1fM",lfs.attributes(full_path, "size")/1024/1024)
|
||||
table.insert(item_table, { text = file, mandatory = sstr, path = full_path })
|
||||
else
|
||||
table.insert(item_table, { text = file, path = full_path })
|
||||
end
|
||||
end
|
||||
local item_table = {}
|
||||
for _, dir in ipairs(dirs) do
|
||||
table.insert(item_table, { text = dir.."/", path = self.path.."/"..dir })
|
||||
end
|
||||
for _, file in ipairs(files) do
|
||||
local full_path = self.path.."/"..file
|
||||
if self.show_filesize then
|
||||
local sstr = string.format("%4.1fM",lfs.attributes(full_path, "size")/1024/1024)
|
||||
table.insert(item_table, { text = file, mandatory = sstr, path = full_path })
|
||||
else
|
||||
table.insert(item_table, { text = file, path = full_path })
|
||||
end
|
||||
end
|
||||
|
||||
return item_table
|
||||
return item_table
|
||||
end
|
||||
|
||||
function FileChooser:changeToPath(path)
|
||||
path = util.realpath(path)
|
||||
self.path = path
|
||||
self:refreshPath()
|
||||
path = util.realpath(path)
|
||||
self.path = path
|
||||
self:refreshPath()
|
||||
end
|
||||
|
||||
function FileChooser:refreshPath()
|
||||
self:swithItemTable(nil, self:genItemTableFromPath(self.path))
|
||||
self:swithItemTable(nil, self:genItemTableFromPath(self.path))
|
||||
end
|
||||
|
||||
function FileChooser:toggleHiddenFiles()
|
||||
self.show_hidden = not self.show_hidden
|
||||
self:swithItemTable(nil, self:genItemTableFromPath(self.path))
|
||||
self.show_hidden = not self.show_hidden
|
||||
self:swithItemTable(nil, self:genItemTableFromPath(self.path))
|
||||
end
|
||||
|
||||
function FileChooser:onMenuSelect(item)
|
||||
if lfs.attributes(item.path, "mode") == "directory" then
|
||||
self:changeToPath(item.path)
|
||||
else
|
||||
self:onFileSelect(item.path)
|
||||
end
|
||||
return true
|
||||
if lfs.attributes(item.path, "mode") == "directory" then
|
||||
self:changeToPath(item.path)
|
||||
else
|
||||
self:onFileSelect(item.path)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function FileChooser:onMenuHold(item)
|
||||
self:onFileHold(item.path)
|
||||
return true
|
||||
self:onFileHold(item.path)
|
||||
return true
|
||||
end
|
||||
|
||||
function FileChooser:onFileSelect(file)
|
||||
UIManager:close(self)
|
||||
return true
|
||||
UIManager:close(self)
|
||||
return true
|
||||
end
|
||||
|
||||
function FileChooser:onFileHold(file)
|
||||
return true
|
||||
return true
|
||||
end
|
||||
|
||||
return FileChooser
|
||||
|
||||
@@ -9,21 +9,21 @@ FixedTextWidget
|
||||
local FixedTextWidget = TextWidget:new{}
|
||||
|
||||
function FixedTextWidget:getSize()
|
||||
local tsize = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, self.text, true, self.bold)
|
||||
if not tsize then
|
||||
return Geom:new{}
|
||||
end
|
||||
self._length = tsize.x
|
||||
self._height = self.face.size
|
||||
return Geom:new{
|
||||
w = self._length,
|
||||
h = self._height,
|
||||
}
|
||||
local tsize = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, self.text, true, self.bold)
|
||||
if not tsize then
|
||||
return Geom:new{}
|
||||
end
|
||||
self._length = tsize.x
|
||||
self._height = self.face.size
|
||||
return Geom:new{
|
||||
w = self._length,
|
||||
h = self._height,
|
||||
}
|
||||
end
|
||||
|
||||
function FixedTextWidget:paintTo(bb, x, y)
|
||||
RenderText:renderUtf8Text(bb, x, y+self._height, self.face, self.text, true, self.bold,
|
||||
self.bgcolor, self.fgcolor)
|
||||
RenderText:renderUtf8Text(bb, x, y+self._height, self.face, self.text, true, self.bold,
|
||||
self.bgcolor, self.fgcolor)
|
||||
end
|
||||
|
||||
return FixedTextWidget
|
||||
|
||||
@@ -8,10 +8,10 @@ Wrapper Widget that manages focus for a whole dialog
|
||||
supports a 2D model of active elements
|
||||
|
||||
e.g.:
|
||||
layout = {
|
||||
{ textinput, textinput },
|
||||
{ okbutton, cancelbutton }
|
||||
}
|
||||
layout = {
|
||||
{ textinput, textinput },
|
||||
{ okbutton, cancelbutton }
|
||||
}
|
||||
|
||||
this is a dialog with 2 rows. in the top row, there is the
|
||||
single (!) widget <textinput>. when the focus is in this
|
||||
@@ -26,76 +26,76 @@ but notice that this does _not_ do the layout for you,
|
||||
it rather defines an abstract layout.
|
||||
]]
|
||||
local FocusManager = InputContainer:new{
|
||||
selected = nil, -- defaults to x=1, y=1
|
||||
layout = nil, -- mandatory
|
||||
movement_allowed = { x = true, y = true }
|
||||
selected = nil, -- defaults to x=1, y=1
|
||||
layout = nil, -- mandatory
|
||||
movement_allowed = { x = true, y = true }
|
||||
}
|
||||
|
||||
function FocusManager:init()
|
||||
self.selected = { x = 1, y = 1 }
|
||||
self.key_events = {
|
||||
-- these will all generate the same event, just with different arguments
|
||||
FocusUp = { {"Up"}, doc = "move focus up", event = "FocusMove", args = {0, -1} },
|
||||
FocusDown = { {"Down"}, doc = "move focus down", event = "FocusMove", args = {0, 1} },
|
||||
FocusLeft = { {"Left"}, doc = "move focus left", event = "FocusMove", args = {-1, 0} },
|
||||
FocusRight = { {"Right"}, doc = "move focus right", event = "FocusMove", args = {1, 0} },
|
||||
}
|
||||
self.selected = { x = 1, y = 1 }
|
||||
self.key_events = {
|
||||
-- these will all generate the same event, just with different arguments
|
||||
FocusUp = { {"Up"}, doc = "move focus up", event = "FocusMove", args = {0, -1} },
|
||||
FocusDown = { {"Down"}, doc = "move focus down", event = "FocusMove", args = {0, 1} },
|
||||
FocusLeft = { {"Left"}, doc = "move focus left", event = "FocusMove", args = {-1, 0} },
|
||||
FocusRight = { {"Right"}, doc = "move focus right", event = "FocusMove", args = {1, 0} },
|
||||
}
|
||||
end
|
||||
|
||||
function FocusManager:onFocusMove(args)
|
||||
local dx, dy = unpack(args)
|
||||
local dx, dy = unpack(args)
|
||||
|
||||
if (dx ~= 0 and not self.movement_allowed.x)
|
||||
or (dy ~= 0 and not self.movement_allowed.y) then
|
||||
return true
|
||||
end
|
||||
if (dx ~= 0 and not self.movement_allowed.x)
|
||||
or (dy ~= 0 and not self.movement_allowed.y) then
|
||||
return true
|
||||
end
|
||||
|
||||
if not self.layout or not self.layout[self.selected.y] or not self.layout[self.selected.y][self.selected.x] then
|
||||
return true
|
||||
end
|
||||
local current_item = self.layout[self.selected.y][self.selected.x]
|
||||
while true do
|
||||
if self.selected.x + dx > #self.layout[self.selected.y]
|
||||
or self.selected.x + dx < 1 then
|
||||
break -- abort when we run into horizontal borders
|
||||
end
|
||||
if not self.layout or not self.layout[self.selected.y] or not self.layout[self.selected.y][self.selected.x] then
|
||||
return true
|
||||
end
|
||||
local current_item = self.layout[self.selected.y][self.selected.x]
|
||||
while true do
|
||||
if self.selected.x + dx > #self.layout[self.selected.y]
|
||||
or self.selected.x + dx < 1 then
|
||||
break -- abort when we run into horizontal borders
|
||||
end
|
||||
|
||||
-- move cyclic in vertical direction
|
||||
if self.selected.y + dy > #self.layout then
|
||||
if not self:onWrapLast() then
|
||||
break
|
||||
end
|
||||
elseif self.selected.y + dy < 1 then
|
||||
if not self:onWrapFirst() then
|
||||
break
|
||||
end
|
||||
else
|
||||
self.selected.y = self.selected.y + dy
|
||||
end
|
||||
self.selected.x = self.selected.x + dx
|
||||
-- move cyclic in vertical direction
|
||||
if self.selected.y + dy > #self.layout then
|
||||
if not self:onWrapLast() then
|
||||
break
|
||||
end
|
||||
elseif self.selected.y + dy < 1 then
|
||||
if not self:onWrapFirst() then
|
||||
break
|
||||
end
|
||||
else
|
||||
self.selected.y = self.selected.y + dy
|
||||
end
|
||||
self.selected.x = self.selected.x + dx
|
||||
|
||||
if self.layout[self.selected.y][self.selected.x] ~= current_item
|
||||
or not self.layout[self.selected.y][self.selected.x].is_inactive then
|
||||
-- we found a different object to focus
|
||||
current_item:handleEvent(Event:new("Unfocus"))
|
||||
self.layout[self.selected.y][self.selected.x]:handleEvent(Event:new("Focus"))
|
||||
-- trigger a repaint (we need to be the registered widget!)
|
||||
UIManager:setDirty(self, "partial")
|
||||
break
|
||||
end
|
||||
end
|
||||
if self.layout[self.selected.y][self.selected.x] ~= current_item
|
||||
or not self.layout[self.selected.y][self.selected.x].is_inactive then
|
||||
-- we found a different object to focus
|
||||
current_item:handleEvent(Event:new("Unfocus"))
|
||||
self.layout[self.selected.y][self.selected.x]:handleEvent(Event:new("Focus"))
|
||||
-- trigger a repaint (we need to be the registered widget!)
|
||||
UIManager:setDirty(self, "partial")
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
return true
|
||||
end
|
||||
|
||||
function FocusManager:onWrapFirst()
|
||||
self.selected.y = #self.layout
|
||||
return true
|
||||
self.selected.y = #self.layout
|
||||
return true
|
||||
end
|
||||
|
||||
function FocusManager:onWrapLast()
|
||||
self.selected.y = 1
|
||||
return true
|
||||
self.selected.y = 1
|
||||
return true
|
||||
end
|
||||
|
||||
return FocusManager
|
||||
|
||||
@@ -4,58 +4,58 @@ local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
A Layout widget that puts objects besides each others
|
||||
--]]
|
||||
local HorizontalGroup = WidgetContainer:new{
|
||||
align = "center",
|
||||
_size = nil,
|
||||
align = "center",
|
||||
_size = nil,
|
||||
}
|
||||
|
||||
function HorizontalGroup:getSize()
|
||||
if not self._size then
|
||||
self._size = { w = 0, h = 0 }
|
||||
self._offsets = { }
|
||||
for i, widget in ipairs(self) do
|
||||
local w_size = widget:getSize()
|
||||
self._offsets[i] = {
|
||||
x = self._size.w,
|
||||
y = w_size.h
|
||||
}
|
||||
self._size.w = self._size.w + w_size.w
|
||||
if w_size.h > self._size.h then
|
||||
self._size.h = w_size.h
|
||||
end
|
||||
end
|
||||
end
|
||||
return self._size
|
||||
if not self._size then
|
||||
self._size = { w = 0, h = 0 }
|
||||
self._offsets = { }
|
||||
for i, widget in ipairs(self) do
|
||||
local w_size = widget:getSize()
|
||||
self._offsets[i] = {
|
||||
x = self._size.w,
|
||||
y = w_size.h
|
||||
}
|
||||
self._size.w = self._size.w + w_size.w
|
||||
if w_size.h > self._size.h then
|
||||
self._size.h = w_size.h
|
||||
end
|
||||
end
|
||||
end
|
||||
return self._size
|
||||
end
|
||||
|
||||
function HorizontalGroup:paintTo(bb, x, y)
|
||||
local size = self:getSize()
|
||||
local size = self:getSize()
|
||||
|
||||
for i, widget in ipairs(self) do
|
||||
if self.align == "center" then
|
||||
widget:paintTo(bb,
|
||||
x + self._offsets[i].x,
|
||||
y + math.floor((size.h - self._offsets[i].y) / 2))
|
||||
elseif self.align == "top" then
|
||||
widget:paintTo(bb, x + self._offsets[i].x, y)
|
||||
elseif self.align == "bottom" then
|
||||
widget:paintTo(bb, x + self._offsets[i].x, y + size.h - self._offsets[i].y)
|
||||
end
|
||||
end
|
||||
for i, widget in ipairs(self) do
|
||||
if self.align == "center" then
|
||||
widget:paintTo(bb,
|
||||
x + self._offsets[i].x,
|
||||
y + math.floor((size.h - self._offsets[i].y) / 2))
|
||||
elseif self.align == "top" then
|
||||
widget:paintTo(bb, x + self._offsets[i].x, y)
|
||||
elseif self.align == "bottom" then
|
||||
widget:paintTo(bb, x + self._offsets[i].x, y + size.h - self._offsets[i].y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function HorizontalGroup:clear()
|
||||
self:free()
|
||||
WidgetContainer.clear(self)
|
||||
self:free()
|
||||
WidgetContainer.clear(self)
|
||||
end
|
||||
|
||||
function HorizontalGroup:resetLayout()
|
||||
self._size = nil
|
||||
self._offsets = {}
|
||||
self._size = nil
|
||||
self._offsets = {}
|
||||
end
|
||||
|
||||
function HorizontalGroup:free()
|
||||
self:resetLayout()
|
||||
WidgetContainer.free(self)
|
||||
self:resetLayout()
|
||||
WidgetContainer.free(self)
|
||||
end
|
||||
|
||||
return HorizontalGroup
|
||||
|
||||
@@ -4,11 +4,11 @@ local Widget = require("ui/widget/widget")
|
||||
Dummy Widget that reserves horizontal space
|
||||
--]]
|
||||
local HorizontalSpan = Widget:new{
|
||||
width = 0,
|
||||
width = 0,
|
||||
}
|
||||
|
||||
function HorizontalSpan:getSize()
|
||||
return {w = self.width, h = 0}
|
||||
return {w = self.width, h = 0}
|
||||
end
|
||||
|
||||
return HorizontalSpan
|
||||
|
||||
@@ -7,51 +7,51 @@ local UIManager = require("ui/uimanager")
|
||||
Button with a big icon image! Designed for touch device
|
||||
--]]
|
||||
local IconButton = InputContainer:new{
|
||||
icon_file = "resources/info-confirm.png",
|
||||
dimen = nil,
|
||||
-- show_parent is used for UIManager:setDirty, so we can trigger repaint
|
||||
show_parent = nil,
|
||||
callback = function() end,
|
||||
icon_file = "resources/info-confirm.png",
|
||||
dimen = nil,
|
||||
-- show_parent is used for UIManager:setDirty, so we can trigger repaint
|
||||
show_parent = nil,
|
||||
callback = function() end,
|
||||
}
|
||||
|
||||
function IconButton:init()
|
||||
self.image = ImageWidget:new{
|
||||
file = self.icon_file
|
||||
}
|
||||
self.image = ImageWidget:new{
|
||||
file = self.icon_file
|
||||
}
|
||||
|
||||
self.show_parent = self.show_parent or self
|
||||
self.dimen = self.image:getSize()
|
||||
self.show_parent = self.show_parent or self
|
||||
self.dimen = self.image:getSize()
|
||||
|
||||
self:initGesListener()
|
||||
self:initGesListener()
|
||||
|
||||
self[1] = self.image
|
||||
self[1] = self.image
|
||||
end
|
||||
|
||||
function IconButton:initGesListener()
|
||||
self.ges_events = {
|
||||
TapClickButton = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
}
|
||||
},
|
||||
}
|
||||
self.ges_events = {
|
||||
TapClickButton = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
function IconButton:onTapClickButton()
|
||||
self.image.invert = true
|
||||
UIManager:setDirty(self.show_parent, "partial")
|
||||
-- make sure button reacts before doing callback
|
||||
UIManager:scheduleIn(0.1, function()
|
||||
self.callback()
|
||||
self.image.invert = false
|
||||
UIManager:setDirty(self.show_parent, "partial")
|
||||
end)
|
||||
return true
|
||||
self.image.invert = true
|
||||
UIManager:setDirty(self.show_parent, "partial")
|
||||
-- make sure button reacts before doing callback
|
||||
UIManager:scheduleIn(0.1, function()
|
||||
self.callback()
|
||||
self.image.invert = false
|
||||
UIManager:setDirty(self.show_parent, "partial")
|
||||
end)
|
||||
return true
|
||||
end
|
||||
|
||||
function IconButton:onSetDimensions(new_dimen)
|
||||
self.dimen = new_dimen
|
||||
self.dimen = new_dimen
|
||||
end
|
||||
|
||||
return IconButton
|
||||
|
||||
@@ -6,51 +6,51 @@ local Geom = require("ui/geometry")
|
||||
ImageWidget shows an image from a file
|
||||
--]]
|
||||
local ImageWidget = Widget:new{
|
||||
file = nil,
|
||||
invert = nil,
|
||||
dim = nil,
|
||||
hide = nil,
|
||||
_bb = nil
|
||||
file = nil,
|
||||
invert = nil,
|
||||
dim = nil,
|
||||
hide = nil,
|
||||
_bb = nil
|
||||
}
|
||||
|
||||
function ImageWidget:_render()
|
||||
local itype = string.lower(string.match(self.file, ".+%.([^.]+)") or "")
|
||||
if itype == "jpeg" or itype == "jpg" then
|
||||
self._bb = Image:fromJPEG(self.file)
|
||||
elseif itype == "png" then
|
||||
self._bb = Image:fromPNG(self.file)
|
||||
end
|
||||
local itype = string.lower(string.match(self.file, ".+%.([^.]+)") or "")
|
||||
if itype == "jpeg" or itype == "jpg" then
|
||||
self._bb = Image:fromJPEG(self.file)
|
||||
elseif itype == "png" then
|
||||
self._bb = Image:fromPNG(self.file)
|
||||
end
|
||||
end
|
||||
|
||||
function ImageWidget:getSize()
|
||||
if not self._bb then
|
||||
self:_render()
|
||||
end
|
||||
return Geom:new{ w = self._bb:getWidth(), h = self._bb:getHeight() }
|
||||
if not self._bb then
|
||||
self:_render()
|
||||
end
|
||||
return Geom:new{ w = self._bb:getWidth(), h = self._bb:getHeight() }
|
||||
end
|
||||
|
||||
function ImageWidget:paintTo(bb, x, y)
|
||||
local size = self:getSize()
|
||||
self.dimen = Geom:new{
|
||||
x = x, y = y,
|
||||
w = size.w,
|
||||
h = size.h
|
||||
}
|
||||
if self.hide then return end
|
||||
bb:blitFrom(self._bb, x, y, 0, 0, size.w, size.h)
|
||||
if self.invert then
|
||||
bb:invertRect(x, y, size.w, size.h)
|
||||
end
|
||||
if self.dim then
|
||||
bb:dimRect(x, y, size.w, size.h)
|
||||
end
|
||||
local size = self:getSize()
|
||||
self.dimen = Geom:new{
|
||||
x = x, y = y,
|
||||
w = size.w,
|
||||
h = size.h
|
||||
}
|
||||
if self.hide then return end
|
||||
bb:blitFrom(self._bb, x, y, 0, 0, size.w, size.h)
|
||||
if self.invert then
|
||||
bb:invertRect(x, y, size.w, size.h)
|
||||
end
|
||||
if self.dim then
|
||||
bb:dimRect(x, y, size.w, size.h)
|
||||
end
|
||||
end
|
||||
|
||||
function ImageWidget:free()
|
||||
if self._bb then
|
||||
self._bb:free()
|
||||
self._bb = nil
|
||||
end
|
||||
if self._bb then
|
||||
self._bb:free()
|
||||
self._bb = nil
|
||||
end
|
||||
end
|
||||
|
||||
return ImageWidget
|
||||
|
||||
@@ -20,68 +20,68 @@ Widget that displays an informational message
|
||||
it vanishes on key press or after a given timeout
|
||||
]]
|
||||
local InfoMessage = InputContainer:new{
|
||||
face = Font:getFace("infofont", 25),
|
||||
text = "",
|
||||
timeout = nil, -- in seconds
|
||||
face = Font:getFace("infofont", 25),
|
||||
text = "",
|
||||
timeout = nil, -- in seconds
|
||||
}
|
||||
|
||||
function InfoMessage:init()
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
AnyKeyPressed = { { Input.group.Any },
|
||||
seqtext = "any key", doc = _("close dialog") }
|
||||
}
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events.TapClose = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
-- we construct the actual content here because self.text is only available now
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
FrameContainer:new{
|
||||
margin = 2,
|
||||
background = 0,
|
||||
HorizontalGroup:new{
|
||||
align = "center",
|
||||
ImageWidget:new{
|
||||
file = "resources/info-i.png"
|
||||
},
|
||||
HorizontalSpan:new{ width = 10 },
|
||||
TextBoxWidget:new{
|
||||
text = self.text,
|
||||
face = self.face
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
AnyKeyPressed = { { Input.group.Any },
|
||||
seqtext = "any key", doc = _("close dialog") }
|
||||
}
|
||||
end
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events.TapClose = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
-- we construct the actual content here because self.text is only available now
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
FrameContainer:new{
|
||||
margin = 2,
|
||||
background = 0,
|
||||
HorizontalGroup:new{
|
||||
align = "center",
|
||||
ImageWidget:new{
|
||||
file = "resources/info-i.png"
|
||||
},
|
||||
HorizontalSpan:new{ width = 10 },
|
||||
TextBoxWidget:new{
|
||||
text = self.text,
|
||||
face = self.face
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function InfoMessage:onShow()
|
||||
-- triggered by the UIManager after we got successfully shown (not yet painted)
|
||||
if self.timeout then
|
||||
UIManager:scheduleIn(self.timeout, function() UIManager:close(self) end)
|
||||
end
|
||||
return true
|
||||
-- triggered by the UIManager after we got successfully shown (not yet painted)
|
||||
if self.timeout then
|
||||
UIManager:scheduleIn(self.timeout, function() UIManager:close(self) end)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function InfoMessage:onAnyKeyPressed()
|
||||
-- triggered by our defined key events
|
||||
UIManager:close(self)
|
||||
return true
|
||||
-- triggered by our defined key events
|
||||
UIManager:close(self)
|
||||
return true
|
||||
end
|
||||
|
||||
function InfoMessage:onTapClose()
|
||||
UIManager:close(self)
|
||||
return true
|
||||
UIManager:close(self)
|
||||
return true
|
||||
end
|
||||
|
||||
return InfoMessage
|
||||
|
||||
@@ -12,112 +12,112 @@ local UIManager = require("ui/uimanager")
|
||||
local Screen = require("ui/screen")
|
||||
|
||||
local InputDialog = InputContainer:new{
|
||||
title = "",
|
||||
input = "",
|
||||
input_hint = "",
|
||||
buttons = nil,
|
||||
input_type = nil,
|
||||
enter_callback = nil,
|
||||
|
||||
width = nil,
|
||||
height = nil,
|
||||
|
||||
title_face = Font:getFace("tfont", 22),
|
||||
input_face = Font:getFace("cfont", 20),
|
||||
|
||||
title_padding = Screen:scaleByDPI(5),
|
||||
title_margin = Screen:scaleByDPI(2),
|
||||
input_padding = Screen:scaleByDPI(10),
|
||||
input_margin = Screen:scaleByDPI(10),
|
||||
button_padding = Screen:scaleByDPI(14),
|
||||
title = "",
|
||||
input = "",
|
||||
input_hint = "",
|
||||
buttons = nil,
|
||||
input_type = nil,
|
||||
enter_callback = nil,
|
||||
|
||||
width = nil,
|
||||
height = nil,
|
||||
|
||||
title_face = Font:getFace("tfont", 22),
|
||||
input_face = Font:getFace("cfont", 20),
|
||||
|
||||
title_padding = Screen:scaleByDPI(5),
|
||||
title_margin = Screen:scaleByDPI(2),
|
||||
input_padding = Screen:scaleByDPI(10),
|
||||
input_margin = Screen:scaleByDPI(10),
|
||||
button_padding = Screen:scaleByDPI(14),
|
||||
}
|
||||
|
||||
function InputDialog:init()
|
||||
self.title = FrameContainer:new{
|
||||
padding = self.title_padding,
|
||||
margin = self.title_margin,
|
||||
bordersize = 0,
|
||||
TextWidget:new{
|
||||
text = self.title,
|
||||
face = self.title_face,
|
||||
width = self.width,
|
||||
}
|
||||
}
|
||||
self.input = InputText:new{
|
||||
text = self.input,
|
||||
hint = self.input_hint,
|
||||
face = self.input_face,
|
||||
width = self.width * 0.9,
|
||||
input_type = self.input_type,
|
||||
enter_callback = self.enter_callback,
|
||||
scroll = false,
|
||||
parent = self,
|
||||
}
|
||||
local button_table = ButtonTable:new{
|
||||
width = self.width,
|
||||
button_font_face = "cfont",
|
||||
button_font_size = 20,
|
||||
buttons = self.buttons,
|
||||
zero_sep = true,
|
||||
}
|
||||
local title_bar = LineWidget:new{
|
||||
--background = 8,
|
||||
dimen = Geom:new{
|
||||
w = button_table:getSize().w + self.button_padding,
|
||||
h = Screen:scaleByDPI(2),
|
||||
}
|
||||
}
|
||||
|
||||
self.dialog_frame = FrameContainer:new{
|
||||
radius = 8,
|
||||
bordersize = 3,
|
||||
padding = 0,
|
||||
margin = 0,
|
||||
background = 0,
|
||||
VerticalGroup:new{
|
||||
align = "left",
|
||||
self.title,
|
||||
title_bar,
|
||||
-- input
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = title_bar:getSize().w,
|
||||
h = self.input:getSize().h,
|
||||
},
|
||||
self.input,
|
||||
},
|
||||
-- buttons
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = title_bar:getSize().w,
|
||||
h = button_table:getSize().h,
|
||||
},
|
||||
button_table,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight() - self.input:getKeyboardDimen().h,
|
||||
},
|
||||
self.dialog_frame,
|
||||
}
|
||||
UIManager.repaint_all = true
|
||||
UIManager.full_refresh = true
|
||||
self.title = FrameContainer:new{
|
||||
padding = self.title_padding,
|
||||
margin = self.title_margin,
|
||||
bordersize = 0,
|
||||
TextWidget:new{
|
||||
text = self.title,
|
||||
face = self.title_face,
|
||||
width = self.width,
|
||||
}
|
||||
}
|
||||
self.input = InputText:new{
|
||||
text = self.input,
|
||||
hint = self.input_hint,
|
||||
face = self.input_face,
|
||||
width = self.width * 0.9,
|
||||
input_type = self.input_type,
|
||||
enter_callback = self.enter_callback,
|
||||
scroll = false,
|
||||
parent = self,
|
||||
}
|
||||
local button_table = ButtonTable:new{
|
||||
width = self.width,
|
||||
button_font_face = "cfont",
|
||||
button_font_size = 20,
|
||||
buttons = self.buttons,
|
||||
zero_sep = true,
|
||||
}
|
||||
local title_bar = LineWidget:new{
|
||||
--background = 8,
|
||||
dimen = Geom:new{
|
||||
w = button_table:getSize().w + self.button_padding,
|
||||
h = Screen:scaleByDPI(2),
|
||||
}
|
||||
}
|
||||
|
||||
self.dialog_frame = FrameContainer:new{
|
||||
radius = 8,
|
||||
bordersize = 3,
|
||||
padding = 0,
|
||||
margin = 0,
|
||||
background = 0,
|
||||
VerticalGroup:new{
|
||||
align = "left",
|
||||
self.title,
|
||||
title_bar,
|
||||
-- input
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = title_bar:getSize().w,
|
||||
h = self.input:getSize().h,
|
||||
},
|
||||
self.input,
|
||||
},
|
||||
-- buttons
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = title_bar:getSize().w,
|
||||
h = button_table:getSize().h,
|
||||
},
|
||||
button_table,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight() - self.input:getKeyboardDimen().h,
|
||||
},
|
||||
self.dialog_frame,
|
||||
}
|
||||
UIManager.repaint_all = true
|
||||
UIManager.full_refresh = true
|
||||
end
|
||||
|
||||
function InputDialog:onShowKeyboard()
|
||||
self.input:onShowKeyboard()
|
||||
self.input:onShowKeyboard()
|
||||
end
|
||||
|
||||
function InputDialog:getInputText()
|
||||
return self.input:getText()
|
||||
return self.input:getText()
|
||||
end
|
||||
|
||||
function InputDialog:onClose()
|
||||
self.input:onCloseKeyboard()
|
||||
self.input:onCloseKeyboard()
|
||||
end
|
||||
|
||||
return InputDialog
|
||||
|
||||
@@ -8,149 +8,149 @@ local Screen = require("ui/screen")
|
||||
local UIManager = require("ui/uimanager")
|
||||
|
||||
local InputText = InputContainer:new{
|
||||
text = "",
|
||||
hint = "demo hint",
|
||||
charlist = {}, -- table to store input string
|
||||
charpos = 1,
|
||||
input_type = nil,
|
||||
|
||||
width = nil,
|
||||
height = nil,
|
||||
face = Font:getFace("cfont", 22),
|
||||
|
||||
padding = 5,
|
||||
margin = 5,
|
||||
bordersize = 2,
|
||||
|
||||
parent = nil, -- parent dialog that will be set dirty
|
||||
scroll = false,
|
||||
text = "",
|
||||
hint = "demo hint",
|
||||
charlist = {}, -- table to store input string
|
||||
charpos = 1,
|
||||
input_type = nil,
|
||||
|
||||
width = nil,
|
||||
height = nil,
|
||||
face = Font:getFace("cfont", 22),
|
||||
|
||||
padding = 5,
|
||||
margin = 5,
|
||||
bordersize = 2,
|
||||
|
||||
parent = nil, -- parent dialog that will be set dirty
|
||||
scroll = false,
|
||||
}
|
||||
|
||||
function InputText:init()
|
||||
self:StringToCharlist(self.text)
|
||||
self:initTextBox()
|
||||
self:initKeyboard()
|
||||
self:StringToCharlist(self.text)
|
||||
self:initTextBox()
|
||||
self:initKeyboard()
|
||||
end
|
||||
|
||||
function InputText:initTextBox()
|
||||
local bgcolor = nil
|
||||
local fgcolor = nil
|
||||
if self.text == "" then
|
||||
self.text = self.hint
|
||||
bgcolor = 0.0
|
||||
fgcolor = 0.5
|
||||
else
|
||||
bgcolor = 0.0
|
||||
fgcolor = 1.0
|
||||
end
|
||||
local text_widget = nil
|
||||
if self.scroll then
|
||||
text_widget = ScrollTextWidget:new{
|
||||
text = self.text,
|
||||
face = self.face,
|
||||
bgcolor = bgcolor,
|
||||
fgcolor = fgcolor,
|
||||
width = self.width,
|
||||
height = self.height,
|
||||
}
|
||||
else
|
||||
text_widget = TextBoxWidget:new{
|
||||
text = self.text,
|
||||
face = self.face,
|
||||
bgcolor = bgcolor,
|
||||
fgcolor = fgcolor,
|
||||
width = self.width,
|
||||
height = self.height,
|
||||
}
|
||||
end
|
||||
self[1] = FrameContainer:new{
|
||||
bordersize = self.bordersize,
|
||||
padding = self.padding,
|
||||
margin = self.margin,
|
||||
text_widget,
|
||||
}
|
||||
self.dimen = self[1]:getSize()
|
||||
local bgcolor = nil
|
||||
local fgcolor = nil
|
||||
if self.text == "" then
|
||||
self.text = self.hint
|
||||
bgcolor = 0.0
|
||||
fgcolor = 0.5
|
||||
else
|
||||
bgcolor = 0.0
|
||||
fgcolor = 1.0
|
||||
end
|
||||
local text_widget = nil
|
||||
if self.scroll then
|
||||
text_widget = ScrollTextWidget:new{
|
||||
text = self.text,
|
||||
face = self.face,
|
||||
bgcolor = bgcolor,
|
||||
fgcolor = fgcolor,
|
||||
width = self.width,
|
||||
height = self.height,
|
||||
}
|
||||
else
|
||||
text_widget = TextBoxWidget:new{
|
||||
text = self.text,
|
||||
face = self.face,
|
||||
bgcolor = bgcolor,
|
||||
fgcolor = fgcolor,
|
||||
width = self.width,
|
||||
height = self.height,
|
||||
}
|
||||
end
|
||||
self[1] = FrameContainer:new{
|
||||
bordersize = self.bordersize,
|
||||
padding = self.padding,
|
||||
margin = self.margin,
|
||||
text_widget,
|
||||
}
|
||||
self.dimen = self[1]:getSize()
|
||||
end
|
||||
|
||||
function InputText:initKeyboard()
|
||||
local keyboard_layout = 2
|
||||
if self.input_type == "number" then
|
||||
keyboard_layout = 3
|
||||
end
|
||||
self.keyboard = VirtualKeyboard:new{
|
||||
layout = keyboard_layout,
|
||||
inputbox = self,
|
||||
width = Screen:getWidth(),
|
||||
height = math.max(Screen:getWidth(), Screen:getHeight())*0.33,
|
||||
}
|
||||
local keyboard_layout = 2
|
||||
if self.input_type == "number" then
|
||||
keyboard_layout = 3
|
||||
end
|
||||
self.keyboard = VirtualKeyboard:new{
|
||||
layout = keyboard_layout,
|
||||
inputbox = self,
|
||||
width = Screen:getWidth(),
|
||||
height = math.max(Screen:getWidth(), Screen:getHeight())*0.33,
|
||||
}
|
||||
end
|
||||
|
||||
function InputText:onShowKeyboard()
|
||||
UIManager:show(self.keyboard)
|
||||
UIManager:show(self.keyboard)
|
||||
end
|
||||
|
||||
function InputText:onCloseKeyboard()
|
||||
UIManager:close(self.keyboard)
|
||||
UIManager:close(self.keyboard)
|
||||
end
|
||||
|
||||
function InputText:getKeyboardDimen()
|
||||
return self.keyboard.dimen
|
||||
return self.keyboard.dimen
|
||||
end
|
||||
|
||||
function InputText:addChar(char)
|
||||
if self.enter_callback and char == '\n' then
|
||||
UIManager:scheduleIn(0.3, function() self.enter_callback() end)
|
||||
return
|
||||
end
|
||||
table.insert(self.charlist, self.charpos, char)
|
||||
self.charpos = self.charpos + 1
|
||||
self.text = self:CharlistToString()
|
||||
self:initTextBox()
|
||||
UIManager:setDirty(self.parent, "partial")
|
||||
if self.enter_callback and char == '\n' then
|
||||
UIManager:scheduleIn(0.3, function() self.enter_callback() end)
|
||||
return
|
||||
end
|
||||
table.insert(self.charlist, self.charpos, char)
|
||||
self.charpos = self.charpos + 1
|
||||
self.text = self:CharlistToString()
|
||||
self:initTextBox()
|
||||
UIManager:setDirty(self.parent, "partial")
|
||||
end
|
||||
|
||||
function InputText:delChar()
|
||||
if self.charpos == 1 then return end
|
||||
self.charpos = self.charpos - 1
|
||||
table.remove(self.charlist, self.charpos)
|
||||
self.text = self:CharlistToString()
|
||||
self:initTextBox()
|
||||
UIManager:setDirty(self.parent, "partial")
|
||||
if self.charpos == 1 then return end
|
||||
self.charpos = self.charpos - 1
|
||||
table.remove(self.charlist, self.charpos)
|
||||
self.text = self:CharlistToString()
|
||||
self:initTextBox()
|
||||
UIManager:setDirty(self.parent, "partial")
|
||||
end
|
||||
|
||||
function InputText:getText()
|
||||
return self.text
|
||||
return self.text
|
||||
end
|
||||
|
||||
function InputText:setText(text)
|
||||
self:StringToCharlist(text)
|
||||
self:initTextBox()
|
||||
UIManager:setDirty(self.parent, "partial")
|
||||
self:StringToCharlist(text)
|
||||
self:initTextBox()
|
||||
UIManager:setDirty(self.parent, "partial")
|
||||
end
|
||||
|
||||
function InputText:StringToCharlist(text)
|
||||
if text == nil then return end
|
||||
-- clear
|
||||
self.charlist = {}
|
||||
self.charpos = 1
|
||||
local prevcharcode, charcode = 0
|
||||
for uchar in string.gfind(text, "([%z\1-\127\194-\244][\128-\191]*)") do
|
||||
charcode = util.utf8charcode(uchar)
|
||||
if prevcharcode then -- utf8
|
||||
self.charlist[#self.charlist+1] = uchar
|
||||
end
|
||||
prevcharcode = charcode
|
||||
end
|
||||
self.text = self:CharlistToString()
|
||||
self.charpos = #self.charlist+1
|
||||
if text == nil then return end
|
||||
-- clear
|
||||
self.charlist = {}
|
||||
self.charpos = 1
|
||||
local prevcharcode, charcode = 0
|
||||
for uchar in string.gfind(text, "([%z\1-\127\194-\244][\128-\191]*)") do
|
||||
charcode = util.utf8charcode(uchar)
|
||||
if prevcharcode then -- utf8
|
||||
self.charlist[#self.charlist+1] = uchar
|
||||
end
|
||||
prevcharcode = charcode
|
||||
end
|
||||
self.text = self:CharlistToString()
|
||||
self.charpos = #self.charlist+1
|
||||
end
|
||||
|
||||
function InputText:CharlistToString()
|
||||
local s, i = ""
|
||||
for i=1, #self.charlist do
|
||||
s = s .. self.charlist[i]
|
||||
end
|
||||
return s
|
||||
local s, i = ""
|
||||
for i=1, #self.charlist do
|
||||
s = s .. self.charlist[i]
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
return InputText
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
local Widget = require("ui/widget/widget")
|
||||
|
||||
local LineWidget = Widget:new{
|
||||
style = "solid",
|
||||
background = 15,
|
||||
dimen = nil,
|
||||
--@TODO replay dirty hack here 13.03 2013 (houqp)
|
||||
empty_segments = nil,
|
||||
style = "solid",
|
||||
background = 15,
|
||||
dimen = nil,
|
||||
--@TODO replay dirty hack here 13.03 2013 (houqp)
|
||||
empty_segments = nil,
|
||||
}
|
||||
|
||||
function LineWidget:paintTo(bb, x, y)
|
||||
if self.style == "dashed" then
|
||||
for i = 0, self.dimen.w - 20, 20 do
|
||||
bb:paintRect(x + i, y,
|
||||
16, self.dimen.h, self.background)
|
||||
end
|
||||
else
|
||||
if self.empty_segments then
|
||||
bb:paintRect(x, y,
|
||||
self.empty_segments[1].s,
|
||||
self.dimen.h,
|
||||
self.background)
|
||||
bb:paintRect(x + self.empty_segments[1].e, y,
|
||||
self.dimen.w - x - self.empty_segments[1].e,
|
||||
self.dimen.h,
|
||||
self.background)
|
||||
else
|
||||
bb:paintRect(x, y, self.dimen.w, self.dimen.h, self.background)
|
||||
end
|
||||
end
|
||||
if self.style == "dashed" then
|
||||
for i = 0, self.dimen.w - 20, 20 do
|
||||
bb:paintRect(x + i, y,
|
||||
16, self.dimen.h, self.background)
|
||||
end
|
||||
else
|
||||
if self.empty_segments then
|
||||
bb:paintRect(x, y,
|
||||
self.empty_segments[1].s,
|
||||
self.dimen.h,
|
||||
self.background)
|
||||
bb:paintRect(x + self.empty_segments[1].e, y,
|
||||
self.dimen.w - x - self.empty_segments[1].e,
|
||||
self.dimen.h,
|
||||
self.background)
|
||||
else
|
||||
bb:paintRect(x, y, self.dimen.w, self.dimen.h, self.background)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return LineWidget
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,50 +14,50 @@ local Screen = require("ui/screen")
|
||||
Widget that displays a tiny notification on top of screen
|
||||
--]]
|
||||
local Notification = InputContainer:new{
|
||||
face = Font:getFace("infofont", 20),
|
||||
text = "Null Message",
|
||||
timeout = nil,
|
||||
face = Font:getFace("infofont", 20),
|
||||
text = "Null Message",
|
||||
timeout = nil,
|
||||
}
|
||||
|
||||
function Notification:init()
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
AnyKeyPressed = { { Input.group.Any }, seqtext = "any key", doc = "close dialog" }
|
||||
}
|
||||
end
|
||||
-- we construct the actual content here because self.text is only available now
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight()/10,
|
||||
},
|
||||
ignore = "height",
|
||||
FrameContainer:new{
|
||||
background = 0,
|
||||
radius = 0,
|
||||
HorizontalGroup:new{
|
||||
align = "center",
|
||||
TextBoxWidget:new{
|
||||
text = self.text,
|
||||
face = self.face,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
AnyKeyPressed = { { Input.group.Any }, seqtext = "any key", doc = "close dialog" }
|
||||
}
|
||||
end
|
||||
-- we construct the actual content here because self.text is only available now
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight()/10,
|
||||
},
|
||||
ignore = "height",
|
||||
FrameContainer:new{
|
||||
background = 0,
|
||||
radius = 0,
|
||||
HorizontalGroup:new{
|
||||
align = "center",
|
||||
TextBoxWidget:new{
|
||||
text = self.text,
|
||||
face = self.face,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function Notification:onShow()
|
||||
-- triggered by the UIManager after we got successfully shown (not yet painted)
|
||||
if self.timeout then
|
||||
UIManager:scheduleIn(self.timeout, function() UIManager:close(self) end)
|
||||
end
|
||||
return true
|
||||
-- triggered by the UIManager after we got successfully shown (not yet painted)
|
||||
if self.timeout then
|
||||
UIManager:scheduleIn(self.timeout, function() UIManager:close(self) end)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function Notification:onAnyKeyPressed()
|
||||
-- triggered by our defined key events
|
||||
UIManager:close(self)
|
||||
return true
|
||||
-- triggered by our defined key events
|
||||
UIManager:close(self)
|
||||
return true
|
||||
end
|
||||
|
||||
return Notification
|
||||
|
||||
@@ -4,48 +4,48 @@ local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
A Layout widget that puts objects above each other
|
||||
--]]
|
||||
local OverlapGroup = WidgetContainer:new{
|
||||
_size = nil,
|
||||
_size = nil,
|
||||
}
|
||||
|
||||
function OverlapGroup:getSize()
|
||||
if not self._size then
|
||||
self._size = {w = 0, h = 0}
|
||||
self._offsets = { x = math.huge, y = math.huge }
|
||||
for i, widget in ipairs(self) do
|
||||
local w_size = widget:getSize()
|
||||
if self._size.h < w_size.h then
|
||||
self._size.h = w_size.h
|
||||
end
|
||||
if self._size.w < w_size.w then
|
||||
self._size.w = w_size.w
|
||||
end
|
||||
end
|
||||
end
|
||||
if not self._size then
|
||||
self._size = {w = 0, h = 0}
|
||||
self._offsets = { x = math.huge, y = math.huge }
|
||||
for i, widget in ipairs(self) do
|
||||
local w_size = widget:getSize()
|
||||
if self._size.h < w_size.h then
|
||||
self._size.h = w_size.h
|
||||
end
|
||||
if self._size.w < w_size.w then
|
||||
self._size.w = w_size.w
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.dimen.w then
|
||||
self._size.w = self.dimen.w
|
||||
end
|
||||
if self.dimen.h then
|
||||
self._size.h = self.dimen.h
|
||||
end
|
||||
if self.dimen.w then
|
||||
self._size.w = self.dimen.w
|
||||
end
|
||||
if self.dimen.h then
|
||||
self._size.h = self.dimen.h
|
||||
end
|
||||
|
||||
return self._size
|
||||
return self._size
|
||||
end
|
||||
|
||||
function OverlapGroup:paintTo(bb, x, y)
|
||||
local size = self:getSize()
|
||||
local size = self:getSize()
|
||||
|
||||
for i, wget in ipairs(self) do
|
||||
local wget_size = wget:getSize()
|
||||
if wget.align == "right" then
|
||||
wget:paintTo(bb, x+size.w-wget_size.w, y)
|
||||
elseif wget.align == "center" then
|
||||
wget:paintTo(bb, x+math.floor((size.w-wget_size.w)/2), y)
|
||||
else
|
||||
-- default to left
|
||||
wget:paintTo(bb, x, y)
|
||||
end
|
||||
end
|
||||
for i, wget in ipairs(self) do
|
||||
local wget_size = wget:getSize()
|
||||
if wget.align == "right" then
|
||||
wget:paintTo(bb, x+size.w-wget_size.w, y)
|
||||
elseif wget.align == "center" then
|
||||
wget:paintTo(bb, x+math.floor((size.w-wget_size.w)/2), y)
|
||||
else
|
||||
-- default to left
|
||||
wget:paintTo(bb, x, y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return OverlapGroup
|
||||
|
||||
@@ -5,39 +5,39 @@ local Geom = require("ui/geometry")
|
||||
ProgressWidget shows a progress bar
|
||||
--]]
|
||||
local ProgressWidget = Widget:new{
|
||||
width = nil,
|
||||
height = nil,
|
||||
margin_h = 3,
|
||||
margin_v = 1,
|
||||
radius = 2,
|
||||
bordersize = 1,
|
||||
bordercolor = 15,
|
||||
bgcolor = 0,
|
||||
rectcolor = 10,
|
||||
percentage = nil,
|
||||
width = nil,
|
||||
height = nil,
|
||||
margin_h = 3,
|
||||
margin_v = 1,
|
||||
radius = 2,
|
||||
bordersize = 1,
|
||||
bordercolor = 15,
|
||||
bgcolor = 0,
|
||||
rectcolor = 10,
|
||||
percentage = nil,
|
||||
}
|
||||
|
||||
function ProgressWidget:getSize()
|
||||
return { w = self.width, h = self.height }
|
||||
return { w = self.width, h = self.height }
|
||||
end
|
||||
|
||||
function ProgressWidget:paintTo(bb, x, y)
|
||||
local my_size = self:getSize()
|
||||
self.dimen = Geom:new{
|
||||
x = x, y = y,
|
||||
w = my_size.w,
|
||||
h = my_size.h
|
||||
}
|
||||
bb:paintRoundedRect(x, y, my_size.w, my_size.h, self.bgcolor, self.radius)
|
||||
bb:paintBorder(x, y, my_size.w, my_size.h,
|
||||
self.bordersize, self.bordercolor, self.radius)
|
||||
bb:paintRect(x+self.margin_h, y+self.margin_v+self.bordersize,
|
||||
(my_size.w-2*self.margin_h)*self.percentage,
|
||||
(my_size.h-2*(self.margin_v+self.bordersize)), self.rectcolor)
|
||||
local my_size = self:getSize()
|
||||
self.dimen = Geom:new{
|
||||
x = x, y = y,
|
||||
w = my_size.w,
|
||||
h = my_size.h
|
||||
}
|
||||
bb:paintRoundedRect(x, y, my_size.w, my_size.h, self.bgcolor, self.radius)
|
||||
bb:paintBorder(x, y, my_size.w, my_size.h,
|
||||
self.bordersize, self.bordercolor, self.radius)
|
||||
bb:paintRect(x+self.margin_h, y+self.margin_v+self.bordersize,
|
||||
(my_size.w-2*self.margin_h)*self.percentage,
|
||||
(my_size.h-2*(self.margin_v+self.bordersize)), self.rectcolor)
|
||||
end
|
||||
|
||||
function ProgressWidget:setPercentage(percentage)
|
||||
self.percentage = percentage
|
||||
self.percentage = percentage
|
||||
end
|
||||
|
||||
return ProgressWidget
|
||||
|
||||
@@ -4,12 +4,12 @@ local Widget = require("ui/widget/widget")
|
||||
Dummy Widget that reserves vertical and horizontal space
|
||||
]]
|
||||
local RectSpan = Widget:new{
|
||||
width = 0,
|
||||
hright = 0,
|
||||
width = 0,
|
||||
hright = 0,
|
||||
}
|
||||
|
||||
function RectSpan:getSize()
|
||||
return {w = self.width, h = self.height}
|
||||
return {w = self.width, h = self.height}
|
||||
end
|
||||
|
||||
return RectSpan
|
||||
|
||||
@@ -13,73 +13,73 @@ local Device = require("ui/device")
|
||||
Text widget with vertical scroll bar
|
||||
--]]
|
||||
local ScrollTextWidget = InputContainer:new{
|
||||
text = nil,
|
||||
face = nil,
|
||||
bgcolor = 0.0, -- [0.0, 1.0]
|
||||
fgcolor = 1.0, -- [0.0, 1.0]
|
||||
width = 400,
|
||||
height = 20,
|
||||
scroll_bar_width = Screen:scaleByDPI(6),
|
||||
text_scroll_span = Screen:scaleByDPI(6),
|
||||
dialog = nil,
|
||||
text = nil,
|
||||
face = nil,
|
||||
bgcolor = 0.0, -- [0.0, 1.0]
|
||||
fgcolor = 1.0, -- [0.0, 1.0]
|
||||
width = 400,
|
||||
height = 20,
|
||||
scroll_bar_width = Screen:scaleByDPI(6),
|
||||
text_scroll_span = Screen:scaleByDPI(6),
|
||||
dialog = nil,
|
||||
}
|
||||
|
||||
function ScrollTextWidget:init()
|
||||
self.text_widget = TextBoxWidget:new{
|
||||
text = self.text,
|
||||
face = self.face,
|
||||
bgcolor = self.bgcolor,
|
||||
fgcolor = self.fgcolor,
|
||||
width = self.width - self.scroll_bar_width - self.text_scroll_span,
|
||||
height = self.height
|
||||
}
|
||||
local visible_line_count = self.text_widget:getVisLineCount()
|
||||
local total_line_count = self.text_widget:getAllLineCount()
|
||||
self.v_scroll_bar = VerticalScrollBar:new{
|
||||
enable = visible_line_count < total_line_count,
|
||||
low = 0,
|
||||
high = visible_line_count/total_line_count,
|
||||
width = Screen:scaleByDPI(6),
|
||||
height = self.height,
|
||||
}
|
||||
local horizontal_group = HorizontalGroup:new{}
|
||||
table.insert(horizontal_group, self.text_widget)
|
||||
table.insert(horizontal_group, HorizontalSpan:new{width = Screen:scaleByDPI(6)})
|
||||
table.insert(horizontal_group, self.v_scroll_bar)
|
||||
self[1] = horizontal_group
|
||||
self.dimen = Geom:new(self[1]:getSize())
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
Swipe = {
|
||||
GestureRange:new{
|
||||
ges = "swipe",
|
||||
range = self.dimen,
|
||||
},
|
||||
},
|
||||
}
|
||||
end
|
||||
self.text_widget = TextBoxWidget:new{
|
||||
text = self.text,
|
||||
face = self.face,
|
||||
bgcolor = self.bgcolor,
|
||||
fgcolor = self.fgcolor,
|
||||
width = self.width - self.scroll_bar_width - self.text_scroll_span,
|
||||
height = self.height
|
||||
}
|
||||
local visible_line_count = self.text_widget:getVisLineCount()
|
||||
local total_line_count = self.text_widget:getAllLineCount()
|
||||
self.v_scroll_bar = VerticalScrollBar:new{
|
||||
enable = visible_line_count < total_line_count,
|
||||
low = 0,
|
||||
high = visible_line_count/total_line_count,
|
||||
width = Screen:scaleByDPI(6),
|
||||
height = self.height,
|
||||
}
|
||||
local horizontal_group = HorizontalGroup:new{}
|
||||
table.insert(horizontal_group, self.text_widget)
|
||||
table.insert(horizontal_group, HorizontalSpan:new{width = Screen:scaleByDPI(6)})
|
||||
table.insert(horizontal_group, self.v_scroll_bar)
|
||||
self[1] = horizontal_group
|
||||
self.dimen = Geom:new(self[1]:getSize())
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
Swipe = {
|
||||
GestureRange:new{
|
||||
ges = "swipe",
|
||||
range = self.dimen,
|
||||
},
|
||||
},
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function ScrollTextWidget:updateScrollBar(text)
|
||||
local virtual_line_num = text:getVirtualLineNum()
|
||||
local visible_line_count = text:getVisLineCount()
|
||||
local all_line_count = text:getAllLineCount()
|
||||
self.v_scroll_bar:set(
|
||||
(virtual_line_num - 1) / all_line_count,
|
||||
(virtual_line_num - 1 + visible_line_count) / all_line_count
|
||||
)
|
||||
local virtual_line_num = text:getVirtualLineNum()
|
||||
local visible_line_count = text:getVisLineCount()
|
||||
local all_line_count = text:getAllLineCount()
|
||||
self.v_scroll_bar:set(
|
||||
(virtual_line_num - 1) / all_line_count,
|
||||
(virtual_line_num - 1 + visible_line_count) / all_line_count
|
||||
)
|
||||
end
|
||||
|
||||
function ScrollTextWidget:onSwipe(arg, ges)
|
||||
if ges.direction == "north" then
|
||||
self.text_widget:scrollDown()
|
||||
self:updateScrollBar(self.text_widget)
|
||||
elseif ges.direction == "south" then
|
||||
self.text_widget:scrollUp()
|
||||
self:updateScrollBar(self.text_widget)
|
||||
end
|
||||
UIManager:setDirty(self.dialog, "partial")
|
||||
return true
|
||||
if ges.direction == "north" then
|
||||
self.text_widget:scrollDown()
|
||||
self:updateScrollBar(self.text_widget)
|
||||
elseif ges.direction == "south" then
|
||||
self.text_widget:scrollUp()
|
||||
self:updateScrollBar(self.text_widget)
|
||||
end
|
||||
UIManager:setDirty(self.dialog, "partial")
|
||||
return true
|
||||
end
|
||||
|
||||
return ScrollTextWidget
|
||||
|
||||
@@ -9,59 +9,59 @@ local Geom = require("ui/geometry")
|
||||
A TextWidget that handles long text wrapping
|
||||
--]]
|
||||
local TextBoxWidget = Widget:new{
|
||||
text = nil,
|
||||
face = nil,
|
||||
bold = nil,
|
||||
bgcolor = 0.0, -- [0.0, 1.0]
|
||||
fgcolor = 1.0, -- [0.0, 1.0]
|
||||
width = 400, -- in pixels
|
||||
height = nil,
|
||||
first_line = 1,
|
||||
virtual_line = 1, -- used by scroll bar
|
||||
line_height = 0.3, -- in em
|
||||
v_list = nil,
|
||||
_bb = nil,
|
||||
_length = 0,
|
||||
text = nil,
|
||||
face = nil,
|
||||
bold = nil,
|
||||
bgcolor = 0.0, -- [0.0, 1.0]
|
||||
fgcolor = 1.0, -- [0.0, 1.0]
|
||||
width = 400, -- in pixels
|
||||
height = nil,
|
||||
first_line = 1,
|
||||
virtual_line = 1, -- used by scroll bar
|
||||
line_height = 0.3, -- in em
|
||||
v_list = nil,
|
||||
_bb = nil,
|
||||
_length = 0,
|
||||
}
|
||||
|
||||
function TextBoxWidget:init()
|
||||
local v_list = nil
|
||||
if self.height then
|
||||
v_list = self:_getCurrentVerticalList()
|
||||
else
|
||||
v_list = self:_getVerticalList()
|
||||
end
|
||||
self:_render(v_list)
|
||||
local v_list = nil
|
||||
if self.height then
|
||||
v_list = self:_getCurrentVerticalList()
|
||||
else
|
||||
v_list = self:_getVerticalList()
|
||||
end
|
||||
self:_render(v_list)
|
||||
end
|
||||
|
||||
function TextBoxWidget:_wrapGreedyAlg(h_list)
|
||||
local cur_line_width = 0
|
||||
local cur_line = {}
|
||||
local v_list = {}
|
||||
local cur_line_width = 0
|
||||
local cur_line = {}
|
||||
local v_list = {}
|
||||
|
||||
for k,w in ipairs(h_list) do
|
||||
cur_line_width = cur_line_width + w.width
|
||||
if w.word == "\n" then
|
||||
if cur_line_width > 0 then
|
||||
-- hard line break
|
||||
table.insert(v_list, cur_line)
|
||||
cur_line = {}
|
||||
cur_line_width = 0
|
||||
end
|
||||
elseif cur_line_width > self.width then
|
||||
-- wrap to next line
|
||||
table.insert(v_list, cur_line)
|
||||
cur_line = {}
|
||||
cur_line_width = w.width
|
||||
table.insert(cur_line, w)
|
||||
else
|
||||
table.insert(cur_line, w)
|
||||
end
|
||||
end
|
||||
-- handle last line
|
||||
table.insert(v_list, cur_line)
|
||||
for k,w in ipairs(h_list) do
|
||||
cur_line_width = cur_line_width + w.width
|
||||
if w.word == "\n" then
|
||||
if cur_line_width > 0 then
|
||||
-- hard line break
|
||||
table.insert(v_list, cur_line)
|
||||
cur_line = {}
|
||||
cur_line_width = 0
|
||||
end
|
||||
elseif cur_line_width > self.width then
|
||||
-- wrap to next line
|
||||
table.insert(v_list, cur_line)
|
||||
cur_line = {}
|
||||
cur_line_width = w.width
|
||||
table.insert(cur_line, w)
|
||||
else
|
||||
table.insert(cur_line, w)
|
||||
end
|
||||
end
|
||||
-- handle last line
|
||||
table.insert(v_list, cur_line)
|
||||
|
||||
return v_list
|
||||
return v_list
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -77,199 +77,199 @@ License: MIT/X11
|
||||
Source: http://snippets.luacode.org/snippets/String_splitting_130
|
||||
--]]
|
||||
function string:gsplit(pattern, capture)
|
||||
pattern = pattern and tostring(pattern) or '%s+'
|
||||
if (''):find(pattern) then
|
||||
error('pattern matches empty string!', 2)
|
||||
end
|
||||
return coroutine.wrap(function()
|
||||
local index = 1
|
||||
repeat
|
||||
local first, last = self:find(pattern, index)
|
||||
if first and last then
|
||||
if index < first then
|
||||
coroutine.yield(self:sub(index, first - 1))
|
||||
end
|
||||
if capture then
|
||||
coroutine.yield(self:sub(first, last))
|
||||
end
|
||||
index = last + 1
|
||||
else
|
||||
if index <= #self then
|
||||
coroutine.yield(self:sub(index))
|
||||
end
|
||||
break
|
||||
end
|
||||
until index > #self
|
||||
end)
|
||||
pattern = pattern and tostring(pattern) or '%s+'
|
||||
if (''):find(pattern) then
|
||||
error('pattern matches empty string!', 2)
|
||||
end
|
||||
return coroutine.wrap(function()
|
||||
local index = 1
|
||||
repeat
|
||||
local first, last = self:find(pattern, index)
|
||||
if first and last then
|
||||
if index < first then
|
||||
coroutine.yield(self:sub(index, first - 1))
|
||||
end
|
||||
if capture then
|
||||
coroutine.yield(self:sub(first, last))
|
||||
end
|
||||
index = last + 1
|
||||
else
|
||||
if index <= #self then
|
||||
coroutine.yield(self:sub(index))
|
||||
end
|
||||
break
|
||||
end
|
||||
until index > #self
|
||||
end)
|
||||
end
|
||||
|
||||
function TextBoxWidget:_getVerticalList(alg)
|
||||
if self.vertical_list then
|
||||
return self.vertical_list
|
||||
end
|
||||
-- build horizontal list
|
||||
local h_list = {}
|
||||
local line_count = 0
|
||||
for line in self.text:gsplit("\n", true) do
|
||||
for words in line:gmatch("[\32-\127\192-\255]+[\128-\191]*") do
|
||||
for word in words:gsplit("%s+", true) do
|
||||
for w in word:gsplit("%p+", true) do
|
||||
local word_box = {}
|
||||
word_box.word = w
|
||||
word_box.width = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, w, true, self.bold).x
|
||||
table.insert(h_list, word_box)
|
||||
end
|
||||
end
|
||||
end
|
||||
if line:sub(-1) == "\n" then table.insert(h_list, {word = '\n', width = 0}) end
|
||||
end
|
||||
if self.vertical_list then
|
||||
return self.vertical_list
|
||||
end
|
||||
-- build horizontal list
|
||||
local h_list = {}
|
||||
local line_count = 0
|
||||
for line in self.text:gsplit("\n", true) do
|
||||
for words in line:gmatch("[\32-\127\192-\255]+[\128-\191]*") do
|
||||
for word in words:gsplit("%s+", true) do
|
||||
for w in word:gsplit("%p+", true) do
|
||||
local word_box = {}
|
||||
word_box.word = w
|
||||
word_box.width = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, w, true, self.bold).x
|
||||
table.insert(h_list, word_box)
|
||||
end
|
||||
end
|
||||
end
|
||||
if line:sub(-1) == "\n" then table.insert(h_list, {word = '\n', width = 0}) end
|
||||
end
|
||||
|
||||
-- @TODO check alg here 25.04 2012 (houqp)
|
||||
-- @TODO replace greedy algorithm with K&P algorithm 25.04 2012 (houqp)
|
||||
self.vertical_list = self:_wrapGreedyAlg(h_list)
|
||||
return self.vertical_list
|
||||
-- @TODO check alg here 25.04 2012 (houqp)
|
||||
-- @TODO replace greedy algorithm with K&P algorithm 25.04 2012 (houqp)
|
||||
self.vertical_list = self:_wrapGreedyAlg(h_list)
|
||||
return self.vertical_list
|
||||
end
|
||||
|
||||
function TextBoxWidget:_getCurrentVerticalList()
|
||||
local line_height = (1 + self.line_height) * self.face.size
|
||||
local v_list = self:_getVerticalList()
|
||||
local current_v_list = {}
|
||||
local height = 0
|
||||
for i = self.first_line, #v_list do
|
||||
if height < self.height - line_height then
|
||||
table.insert(current_v_list, v_list[i])
|
||||
height = height + line_height
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
return current_v_list
|
||||
local line_height = (1 + self.line_height) * self.face.size
|
||||
local v_list = self:_getVerticalList()
|
||||
local current_v_list = {}
|
||||
local height = 0
|
||||
for i = self.first_line, #v_list do
|
||||
if height < self.height - line_height then
|
||||
table.insert(current_v_list, v_list[i])
|
||||
height = height + line_height
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
return current_v_list
|
||||
end
|
||||
|
||||
function TextBoxWidget:_getPreviousVerticalList()
|
||||
local line_height = (1 + self.line_height) * self.face.size
|
||||
local v_list = self:_getVerticalList()
|
||||
local previous_v_list = {}
|
||||
local height = 0
|
||||
if self.first_line == 1 then
|
||||
return self:_getCurrentVerticalList()
|
||||
end
|
||||
self.virtual_line = self.first_line
|
||||
for i = self.first_line - 1, 1, -1 do
|
||||
if height < self.height - line_height then
|
||||
table.insert(previous_v_list, 1, v_list[i])
|
||||
height = height + line_height
|
||||
self.virtual_line = self.virtual_line - 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
for i = self.first_line, #v_list do
|
||||
if height < self.height - line_height then
|
||||
table.insert(previous_v_list, v_list[i])
|
||||
height = height + line_height
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
if self.first_line > #previous_v_list then
|
||||
self.first_line = self.first_line - #previous_v_list
|
||||
else
|
||||
self.first_line = 1
|
||||
end
|
||||
return previous_v_list
|
||||
local line_height = (1 + self.line_height) * self.face.size
|
||||
local v_list = self:_getVerticalList()
|
||||
local previous_v_list = {}
|
||||
local height = 0
|
||||
if self.first_line == 1 then
|
||||
return self:_getCurrentVerticalList()
|
||||
end
|
||||
self.virtual_line = self.first_line
|
||||
for i = self.first_line - 1, 1, -1 do
|
||||
if height < self.height - line_height then
|
||||
table.insert(previous_v_list, 1, v_list[i])
|
||||
height = height + line_height
|
||||
self.virtual_line = self.virtual_line - 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
for i = self.first_line, #v_list do
|
||||
if height < self.height - line_height then
|
||||
table.insert(previous_v_list, v_list[i])
|
||||
height = height + line_height
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
if self.first_line > #previous_v_list then
|
||||
self.first_line = self.first_line - #previous_v_list
|
||||
else
|
||||
self.first_line = 1
|
||||
end
|
||||
return previous_v_list
|
||||
end
|
||||
|
||||
function TextBoxWidget:_getNextVerticalList()
|
||||
local line_height = (1 + self.line_height) * self.face.size
|
||||
local v_list = self:_getVerticalList()
|
||||
local current_v_list = self:_getCurrentVerticalList()
|
||||
local next_v_list = {}
|
||||
local height = 0
|
||||
if self.first_line + #current_v_list > #v_list then
|
||||
return current_v_list
|
||||
end
|
||||
self.virtual_line = self.first_line
|
||||
for i = self.first_line + #current_v_list, #v_list do
|
||||
if height < self.height - line_height then
|
||||
table.insert(next_v_list, v_list[i])
|
||||
height = height + line_height
|
||||
self.virtual_line = self.virtual_line + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
self.first_line = self.first_line + #current_v_list
|
||||
return next_v_list
|
||||
local line_height = (1 + self.line_height) * self.face.size
|
||||
local v_list = self:_getVerticalList()
|
||||
local current_v_list = self:_getCurrentVerticalList()
|
||||
local next_v_list = {}
|
||||
local height = 0
|
||||
if self.first_line + #current_v_list > #v_list then
|
||||
return current_v_list
|
||||
end
|
||||
self.virtual_line = self.first_line
|
||||
for i = self.first_line + #current_v_list, #v_list do
|
||||
if height < self.height - line_height then
|
||||
table.insert(next_v_list, v_list[i])
|
||||
height = height + line_height
|
||||
self.virtual_line = self.virtual_line + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
self.first_line = self.first_line + #current_v_list
|
||||
return next_v_list
|
||||
end
|
||||
|
||||
function TextBoxWidget:_render(v_list)
|
||||
local font_height = self.face.size
|
||||
local line_height_px = self.line_height * font_height
|
||||
local space_w = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, " ", true).x
|
||||
local h = (font_height + line_height_px) * #v_list
|
||||
self._bb = Blitbuffer.new(self.width, h)
|
||||
local y = font_height
|
||||
local pen_x = 0
|
||||
for _,l in ipairs(v_list) do
|
||||
pen_x = 0
|
||||
for _,w in ipairs(l) do
|
||||
--@TODO Don't use kerning for monospaced fonts. (houqp)
|
||||
-- refert to cb25029dddc42693cc7aaefbe47e9bd3b7e1a750 in master tree
|
||||
RenderText:renderUtf8Text(self._bb, pen_x, y, self.face, w.word, true, self.bold, self.bgcolor, self.fgcolor)
|
||||
pen_x = pen_x + w.width
|
||||
end
|
||||
y = y + line_height_px + font_height
|
||||
end
|
||||
-- -- if text is shorter than one line, shrink to text's width
|
||||
-- if #v_list == 1 then
|
||||
-- self.width = pen_x
|
||||
-- end
|
||||
local font_height = self.face.size
|
||||
local line_height_px = self.line_height * font_height
|
||||
local space_w = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, " ", true).x
|
||||
local h = (font_height + line_height_px) * #v_list
|
||||
self._bb = Blitbuffer.new(self.width, h)
|
||||
local y = font_height
|
||||
local pen_x = 0
|
||||
for _,l in ipairs(v_list) do
|
||||
pen_x = 0
|
||||
for _,w in ipairs(l) do
|
||||
--@TODO Don't use kerning for monospaced fonts. (houqp)
|
||||
-- refert to cb25029dddc42693cc7aaefbe47e9bd3b7e1a750 in master tree
|
||||
RenderText:renderUtf8Text(self._bb, pen_x, y, self.face, w.word, true, self.bold, self.bgcolor, self.fgcolor)
|
||||
pen_x = pen_x + w.width
|
||||
end
|
||||
y = y + line_height_px + font_height
|
||||
end
|
||||
-- -- if text is shorter than one line, shrink to text's width
|
||||
-- if #v_list == 1 then
|
||||
-- self.width = pen_x
|
||||
-- end
|
||||
end
|
||||
|
||||
function TextBoxWidget:getVirtualLineNum()
|
||||
return self.virtual_line
|
||||
return self.virtual_line
|
||||
end
|
||||
|
||||
function TextBoxWidget:getAllLineCount()
|
||||
local v_list = self:_getVerticalList()
|
||||
return #v_list
|
||||
local v_list = self:_getVerticalList()
|
||||
return #v_list
|
||||
end
|
||||
|
||||
function TextBoxWidget:getVisLineCount()
|
||||
local line_height = (1 + self.line_height) * self.face.size
|
||||
return math.floor(self.height / line_height)
|
||||
local line_height = (1 + self.line_height) * self.face.size
|
||||
return math.floor(self.height / line_height)
|
||||
end
|
||||
|
||||
function TextBoxWidget:scrollDown()
|
||||
local next_v_list = self:_getNextVerticalList()
|
||||
self:free()
|
||||
self:_render(next_v_list)
|
||||
local next_v_list = self:_getNextVerticalList()
|
||||
self:free()
|
||||
self:_render(next_v_list)
|
||||
end
|
||||
|
||||
function TextBoxWidget:scrollUp()
|
||||
local previous_v_list = self:_getPreviousVerticalList()
|
||||
self:free()
|
||||
self:_render(previous_v_list)
|
||||
local previous_v_list = self:_getPreviousVerticalList()
|
||||
self:free()
|
||||
self:_render(previous_v_list)
|
||||
end
|
||||
|
||||
function TextBoxWidget:getSize()
|
||||
if self.width and self.height then
|
||||
return Geom:new{ w = self.width, h = self.height}
|
||||
else
|
||||
return Geom:new{ w = self.width, h = self._bb:getHeight()}
|
||||
end
|
||||
if self.width and self.height then
|
||||
return Geom:new{ w = self.width, h = self.height}
|
||||
else
|
||||
return Geom:new{ w = self.width, h = self._bb:getHeight()}
|
||||
end
|
||||
end
|
||||
|
||||
function TextBoxWidget:paintTo(bb, x, y)
|
||||
bb:blitFrom(self._bb, x, y, 0, 0, self.width, self._bb:getHeight())
|
||||
bb:blitFrom(self._bb, x, y, 0, 0, self.width, self._bb:getHeight())
|
||||
end
|
||||
|
||||
function TextBoxWidget:free()
|
||||
if self._bb then
|
||||
self._bb:free()
|
||||
self._bb = nil
|
||||
end
|
||||
if self._bb then
|
||||
self._bb:free()
|
||||
self._bb = nil
|
||||
end
|
||||
end
|
||||
|
||||
return TextBoxWidget
|
||||
|
||||
@@ -7,55 +7,55 @@ local Geom = require("ui/geometry")
|
||||
A TextWidget puts a string on a single line
|
||||
--]]
|
||||
local TextWidget = Widget:new{
|
||||
text = nil,
|
||||
face = nil,
|
||||
bold = nil,
|
||||
bgcolor = 0.0, -- [0.0, 1.0]
|
||||
fgcolor = 1.0, -- [0.0, 1.0]
|
||||
_bb = nil,
|
||||
_length = 0,
|
||||
_height = 0,
|
||||
_maxlength = 1200,
|
||||
text = nil,
|
||||
face = nil,
|
||||
bold = nil,
|
||||
bgcolor = 0.0, -- [0.0, 1.0]
|
||||
fgcolor = 1.0, -- [0.0, 1.0]
|
||||
_bb = nil,
|
||||
_length = 0,
|
||||
_height = 0,
|
||||
_maxlength = 1200,
|
||||
}
|
||||
|
||||
--function TextWidget:_render()
|
||||
--local h = self.face.size * 1.3
|
||||
--self._bb = Blitbuffer.new(self._maxlength, h)
|
||||
--self._length = RenderText:renderUtf8Text(self._bb, 0, h*0.8, self.face, self.text, true, self.bold)
|
||||
--local h = self.face.size * 1.3
|
||||
--self._bb = Blitbuffer.new(self._maxlength, h)
|
||||
--self._length = RenderText:renderUtf8Text(self._bb, 0, h*0.8, self.face, self.text, true, self.bold)
|
||||
--end
|
||||
|
||||
function TextWidget:getSize()
|
||||
--if not self._bb then
|
||||
--self:_render()
|
||||
--end
|
||||
--return { w = self._length, h = self._bb:getHeight() }
|
||||
local tsize = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, self.text, true, self.bold)
|
||||
if not tsize then
|
||||
return Geom:new{}
|
||||
end
|
||||
self._length = tsize.x
|
||||
self._height = self.face.size * 1.5
|
||||
return Geom:new{
|
||||
w = self._length,
|
||||
h = self._height,
|
||||
}
|
||||
--if not self._bb then
|
||||
--self:_render()
|
||||
--end
|
||||
--return { w = self._length, h = self._bb:getHeight() }
|
||||
local tsize = RenderText:sizeUtf8Text(0, Screen:getWidth(), self.face, self.text, true, self.bold)
|
||||
if not tsize then
|
||||
return Geom:new{}
|
||||
end
|
||||
self._length = tsize.x
|
||||
self._height = self.face.size * 1.5
|
||||
return Geom:new{
|
||||
w = self._length,
|
||||
h = self._height,
|
||||
}
|
||||
end
|
||||
|
||||
function TextWidget:paintTo(bb, x, y)
|
||||
--if not self._bb then
|
||||
--self:_render()
|
||||
--end
|
||||
--bb:blitFrom(self._bb, x, y, 0, 0, self._length, self._bb:getHeight())
|
||||
--@TODO Don't use kerning for monospaced fonts. (houqp)
|
||||
RenderText:renderUtf8Text(bb, x, y+self._height*0.7, self.face, self.text, true, self.bold,
|
||||
self.bgcolor, self.fgcolor, self.width)
|
||||
--if not self._bb then
|
||||
--self:_render()
|
||||
--end
|
||||
--bb:blitFrom(self._bb, x, y, 0, 0, self._length, self._bb:getHeight())
|
||||
--@TODO Don't use kerning for monospaced fonts. (houqp)
|
||||
RenderText:renderUtf8Text(bb, x, y+self._height*0.7, self.face, self.text, true, self.bold,
|
||||
self.bgcolor, self.fgcolor, self.width)
|
||||
end
|
||||
|
||||
function TextWidget:free()
|
||||
if self._bb then
|
||||
self._bb:free()
|
||||
self._bb = nil
|
||||
end
|
||||
if self._bb then
|
||||
self._bb:free()
|
||||
self._bb = nil
|
||||
end
|
||||
end
|
||||
|
||||
return TextWidget
|
||||
|
||||
@@ -14,126 +14,126 @@ local DEBUG = require("dbg")
|
||||
local _ = require("gettext")
|
||||
|
||||
local ToggleLabel = TextWidget:new{
|
||||
bold = true,
|
||||
bgcolor = 0,
|
||||
fgcolor = 1,
|
||||
bold = true,
|
||||
bgcolor = 0,
|
||||
fgcolor = 1,
|
||||
}
|
||||
|
||||
function ToggleLabel:paintTo(bb, x, y)
|
||||
RenderText:renderUtf8Text(bb, x, y+self._height*0.75, self.face, self.text, true, self.bold, self.bgcolor, self.fgcolor)
|
||||
RenderText:renderUtf8Text(bb, x, y+self._height*0.75, self.face, self.text, true, self.bold, self.bgcolor, self.fgcolor)
|
||||
end
|
||||
|
||||
local ToggleSwitch = InputContainer:new{
|
||||
width = Screen:scaleByDPI(216),
|
||||
height = Screen:scaleByDPI(30),
|
||||
bgcolor = 0, -- unfoused item color
|
||||
fgcolor = 7, -- focused item color
|
||||
width = Screen:scaleByDPI(216),
|
||||
height = Screen:scaleByDPI(30),
|
||||
bgcolor = 0, -- unfoused item color
|
||||
fgcolor = 7, -- focused item color
|
||||
}
|
||||
|
||||
function ToggleSwitch:init()
|
||||
self.n_pos = #self.toggle
|
||||
self.position = nil
|
||||
self.n_pos = #self.toggle
|
||||
self.position = nil
|
||||
|
||||
local label_font_face = "cfont"
|
||||
local label_font_size = 16
|
||||
local label_font_face = "cfont"
|
||||
local label_font_size = 16
|
||||
|
||||
self.toggle_frame = FrameContainer:new{background = 0, color = 7, radius = 7, bordersize = 1, padding = 2,}
|
||||
self.toggle_content = HorizontalGroup:new{}
|
||||
self.toggle_frame = FrameContainer:new{background = 0, color = 7, radius = 7, bordersize = 1, padding = 2,}
|
||||
self.toggle_content = HorizontalGroup:new{}
|
||||
|
||||
for i=1,#self.toggle do
|
||||
local label = ToggleLabel:new{
|
||||
align = "center",
|
||||
text = self.toggle[i],
|
||||
face = Font:getFace(label_font_face, label_font_size),
|
||||
}
|
||||
local content = CenterContainer:new{
|
||||
dimen = Geom:new{w = self.width/self.n_pos, h = self.height},
|
||||
label,
|
||||
}
|
||||
local button = FrameContainer:new{
|
||||
background = 0,
|
||||
color = 7,
|
||||
margin = 0,
|
||||
radius = 5,
|
||||
bordersize = 1,
|
||||
padding = 0,
|
||||
content,
|
||||
}
|
||||
table.insert(self.toggle_content, button)
|
||||
end
|
||||
for i=1,#self.toggle do
|
||||
local label = ToggleLabel:new{
|
||||
align = "center",
|
||||
text = self.toggle[i],
|
||||
face = Font:getFace(label_font_face, label_font_size),
|
||||
}
|
||||
local content = CenterContainer:new{
|
||||
dimen = Geom:new{w = self.width/self.n_pos, h = self.height},
|
||||
label,
|
||||
}
|
||||
local button = FrameContainer:new{
|
||||
background = 0,
|
||||
color = 7,
|
||||
margin = 0,
|
||||
radius = 5,
|
||||
bordersize = 1,
|
||||
padding = 0,
|
||||
content,
|
||||
}
|
||||
table.insert(self.toggle_content, button)
|
||||
end
|
||||
|
||||
self.toggle_frame[1] = self.toggle_content
|
||||
self[1] = self.toggle_frame
|
||||
self.dimen = Geom:new(self.toggle_frame:getSize())
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapSelect = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
},
|
||||
doc = _("Toggle switch"),
|
||||
},
|
||||
}
|
||||
end
|
||||
self.toggle_frame[1] = self.toggle_content
|
||||
self[1] = self.toggle_frame
|
||||
self.dimen = Geom:new(self.toggle_frame:getSize())
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapSelect = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
},
|
||||
doc = _("Toggle switch"),
|
||||
},
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function ToggleSwitch:update()
|
||||
local pos = self.position
|
||||
for i=1,#self.toggle_content do
|
||||
if pos == i then
|
||||
self.toggle_content[i].color = self.fgcolor
|
||||
self.toggle_content[i].background = self.fgcolor
|
||||
self.toggle_content[i][1][1].bgcolor = self.fgcolor/15
|
||||
self.toggle_content[i][1][1].fgcolor = 0.0
|
||||
else
|
||||
self.toggle_content[i].color = self.bgcolor
|
||||
self.toggle_content[i].background = self.bgcolor
|
||||
self.toggle_content[i][1][1].bgcolor = 0.0
|
||||
self.toggle_content[i][1][1].fgcolor = 1.0
|
||||
end
|
||||
end
|
||||
local pos = self.position
|
||||
for i=1,#self.toggle_content do
|
||||
if pos == i then
|
||||
self.toggle_content[i].color = self.fgcolor
|
||||
self.toggle_content[i].background = self.fgcolor
|
||||
self.toggle_content[i][1][1].bgcolor = self.fgcolor/15
|
||||
self.toggle_content[i][1][1].fgcolor = 0.0
|
||||
else
|
||||
self.toggle_content[i].color = self.bgcolor
|
||||
self.toggle_content[i].background = self.bgcolor
|
||||
self.toggle_content[i][1][1].bgcolor = 0.0
|
||||
self.toggle_content[i][1][1].fgcolor = 1.0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ToggleSwitch:setPosition(position)
|
||||
self.position = position
|
||||
self:update()
|
||||
self.position = position
|
||||
self:update()
|
||||
end
|
||||
|
||||
function ToggleSwitch:togglePosition(position)
|
||||
if self.n_pos == 2 and self.alternate ~= false then
|
||||
self.position = (self.position+1)%self.n_pos
|
||||
self.position = self.position == 0 and self.n_pos or self.position
|
||||
elseif self.n_pos == 1 then
|
||||
self.position = self.position == 1 and 0 or 1
|
||||
else
|
||||
self.position = position
|
||||
end
|
||||
self:update()
|
||||
if self.n_pos == 2 and self.alternate ~= false then
|
||||
self.position = (self.position+1)%self.n_pos
|
||||
self.position = self.position == 0 and self.n_pos or self.position
|
||||
elseif self.n_pos == 1 then
|
||||
self.position = self.position == 1 and 0 or 1
|
||||
else
|
||||
self.position = position
|
||||
end
|
||||
self:update()
|
||||
end
|
||||
|
||||
function ToggleSwitch:onTapSelect(arg, gev)
|
||||
local position = math.ceil(
|
||||
(gev.pos.x - self.dimen.x) / self.dimen.w * self.n_pos
|
||||
)
|
||||
--DEBUG("toggle position:", position)
|
||||
self:togglePosition(position)
|
||||
--[[
|
||||
if self.values then
|
||||
self.values = self.values or {}
|
||||
self.config:onConfigChoice(self.name, self.values[self.position])
|
||||
end
|
||||
if self.event then
|
||||
self.args = self.args or {}
|
||||
self.config:onConfigEvent(self.event, self.args[self.position])
|
||||
end
|
||||
if self.events then
|
||||
self.config:onConfigEvents(self.events, self.position)
|
||||
end
|
||||
--]]
|
||||
self.config:onConfigChoose(self.values, self.name, self.event, self.args, self.events, self.position)
|
||||
UIManager:setDirty(self.config, "partial")
|
||||
return true
|
||||
local position = math.ceil(
|
||||
(gev.pos.x - self.dimen.x) / self.dimen.w * self.n_pos
|
||||
)
|
||||
--DEBUG("toggle position:", position)
|
||||
self:togglePosition(position)
|
||||
--[[
|
||||
if self.values then
|
||||
self.values = self.values or {}
|
||||
self.config:onConfigChoice(self.name, self.values[self.position])
|
||||
end
|
||||
if self.event then
|
||||
self.args = self.args or {}
|
||||
self.config:onConfigEvent(self.event, self.args[self.position])
|
||||
end
|
||||
if self.events then
|
||||
self.config:onConfigEvents(self.events, self.position)
|
||||
end
|
||||
--]]
|
||||
self.config:onConfigChoose(self.values, self.name, self.event, self.args, self.events, self.position)
|
||||
UIManager:setDirty(self.config, "partial")
|
||||
return true
|
||||
end
|
||||
|
||||
return ToggleSwitch
|
||||
|
||||
@@ -22,49 +22,49 @@ local _ = require("gettext")
|
||||
TouchMenuItem widget
|
||||
--]]
|
||||
local TouchMenuItem = InputContainer:new{
|
||||
menu = nil,
|
||||
vertical_align = "center",
|
||||
item = nil,
|
||||
dimen = nil,
|
||||
face = Font:getFace("cfont", 22),
|
||||
show_parent = nil,
|
||||
menu = nil,
|
||||
vertical_align = "center",
|
||||
item = nil,
|
||||
dimen = nil,
|
||||
face = Font:getFace("cfont", 22),
|
||||
show_parent = nil,
|
||||
}
|
||||
|
||||
function TouchMenuItem:init()
|
||||
self.ges_events = {
|
||||
TapSelect = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
},
|
||||
doc = _("Select Menu Item"),
|
||||
},
|
||||
}
|
||||
self.ges_events = {
|
||||
TapSelect = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
},
|
||||
doc = _("Select Menu Item"),
|
||||
},
|
||||
}
|
||||
|
||||
self.item_frame = FrameContainer:new{
|
||||
width = self.dimen.w,
|
||||
bordersize = 0,
|
||||
color = 15,
|
||||
HorizontalGroup:new {
|
||||
align = "center",
|
||||
HorizontalSpan:new{ width = 10 },
|
||||
TextWidget:new{
|
||||
text = self.item.text or self.item.text_func(),
|
||||
face = self.face,
|
||||
},
|
||||
},
|
||||
}
|
||||
self[1] = self.item_frame
|
||||
self.item_frame = FrameContainer:new{
|
||||
width = self.dimen.w,
|
||||
bordersize = 0,
|
||||
color = 15,
|
||||
HorizontalGroup:new {
|
||||
align = "center",
|
||||
HorizontalSpan:new{ width = 10 },
|
||||
TextWidget:new{
|
||||
text = self.item.text or self.item.text_func(),
|
||||
face = self.face,
|
||||
},
|
||||
},
|
||||
}
|
||||
self[1] = self.item_frame
|
||||
end
|
||||
|
||||
function TouchMenuItem:onTapSelect(arg, ges)
|
||||
self.item_frame.invert = true
|
||||
UIManager:setDirty(self.show_parent, "partial")
|
||||
UIManager:scheduleIn(0.5, function()
|
||||
self.item_frame.invert = false
|
||||
UIManager:setDirty(self.show_parent, "partial")
|
||||
end)
|
||||
self.menu:onMenuSelect(self.item)
|
||||
self.item_frame.invert = true
|
||||
UIManager:setDirty(self.show_parent, "partial")
|
||||
UIManager:scheduleIn(0.5, function()
|
||||
self.item_frame.invert = false
|
||||
UIManager:setDirty(self.show_parent, "partial")
|
||||
end)
|
||||
self.menu:onMenuSelect(self.item)
|
||||
end
|
||||
|
||||
|
||||
@@ -72,97 +72,97 @@ end
|
||||
TouchMenuBar widget
|
||||
--]]
|
||||
local TouchMenuBar = InputContainer:new{
|
||||
height = Screen:scaleByDPI(70),
|
||||
width = Screen:getWidth(),
|
||||
icons = {},
|
||||
-- touch menu that holds the bar, used for trigger repaint on icons
|
||||
show_parent = nil,
|
||||
menu = nil,
|
||||
height = Screen:scaleByDPI(70),
|
||||
width = Screen:getWidth(),
|
||||
icons = {},
|
||||
-- touch menu that holds the bar, used for trigger repaint on icons
|
||||
show_parent = nil,
|
||||
menu = nil,
|
||||
}
|
||||
|
||||
function TouchMenuBar:init()
|
||||
self.show_parent = self.show_parent or self
|
||||
self.show_parent = self.show_parent or self
|
||||
|
||||
self.dimen = Geom:new{
|
||||
w = self.width,
|
||||
h = self.height,
|
||||
}
|
||||
self.dimen = Geom:new{
|
||||
w = self.width,
|
||||
h = self.height,
|
||||
}
|
||||
|
||||
self.bar_icon_group = HorizontalGroup:new{}
|
||||
self.bar_icon_group = HorizontalGroup:new{}
|
||||
|
||||
local icon_sep = LineWidget:new{
|
||||
dimen = Geom:new{
|
||||
w = Screen:scaleByDPI(2),
|
||||
h = self.height,
|
||||
}
|
||||
}
|
||||
local icon_sep = LineWidget:new{
|
||||
dimen = Geom:new{
|
||||
w = Screen:scaleByDPI(2),
|
||||
h = self.height,
|
||||
}
|
||||
}
|
||||
|
||||
local icon_span = HorizontalSpan:new{ width = Screen:scaleByDPI(20) }
|
||||
local icon_span = HorizontalSpan:new{ width = Screen:scaleByDPI(20) }
|
||||
|
||||
-- build up image widget for menu icon bar
|
||||
self.icon_widgets = {}
|
||||
-- the start_seg for first icon_widget should be 0
|
||||
-- we asign negative here to offset it in the loop
|
||||
start_seg = -icon_sep:getSize().w
|
||||
end_seg = start_seg
|
||||
for k, v in ipairs(self.icons) do
|
||||
local ib = IconButton:new{
|
||||
show_parent = self.show_parent,
|
||||
icon_file = v,
|
||||
callback = nil,
|
||||
}
|
||||
-- build up image widget for menu icon bar
|
||||
self.icon_widgets = {}
|
||||
-- the start_seg for first icon_widget should be 0
|
||||
-- we asign negative here to offset it in the loop
|
||||
start_seg = -icon_sep:getSize().w
|
||||
end_seg = start_seg
|
||||
for k, v in ipairs(self.icons) do
|
||||
local ib = IconButton:new{
|
||||
show_parent = self.show_parent,
|
||||
icon_file = v,
|
||||
callback = nil,
|
||||
}
|
||||
|
||||
table.insert(self.icon_widgets, HorizontalGroup:new{
|
||||
icon_span,
|
||||
ib,
|
||||
icon_span,
|
||||
})
|
||||
table.insert(self.icon_widgets, HorizontalGroup:new{
|
||||
icon_span,
|
||||
ib,
|
||||
icon_span,
|
||||
})
|
||||
|
||||
-- we have to use local variable here for closure callback
|
||||
local _start_seg = end_seg + icon_sep:getSize().w
|
||||
local _end_seg = _start_seg + self.icon_widgets[k]:getSize().w
|
||||
-- we have to use local variable here for closure callback
|
||||
local _start_seg = end_seg + icon_sep:getSize().w
|
||||
local _end_seg = _start_seg + self.icon_widgets[k]:getSize().w
|
||||
|
||||
if k == 1 then
|
||||
self.bar_sep = LineWidget:new{
|
||||
dimen = Geom:new{
|
||||
w = self.width,
|
||||
h = Screen:scaleByDPI(2),
|
||||
},
|
||||
empty_segments = {
|
||||
{
|
||||
s = _start_seg, e = _end_seg
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
if k == 1 then
|
||||
self.bar_sep = LineWidget:new{
|
||||
dimen = Geom:new{
|
||||
w = self.width,
|
||||
h = Screen:scaleByDPI(2),
|
||||
},
|
||||
empty_segments = {
|
||||
{
|
||||
s = _start_seg, e = _end_seg
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
ib.callback = function()
|
||||
self.bar_sep.empty_segments = {
|
||||
{
|
||||
s = _start_seg, e = _end_seg
|
||||
}
|
||||
}
|
||||
self.menu:switchMenuTab(k)
|
||||
end
|
||||
ib.callback = function()
|
||||
self.bar_sep.empty_segments = {
|
||||
{
|
||||
s = _start_seg, e = _end_seg
|
||||
}
|
||||
}
|
||||
self.menu:switchMenuTab(k)
|
||||
end
|
||||
|
||||
table.insert(self.bar_icon_group, self.icon_widgets[k])
|
||||
table.insert(self.bar_icon_group, icon_sep)
|
||||
table.insert(self.bar_icon_group, self.icon_widgets[k])
|
||||
table.insert(self.bar_icon_group, icon_sep)
|
||||
|
||||
start_seg = _start_seg
|
||||
end_seg = _end_seg
|
||||
end
|
||||
start_seg = _start_seg
|
||||
end_seg = _end_seg
|
||||
end
|
||||
|
||||
self[1] = FrameContainer:new{
|
||||
bordersize = 0,
|
||||
padding = 0,
|
||||
VerticalGroup:new{
|
||||
align = "left",
|
||||
-- bar icons
|
||||
self.bar_icon_group,
|
||||
-- separate line
|
||||
self.bar_sep
|
||||
},
|
||||
}
|
||||
self[1] = FrameContainer:new{
|
||||
bordersize = 0,
|
||||
padding = 0,
|
||||
VerticalGroup:new{
|
||||
align = "left",
|
||||
-- bar icons
|
||||
self.bar_icon_group,
|
||||
-- separate line
|
||||
self.bar_sep
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -170,258 +170,258 @@ end
|
||||
TouchMenu widget
|
||||
--]]
|
||||
local TouchMenu = InputContainer:new{
|
||||
tab_item_table = {},
|
||||
-- for returnning in multi-level menus
|
||||
item_table_stack = nil,
|
||||
item_table = nil,
|
||||
item_height = Screen:scaleByDPI(50),
|
||||
bordersize = Screen:scaleByDPI(2),
|
||||
padding = Screen:scaleByDPI(5),
|
||||
footer_height = Screen:scaleByDPI(50),
|
||||
width = nil,
|
||||
height = nil,
|
||||
page = 1,
|
||||
max_per_page = 10,
|
||||
-- for UIManager:setDirty
|
||||
show_parent = nil,
|
||||
cur_tab = -1,
|
||||
close_callback = nil,
|
||||
tab_item_table = {},
|
||||
-- for returnning in multi-level menus
|
||||
item_table_stack = nil,
|
||||
item_table = nil,
|
||||
item_height = Screen:scaleByDPI(50),
|
||||
bordersize = Screen:scaleByDPI(2),
|
||||
padding = Screen:scaleByDPI(5),
|
||||
footer_height = Screen:scaleByDPI(50),
|
||||
width = nil,
|
||||
height = nil,
|
||||
page = 1,
|
||||
max_per_page = 10,
|
||||
-- for UIManager:setDirty
|
||||
show_parent = nil,
|
||||
cur_tab = -1,
|
||||
close_callback = nil,
|
||||
}
|
||||
|
||||
function TouchMenu:init()
|
||||
self.show_parent = self.show_parent or self
|
||||
if not self.close_callback then
|
||||
self.close_callback = function()
|
||||
UIManager:close(self.show_parent)
|
||||
end
|
||||
end
|
||||
self.show_parent = self.show_parent or self
|
||||
if not self.close_callback then
|
||||
self.close_callback = function()
|
||||
UIManager:close(self.show_parent)
|
||||
end
|
||||
end
|
||||
|
||||
self.ges_events.TapCloseAllMenus = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
}
|
||||
self.ges_events.Swipe = {
|
||||
GestureRange:new{
|
||||
ges = "swipe",
|
||||
range = self.dimen,
|
||||
}
|
||||
}
|
||||
self.ges_events.TapCloseAllMenus = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = Geom:new{
|
||||
x = 0, y = 0,
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight(),
|
||||
}
|
||||
}
|
||||
}
|
||||
self.ges_events.Swipe = {
|
||||
GestureRange:new{
|
||||
ges = "swipe",
|
||||
range = self.dimen,
|
||||
}
|
||||
}
|
||||
|
||||
local icons = {}
|
||||
for _,v in ipairs(self.tab_item_table) do
|
||||
table.insert(icons, v.icon)
|
||||
end
|
||||
self.bar = TouchMenuBar:new{
|
||||
width = self.width - self.padding * 2 - self.bordersize * 2,
|
||||
icons = icons,
|
||||
show_parent = self.show_parent,
|
||||
menu = self,
|
||||
}
|
||||
local icons = {}
|
||||
for _,v in ipairs(self.tab_item_table) do
|
||||
table.insert(icons, v.icon)
|
||||
end
|
||||
self.bar = TouchMenuBar:new{
|
||||
width = self.width - self.padding * 2 - self.bordersize * 2,
|
||||
icons = icons,
|
||||
show_parent = self.show_parent,
|
||||
menu = self,
|
||||
}
|
||||
|
||||
self.item_group = VerticalGroup:new{
|
||||
align = "left",
|
||||
}
|
||||
self.item_group = VerticalGroup:new{
|
||||
align = "left",
|
||||
}
|
||||
|
||||
self.footer_page = TextWidget:new{
|
||||
face = Font:getFace("ffont", 20),
|
||||
text = "",
|
||||
}
|
||||
self.time_info = TextWidget:new{
|
||||
face = Font:getFace("ffont", 20),
|
||||
text = "",
|
||||
}
|
||||
local footer_width = self.width - self.padding*2 - self.bordersize*2
|
||||
self.footer = HorizontalGroup:new{
|
||||
LeftContainer:new{
|
||||
dimen = Geom:new{ w = footer_width*0.33, h = self.footer_height},
|
||||
IconButton:new{
|
||||
invert = true,
|
||||
icon_file = "resources/icons/appbar.chevron.up.png",
|
||||
show_parent = self.show_parent,
|
||||
callback = function()
|
||||
self:backToUpperMenu()
|
||||
end,
|
||||
},
|
||||
},
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{ w = footer_width*0.33, h = self.footer_height},
|
||||
self.footer_page,
|
||||
},
|
||||
RightContainer:new{
|
||||
dimen = Geom:new{ w = footer_width*0.33, h = self.footer_height},
|
||||
self.time_info,
|
||||
}
|
||||
}
|
||||
self.footer_page = TextWidget:new{
|
||||
face = Font:getFace("ffont", 20),
|
||||
text = "",
|
||||
}
|
||||
self.time_info = TextWidget:new{
|
||||
face = Font:getFace("ffont", 20),
|
||||
text = "",
|
||||
}
|
||||
local footer_width = self.width - self.padding*2 - self.bordersize*2
|
||||
self.footer = HorizontalGroup:new{
|
||||
LeftContainer:new{
|
||||
dimen = Geom:new{ w = footer_width*0.33, h = self.footer_height},
|
||||
IconButton:new{
|
||||
invert = true,
|
||||
icon_file = "resources/icons/appbar.chevron.up.png",
|
||||
show_parent = self.show_parent,
|
||||
callback = function()
|
||||
self:backToUpperMenu()
|
||||
end,
|
||||
},
|
||||
},
|
||||
CenterContainer:new{
|
||||
dimen = Geom:new{ w = footer_width*0.33, h = self.footer_height},
|
||||
self.footer_page,
|
||||
},
|
||||
RightContainer:new{
|
||||
dimen = Geom:new{ w = footer_width*0.33, h = self.footer_height},
|
||||
self.time_info,
|
||||
}
|
||||
}
|
||||
|
||||
self[1] = FrameContainer:new{
|
||||
padding = self.padding,
|
||||
bordersize = self.bordersize,
|
||||
background = 0,
|
||||
-- menubar and footer will be inserted in
|
||||
-- item_group in updateItems
|
||||
self.item_group,
|
||||
}
|
||||
self[1] = FrameContainer:new{
|
||||
padding = self.padding,
|
||||
bordersize = self.bordersize,
|
||||
background = 0,
|
||||
-- menubar and footer will be inserted in
|
||||
-- item_group in updateItems
|
||||
self.item_group,
|
||||
}
|
||||
|
||||
self:switchMenuTab(1)
|
||||
self:updateItems()
|
||||
self:switchMenuTab(1)
|
||||
self:updateItems()
|
||||
end
|
||||
|
||||
function TouchMenu:_recalculateDimen()
|
||||
self.dimen.w = self.width
|
||||
self.dimen.w = self.width
|
||||
|
||||
-- if height not given, dynamically calculate it
|
||||
if not self.height then
|
||||
self.dimen.h = (#self.item_table + 2) * self.item_height
|
||||
+ self.bar:getSize().h
|
||||
else
|
||||
self.dimen.h = self.height
|
||||
end
|
||||
-- make sure self.dimen.h does not overflow screen height
|
||||
if self.dimen.h > Screen:getHeight() then
|
||||
self.dimen.h = Screen:getHeight() - self.bar:getSize().h
|
||||
end
|
||||
-- if height not given, dynamically calculate it
|
||||
if not self.height then
|
||||
self.dimen.h = (#self.item_table + 2) * self.item_height
|
||||
+ self.bar:getSize().h
|
||||
else
|
||||
self.dimen.h = self.height
|
||||
end
|
||||
-- make sure self.dimen.h does not overflow screen height
|
||||
if self.dimen.h > Screen:getHeight() then
|
||||
self.dimen.h = Screen:getHeight() - self.bar:getSize().h
|
||||
end
|
||||
|
||||
self.perpage = math.floor(self.dimen.h / self.item_height) - 2
|
||||
if self.perpage > self.max_per_page then
|
||||
self.perpage = self.max_per_page
|
||||
end
|
||||
self.perpage = math.floor(self.dimen.h / self.item_height) - 2
|
||||
if self.perpage > self.max_per_page then
|
||||
self.perpage = self.max_per_page
|
||||
end
|
||||
|
||||
self.page_num = math.ceil(#self.item_table / self.perpage)
|
||||
self.page_num = math.ceil(#self.item_table / self.perpage)
|
||||
end
|
||||
|
||||
function TouchMenu:updateItems()
|
||||
self:_recalculateDimen()
|
||||
self.item_group:clear()
|
||||
table.insert(self.item_group, self.bar)
|
||||
self:_recalculateDimen()
|
||||
self.item_group:clear()
|
||||
table.insert(self.item_group, self.bar)
|
||||
|
||||
local item_width = self.dimen.w - self.padding*2 - self.bordersize*2
|
||||
local item_width = self.dimen.w - self.padding*2 - self.bordersize*2
|
||||
|
||||
for c = 1, self.perpage do
|
||||
-- calculate index in item_table
|
||||
local i = (self.page - 1) * self.perpage + c
|
||||
if i <= #self.item_table then
|
||||
local item_tmp = TouchMenuItem:new{
|
||||
item = self.item_table[i],
|
||||
menu = self,
|
||||
dimen = Geom:new{
|
||||
w = item_width,
|
||||
h = self.item_height,
|
||||
},
|
||||
show_parent = self.show_parent,
|
||||
}
|
||||
table.insert(self.item_group, item_tmp)
|
||||
-- insert split line
|
||||
if c ~= self.perpage then
|
||||
table.insert(self.item_group, HorizontalGroup:new{
|
||||
-- pad with 10 pixel to align with the up arrow in footer
|
||||
HorizontalSpan:new{width = 10},
|
||||
LineWidget:new{
|
||||
style = "dashed",
|
||||
dimen = Geom:new{
|
||||
w = item_width - 20,
|
||||
h = 1,
|
||||
}
|
||||
}
|
||||
})
|
||||
end
|
||||
else
|
||||
-- item not enough to fill the whole page, break out of loop
|
||||
--table.insert(self.item_group,
|
||||
--VerticalSpan:new{
|
||||
--width = self.item_height
|
||||
--})
|
||||
--break
|
||||
end -- if i <= self.items
|
||||
end -- for c=1, self.perpage
|
||||
for c = 1, self.perpage do
|
||||
-- calculate index in item_table
|
||||
local i = (self.page - 1) * self.perpage + c
|
||||
if i <= #self.item_table then
|
||||
local item_tmp = TouchMenuItem:new{
|
||||
item = self.item_table[i],
|
||||
menu = self,
|
||||
dimen = Geom:new{
|
||||
w = item_width,
|
||||
h = self.item_height,
|
||||
},
|
||||
show_parent = self.show_parent,
|
||||
}
|
||||
table.insert(self.item_group, item_tmp)
|
||||
-- insert split line
|
||||
if c ~= self.perpage then
|
||||
table.insert(self.item_group, HorizontalGroup:new{
|
||||
-- pad with 10 pixel to align with the up arrow in footer
|
||||
HorizontalSpan:new{width = 10},
|
||||
LineWidget:new{
|
||||
style = "dashed",
|
||||
dimen = Geom:new{
|
||||
w = item_width - 20,
|
||||
h = 1,
|
||||
}
|
||||
}
|
||||
})
|
||||
end
|
||||
else
|
||||
-- item not enough to fill the whole page, break out of loop
|
||||
--table.insert(self.item_group,
|
||||
--VerticalSpan:new{
|
||||
--width = self.item_height
|
||||
--})
|
||||
--break
|
||||
end -- if i <= self.items
|
||||
end -- for c=1, self.perpage
|
||||
|
||||
table.insert(self.item_group, VerticalSpan:new{width = Screen:scaleByDPI(2)})
|
||||
table.insert(self.item_group, self.footer)
|
||||
self.footer_page.text = _("Page ")..self.page.."/"..self.page_num
|
||||
self.time_info.text = os.date("%H:%M")
|
||||
-- FIXME: this is a dirty hack to clear previous menus
|
||||
-- refert to issue #664
|
||||
UIManager.repaint_all = true
|
||||
table.insert(self.item_group, VerticalSpan:new{width = Screen:scaleByDPI(2)})
|
||||
table.insert(self.item_group, self.footer)
|
||||
self.footer_page.text = _("Page ")..self.page.."/"..self.page_num
|
||||
self.time_info.text = os.date("%H:%M")
|
||||
-- FIXME: this is a dirty hack to clear previous menus
|
||||
-- refert to issue #664
|
||||
UIManager.repaint_all = true
|
||||
end
|
||||
|
||||
function TouchMenu:switchMenuTab(tab_num)
|
||||
if self.tab_item_table[tab_num].callback then
|
||||
self.tab_item_table[tab_num].callback()
|
||||
end
|
||||
if self.cur_tab ~= tab_num then
|
||||
-- it's like getting a new menu everytime we switch tab!
|
||||
self.page = 1
|
||||
-- clear item table stack
|
||||
self.item_table_stack = {}
|
||||
self.cur_tab = tab_num
|
||||
self.item_table = self.tab_item_table[tab_num]
|
||||
self:updateItems()
|
||||
end
|
||||
if self.tab_item_table[tab_num].callback then
|
||||
self.tab_item_table[tab_num].callback()
|
||||
end
|
||||
if self.cur_tab ~= tab_num then
|
||||
-- it's like getting a new menu everytime we switch tab!
|
||||
self.page = 1
|
||||
-- clear item table stack
|
||||
self.item_table_stack = {}
|
||||
self.cur_tab = tab_num
|
||||
self.item_table = self.tab_item_table[tab_num]
|
||||
self:updateItems()
|
||||
end
|
||||
end
|
||||
|
||||
function TouchMenu:backToUpperMenu()
|
||||
if #self.item_table_stack ~= 0 then
|
||||
self.item_table = table.remove(self.item_table_stack)
|
||||
self.page = 1
|
||||
self:updateItems()
|
||||
end
|
||||
if #self.item_table_stack ~= 0 then
|
||||
self.item_table = table.remove(self.item_table_stack)
|
||||
self.page = 1
|
||||
self:updateItems()
|
||||
end
|
||||
end
|
||||
|
||||
function TouchMenu:closeMenu()
|
||||
self.close_callback()
|
||||
self.close_callback()
|
||||
end
|
||||
|
||||
function TouchMenu:onNextPage()
|
||||
if self.page < self.page_num then
|
||||
self.page = self.page + 1
|
||||
self:updateItems()
|
||||
end
|
||||
return true
|
||||
if self.page < self.page_num then
|
||||
self.page = self.page + 1
|
||||
self:updateItems()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function TouchMenu:onPrevPage()
|
||||
if self.page > 1 then
|
||||
self.page = self.page - 1
|
||||
self:updateItems()
|
||||
end
|
||||
return true
|
||||
if self.page > 1 then
|
||||
self.page = self.page - 1
|
||||
self:updateItems()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function TouchMenu:onSwipe(arg, ges_ev)
|
||||
if ges_ev.direction == "west" or ges_ev.direction == "north" then
|
||||
self:onNextPage()
|
||||
elseif ges_ev.direction == "east" or ges_ev.direction == "south" then
|
||||
self:onPrevPage()
|
||||
end
|
||||
if ges_ev.direction == "west" or ges_ev.direction == "north" then
|
||||
self:onNextPage()
|
||||
elseif ges_ev.direction == "east" or ges_ev.direction == "south" then
|
||||
self:onPrevPage()
|
||||
end
|
||||
end
|
||||
|
||||
function TouchMenu:onMenuSelect(item)
|
||||
if item.sub_item_table == nil then
|
||||
if item.callback then
|
||||
-- put stuff in scheduler so we can See
|
||||
-- the effect of inverted menu item
|
||||
UIManager:scheduleIn(0.1, function()
|
||||
self:closeMenu()
|
||||
item.callback()
|
||||
end)
|
||||
end
|
||||
else
|
||||
table.insert(self.item_table_stack, self.item_table)
|
||||
self.item_table = item.sub_item_table
|
||||
self:updateItems()
|
||||
end
|
||||
return true
|
||||
if item.sub_item_table == nil then
|
||||
if item.callback then
|
||||
-- put stuff in scheduler so we can See
|
||||
-- the effect of inverted menu item
|
||||
UIManager:scheduleIn(0.1, function()
|
||||
self:closeMenu()
|
||||
item.callback()
|
||||
end)
|
||||
end
|
||||
else
|
||||
table.insert(self.item_table_stack, self.item_table)
|
||||
self.item_table = item.sub_item_table
|
||||
self:updateItems()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function TouchMenu:onTapCloseAllMenus(arg, ges_ev)
|
||||
if ges_ev.pos:notIntersectWith(self.dimen) then
|
||||
self:closeMenu()
|
||||
end
|
||||
if ges_ev.pos:notIntersectWith(self.dimen) then
|
||||
self:closeMenu()
|
||||
end
|
||||
end
|
||||
|
||||
return TouchMenu
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user