Merge pull request #204 from houqp/new_ui_code

some more adjustments to make it usable for my K4
This commit is contained in:
Dobrica Pavlinušić
2012-06-13 07:04:38 -07:00
16 changed files with 461 additions and 56 deletions

22
cre.cpp
View File

@@ -149,7 +149,7 @@ static int getCurrentPercent(lua_State *L) {
return 1;
}
static int getXPointer(lua_State *L) {
static int getCurrentXPointer(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
ldomXPointer xp = doc->text_view->getBookmark();
@@ -166,6 +166,22 @@ static int getFullHeight(lua_State *L) {
return 1;
}
static int getFontSize(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
lua_pushinteger(L, doc->text_view->getFontSize());
return 1;
}
static int getFontFace(lua_State *L) {
CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument");
lua_pushstring(L, doc->text_view->getDefaultFontFace().c_str());
return 1;
}
/*
* helper function for getTableOfContent()
*/
@@ -444,8 +460,10 @@ static const struct luaL_Reg credocument_meth[] = {
{"getPosFromXPointer", getPosFromXPointer},
{"getCurrentPos", getCurrentPos},
{"getCurrentPercent", getCurrentPercent},
{"getXPointer", getXPointer},
{"getCurrentXPointer", getCurrentXPointer},
{"getFullHeight", getFullHeight},
{"getFontSize", getFontSize},
{"getFontFace", getFontFace},
{"getToc", getTableOfContent},
/*--- set methods ---*/
{"setFontFace", setFontFace},

View File

@@ -1,10 +1,11 @@
require "cache"
require "ui/geometry"
CreDocument = Document:new{
_document = false,
engine_initilized = false,
line_space_percent = 100,
--dc_null = DrawContext.new()
default_font = "Droid Sans Fallback",
}
-- NuPogodi, 20.05.12: inspect the zipfile content
@@ -22,20 +23,28 @@ function CreDocument:zipContentExt(fname)
return string.lower(string.match(s, ".+%.([^.]+)"))
end
function CreDocument:init()
-- we need to initialize the CRE font list
local fonts = Font:getFontList()
for _k, _v in ipairs(fonts) do
local ok, err = pcall(cre.registerFont, Font.fontdir..'/'.._v)
if not ok then
DEBUG(err)
function CreDocument:engineInit()
if not engine_initilized then
-- we need to initialize the CRE font list
local fonts = Font:getFontList()
for _k, _v in ipairs(fonts) do
local ok, err = pcall(cre.registerFont, Font.fontdir..'/'.._v)
if not ok then
DEBUG(err)
end
end
end
--local default_font = G_reader_settings:readSetting("cre_font")
--if default_font then
--self.default_font = default_font
--end
local default_font = G_reader_settings:readSetting("cre_font")
if default_font then
self.default_font = default_font
end
engine_initilized = true
end
end
function CreDocument:init()
self:engineInit()
local ok
local file_type = string.lower(string.match(self.file, ".+%.([^.]+)"))
@@ -64,7 +73,8 @@ function CreDocument:init()
self.info.has_pages = false
self:_readMetadata()
self._document:setDefaultInterlineSpace(self.line_space_percent)
-- @TODO read line_space_percent from setting file 12.06 2012 (houqp)
--self._document:setDefaultInterlineSpace(self.line_space_percent)
end
function CreDocument:hintPage(pageno, zoom, rotation)
@@ -76,4 +86,38 @@ end
function CreDocument:renderPage(pageno, rect, zoom, rotation)
end
function CreDocument:getFontFace()
return self._document:getFontFace()
end
function CreDocument:setFontFace(new_font_face)
if new_font_face then
self._document:setFontFace(new_font_face)
end
end
function CreDocument:getFontSize()
return self._document:getFontSize()
end
function CreDocument:zoomFont(delta)
self._document:zoomFont(delta)
end
function CreDocument:setInterlineSpacePercent(percent)
self._document:setDefaultInterlineSpace(percent)
end
DocumentRegistry:addProvider("txt", "application/txt", CreDocument)
DocumentRegistry:addProvider("epub", "application/epub", CreDocument)
DocumentRegistry:addProvider("html", "application/html", CreDocument)
DocumentRegistry:addProvider("htm", "application/htm", CreDocument)
DocumentRegistry:addProvider("zip", "application/zip", CreDocument)
DocumentRegistry:addProvider("rtf", "application/rtf", CreDocument)
DocumentRegistry:addProvider("mobi", "application/mobi", CreDocument)
DocumentRegistry:addProvider("prc", "application/prc", CreDocument)
DocumentRegistry:addProvider("azw", "application/azw", CreDocument)
DocumentRegistry:addProvider("chm", "application/chm", CreDocument)
DocumentRegistry:addProvider("pdb", "application/pdb", CreDocument)
DocumentRegistry:addProvider("doc", "application/doc", CreDocument)
DocumentRegistry:addProvider("tcr", "application/tcr", CreDocument)

View File

@@ -14,11 +14,16 @@ function DocumentRegistry:getProvider(file)
local extension = string.lower(string.match(file, ".+%.([^.]+)"))
for _, provider in ipairs(self.providers) do
if extension == provider.extension then
return provider.provider:new{file = file}
return provider.provider
end
end
end
function DocumentRegistry:openDocument(file)
return self:getProvider(file):new{file = file}
end
--[[
This is an abstract interface to a document
]]--
@@ -41,7 +46,7 @@ Document = {
number_of_pages = 0,
-- if not pageable, length of the document in pixels
length = 0,
doc_height = 0,
-- other metadata
title = "",
@@ -98,7 +103,7 @@ function Document:_readMetadata()
if self.info.has_pages then
self.info.number_of_pages = self._document:getPages()
else
self.info.length = self._document:getFullHeight()
self.info.doc_height = self._document:getFullHeight()
end
return true
end

26
frontend/ui/device.lua Normal file
View File

@@ -0,0 +1,26 @@
function util.isKindle4()
re_val = os.execute("cat /proc/cpuinfo | grep MX50")
if re_val == 0 then
return true
else
return false
end
end
function util.isKindle3()
re_val = os.execute("cat /proc/cpuinfo | grep MX35")
if re_val == 0 then
return true
else
return false
end
end
function util.isKindle2()
re_val = os.execute("cat /proc/cpuinfo | grep MX3")
if re_val == 0 then
return true
else
return false
end
end

View File

@@ -1,4 +1,5 @@
require "ui/event"
require "ui/device"
-- constants from <linux/input.h>
EV_KEY = 1
@@ -110,6 +111,7 @@ Input = {
[44] = "Z", [45] = "X", [46] = "C", [47] = "V", [48] = "B", [49] = "N", [50] = "M", [52] = ".", [53] = "/", -- only KDX
[28] = "Enter",
[29] = "ScreenKB", -- K[4]
[42] = "Shift",
[56] = "Alt",
[57] = " ",
@@ -118,12 +120,12 @@ Input = {
[92] = "Press", -- KDX
[94] = "Sym", -- KDX
[98] = "Home", -- KDX
[102] = "Home", -- K[3]
[102] = "Home", -- K[3] & k[4]
[104] = "LPgBack", -- K[3] only
[103] = "Up", -- K[3]
[103] = "Up", -- K[3] & k[4]
[105] = "Left",
[106] = "Right",
[108] = "Down", -- K[3]
[108] = "Down", -- K[3] & k[4]
[109] = "RPgBack",
[114] = "VMinus",
[115] = "VPlus",
@@ -132,11 +134,11 @@ Input = {
[124] = "RPgFwd", -- KDX
[126] = "Sym", -- K[3]
[139] = "Menu",
[158] = "Back", -- K[3]
[158] = "Back", -- K[3] & K[4]
[190] = "AA", -- K[3]
[191] = "RPgFwd", -- K[3]
[191] = "RPgFwd", -- K[3] & k[4]
[193] = "LPgFwd", -- K[3] only
[194] = "Press", -- K[3]
[194] = "Press", -- K[3] & k[4]
},
sdl_event_map = {
[10] = "1", [11] = "2", [12] = "3", [13] = "4", [14] = "5", [15] = "6", [16] = "7", [17] = "8", [18] = "9", [19] = "0",
@@ -229,12 +231,24 @@ function Input:init()
-- check if we are running on Kindle 3 (additional volume input)
local f=lfs.attributes("/dev/input/event2")
if f then
print("Auto-detected Kindle 3")
input.open("/dev/input/event2")
if util.isKindle3() then
print("Auto-detected Kindle 3")
end
end
if util.isKindle4() then
print("Auto-detected Kindle 4")
self:adjustKindle4EventMap()
end
end
end
function Input:adjustKindle4EventMap()
self.event_map[193] = "LPgBack"
self.event_map[104] = "LPgFwd"
end
function Input:waitEvent(timeout_us, timeout_s)
-- wrapper for input.waitForEvents that will retry for some cases
local ok, ev
@@ -247,6 +261,8 @@ function Input:waitEvent(timeout_us, timeout_s)
-- don't report an error on timeout
ev = nil
break
elseif ev == "application forced to quit" then
os.exit(0)
end
DEBUG("got error waiting for events:", ev)
if ev ~= "Waiting for input failed: 4\n" then

View File

@@ -357,6 +357,9 @@ function Menu:onNextPage()
elseif self.page == self.page_num then
-- on the last page, we check if we're on the last item
local end_position = #self.item_table % self.perpage
if end_position == 0 then
end_position = self.perpage
end
if end_position ~= self.selected.y then
self:updateItems(end_position)
end
@@ -367,8 +370,8 @@ end
function Menu:onPrevPage()
if self.page > 1 then
self.page = self.page - 1
self:updateItems(1)
end
self:updateItems(1)
return true
end

View File

@@ -0,0 +1,109 @@
ReaderFont = InputContainer:new{
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" },
},
dimen = Geom:new{ w = Screen:getWidth()-20, h = Screen:getHeight()-20},
font_face = nil,
font_size = nil,
line_space_percent = 100,
}
function ReaderFont:init()
self.font_face = self.ui.document:getFontFace()
self.font_size = self.ui.document:getFontSize()
end
function ReaderFont:onSetDimensions(dimen)
self.dimen = dimen
end
function ReaderFont:onShowFontMenu()
-- build menu item_table
local face_list = cre.getFontFaces()
for k,v in ipairs(face_list) do
face_list[k] = {text = v}
end
-- NuPogodi, 18.05.12: define the number of the current font in face_list
--local item_no = 0
--while face_list[item_no] ~= self.font_face and item_no < #face_list do
--item_no = item_no + 1
--end
--local fonts_menu = Menu:new{
--menu_title = "Fonts Menu",
--item_array = face_list,
--current_entry = item_no - 1,
--}
local font_menu = Menu:new{
title = "Font Menu",
item_table = face_list,
dimen = self.dimen,
ui = self.ui
}
function font_menu:onMenuChoice(item)
if item.text and self.font_face ~= item.text then
self.font_face = item.text
msg = InfoMessage:new{ text = "Redrawing with "..item.text}
UIManager:show(msg)
self.ui.document:setFontFace(item.text)
-- signal readerrolling to update pos in new height
self.ui:handleEvent(Event:new("UpdatePos"))
UIManager:close(msg)
end
end
UIManager:show(font_menu)
return true
end
function ReaderFont:onChangeSize(direction)
local delta = 1
if direction == "decrease" then
delta = -1
end
self.font_size = self.font_size + delta
msg = InfoMessage:new{text = direction.." font size to "..self.font_size}
UIManager:show(msg)
self.ui.document:zoomFont(delta)
self.ui:handleEvent(Event:new("UpdatePos"))
UIManager:close(msg)
return true
end
function ReaderFont:onChangeLineSpace(direction)
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)
else
self.line_space_percent = self.line_space_percent + 10
self.line_space_percent = math.min(self.line_space_percent, 200)
end
msg = InfoMessage:new{"line spacing "..self.line_space_percent.."%"}
self.ui.document:setInterlineSpacePercent(self.line_space_percent)
self.ui:handleEvent(Event:new("UpdatePos"))
return true
end

View File

@@ -8,17 +8,46 @@ function ReaderMenu:onShowMenu()
local item_table = {}
table.insert(item_table, {
text = "Switch zoom mode",
text = "Screen rotate",
sub_item_table = {
{
text = "Zoom to fit content width",
text = "rotate 90 degree clockwise",
callback = function()
Screen:screenRotate("clockwise")
self.ui:handleEvent(Event:new("SetDimensions", Screen:getSize()))
end
},
{
text = "Zoom to fit content height",
text = "rotate 90 degree anticlockwise",
callback = function()
Screen:screenRotate("anticlockwise")
self.ui:handleEvent(Event:new("SetDimensions", Screen:getSize()))
end
},
}
})
if self.ui.document.info.has_pages then
table.insert(item_table, {
text = "Switch zoom mode",
sub_item_table = {
{
text = "Zoom to fit content width",
},
{
text = "Zoom to fit content height",
},
}
})
else
table.insert(item_table, {
text = "Font menu",
callback = function()
self.ui:handleEvent(Event:new("ShowFontMenu"))
end
})
end
table.insert(item_table, {
text = "Return to file browser"
})
@@ -30,6 +59,12 @@ function ReaderMenu:onShowMenu()
height = #item_table + 3 * 28
}
function main_menu:onMenuChoice(item)
if item.callback then
item.callback()
end
end
UIManager:show(main_menu)
return true

View File

@@ -20,13 +20,15 @@ ReaderRolling = InputContainer:new{
GotoLast = { {"0"}, doc = "go to end", event = "GotoPercent", args = 100},
},
old_doc_height = nil,
current_pos = 0,
length = nil,
doc_height = nil,
panning_steps = ReaderPanning.panning_steps,
}
function ReaderRolling:init()
self.length = self.ui.document.info.length
self.doc_height = self.ui.document.info.doc_height
self.old_doc_height = self.doc_height
end
function ReaderRolling:onPosUpdate(new_pos)
@@ -36,13 +38,32 @@ end
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.length then new_pos = self.length end
if new_pos > self.doc_height then new_pos = self.doc_height end
self.ui:handleEvent(Event:new("PosUpdate", new_pos))
end
function ReaderRolling:gotoPercent(new_percent)
self:gotoPos(new_percent * self.doc_height / 10000)
end
-- remember to signal this event the document has been zoomed,
-- font has been changed, or line height has been changed.
function ReaderRolling:onUpdatePos()
-- reread document height
self.ui.document:_readMetadata()
-- update self.current_pos if the height of document has been changed.
if self.old_doc_height ~= self.ui.document.info.doc_height then
self:gotoPos(self.current_pos *
(self.ui.document.info.doc_height - self.dialog.dimen.h) /
(self.old_doc_height - self.dialog.dimen.h))
self.old_doc_height = self.ui.document.info.doc_height
end
return true
end
function ReaderRolling:onGotoPercent(percent)
DEBUG("goto document offset in percent:", percent)
self:gotoPos(percent * self.length / 10000)
self:gotoPercent(percent)
return true
end
@@ -60,5 +81,6 @@ function ReaderRolling:onPanning(args, key)
end
function ReaderRolling:onZoom()
--@TODO re-read length info after font or lineheight changes 05.06 2012 (houqp)
--@TODO re-read doc_height info after font or lineheight changes 05.06 2012 (houqp)
self:onUpdatePos()
end

View File

@@ -59,8 +59,7 @@ function ReaderToc:onShowToc()
local toc_menu = Menu:new{
title = "Table of Contents",
item_table = items,
width = self.dimen.w,
height = self.dimen.h,
dimen = self.dimen,
ui = self.ui
}
function toc_menu:onMenuChoice(item)
@@ -70,6 +69,10 @@ function ReaderToc:onShowToc()
UIManager:show(toc_menu)
end
function ReaderToc:onSetDimensions(dimen)
self.dimen = dimen
end
function ReaderToc:onPageUpdate(new_page_no)
self.current_page = new_page_no
end

View File

@@ -59,21 +59,16 @@ function ReaderView:recalculate()
self.page_area = page_size
-- reset our size
self.visible_area:setSizeTo(self.ui.dimen)
self.visible_area:setSizeTo(self.dimen)
-- and recalculate it according to page size
self.visible_area:offsetWithin(self.page_area, 0, 0)
else
self.visible_area:setSizeTo(self.ui.dimen)
self.visible_area:setSizeTo(self.dimen)
end
-- flag a repaint
UIManager:setDirty(self.dialog)
end
function ReaderView:onSetDimensions(dimensions)
-- recalculate view
self:recalculate()
end
function ReaderView:PanningUpdate(dx, dy)
DEBUG("pan by", dx, dy)
local old = self.visible_area:copy()
@@ -87,6 +82,12 @@ function ReaderView:PanningUpdate(dx, dy)
return true
end
function ReaderView:onSetDimensions(dimensions)
self.dimen = dimensions
-- recalculate view
self:recalculate()
end
function ReaderView:onPageUpdate(new_page_no)
self.state.page = new_page_no
self:recalculate()

View File

@@ -6,6 +6,7 @@ require "ui/reader/readerrotation"
require "ui/reader/readerpaging"
require "ui/reader/readerrolling"
require "ui/reader/readertoc"
require "ui/reader/readerfont"
require "ui/reader/readermenu"
--[[
@@ -27,6 +28,11 @@ ReaderUI = InputContainer:new{
-- the document interface
document = nil,
-- initial page or percent inside document on opening
start_pos = nil,
-- password for document unlock
password = nil,
}
function ReaderUI:init()
@@ -37,6 +43,7 @@ function ReaderUI:init()
-- a view container (so it must be child #1!)
self[1] = ReaderView:new{
dialog = self.dialog,
dimen = self.dimen,
ui = self
}
-- rotation controller
@@ -80,20 +87,38 @@ function ReaderUI:init()
ui = self
}
table.insert(self, pager)
pager:gotoPage(1)
if not self.start_pos then
self.start_pos = 1
end
pager:gotoPage(self.start_pos)
else
-- rolling controller
local roller = ReaderRolling:new{
dialog = self.dialog,
view = self[1],
ui = self
}
table.insert(self, roller)
roller:gotoPos(0)
if not self.start_pos then
self.start_pos = 0
end
roller:gotoPercent(self.start_pos)
-- font menu
local font_menu = ReaderFont:new{
dialog = self.dialog,
view = self[1],
ui = self
}
table.insert(self, font_menu)
end
-- notify childs of dimensions
self:handleEvent(Event:new("SetDimensions", self.dimen))
end
function ReaderUI:onSetDimensions(dimen)
self.dimen = dimen
end
function ReaderUI:onClose()
DEBUG("closing reader")
if self.document then

View File

@@ -66,6 +66,7 @@ function Screen:screenRotate(orien)
self.fb:setOrientation(self.cur_rotation_mode)
self.fb:close()
self.fb = einkfb.open("/dev/fb0")
Input.rotation = self.cur_rotation_mode
end
function Screen:getSize()
@@ -88,6 +89,10 @@ function Screen:updateRotationMode()
self.cur_rotation_mode = self.fb:getOrientation()
end
function Screen:setRotationMode(mode)
self.fb:setOrientation(Screen.native_rotation_mode)
end
function Screen:saveCurrentBB()
local width, height = self:getWidth(), self.getHeight()

View File

@@ -1,4 +1,5 @@
require "ui/geometry"
require "ui/device"
require "ui/inputevent"
require "ui/widget"
require "ui/screen"

104
reader.lua Normal file → Executable file
View File

@@ -1,12 +1,16 @@
#!./kpdfview
package.path = "./frontend/?.lua"
require "ui/ui"
require "ui/readerui"
require "ui/filechooser"
require "ui/infomessage"
require "document/document"
require "alt_getopt"
function showReader(file)
local document = DocumentRegistry:getProvider(file)
function showReader(file, pass)
local document = DocumentRegistry:openDocument(file)
if not document then
UIManager:show(InfoMessage:new{ text = "No reader engine for this file" })
return
@@ -22,8 +26,10 @@ function showReader(file)
local reader = ReaderUI:new{
dialog = readerwindow,
dimen = Screen:getSize(),
document = document
document = document,
password = pass
}
readerwindow[1] = reader
UIManager:show(readerwindow)
@@ -33,7 +39,12 @@ function showFileManager(path)
local FileManager = FileChooser:new{
path = path,
dimen = Screen:getSize(),
is_borderless = true
is_borderless = true,
filter = function(filename)
if DocumentRegistry:getProvider(filename) then
return true
end
end
}
function FileManager:onFileSelect(file)
@@ -49,6 +60,87 @@ function showFileManager(path)
UIManager:show(FileManager)
end
showFileManager(".")
UIManager:run()
-- option parsing:
longopts = {
password = "p",
goto = "g",
gamma = "G",
debug = "d",
help = "h"
}
function showusage()
print("usage: ./reader.lua [OPTION] ... path")
print("Read all the books on your E-Ink reader")
print("")
print("-p, --password=PASSWORD set password for reading PDF document")
print("-G, --gamma=GAMMA set gamma correction")
print(" (floating point notation, e.g. \"1.5\")")
print("-d, --debug start in debug mode")
print("-h, --help show this usage help")
print("")
print("If you give the name of a directory instead of a file path, a file")
print("chooser will show up and let you select a file")
print("")
print("If you don't pass any path, the last viewed document will be opened")
print("")
print("This software is licensed under the GPLv3.")
print("See http://github.com/hwhw/kindlepdfviewer for more info.")
return
end
optarg, optind = alt_getopt.get_opts(ARGV, "p:G:hg:dg:", longopts)
if optarg["h"] then
return showusage()
end
if not optarg["d"] then
DEBUG = function() end
end
if optarg["G"] ~= nil then
globalgamma = optarg["G"]
end
-- set up reader's setting: font
G_reader_settings = DocSettings:open(".reader")
fontmap = G_reader_settings:readSetting("fontmap")
if fontmap ~= nil then
Font.fontmap = fontmap
end
local last_file = G_reader_settings:readSetting("lastfile")
Screen:updateRotationMode()
Screen.native_rotation_mode = Screen.cur_rotation_mode
if ARGV[optind] then
if lfs.attributes(ARGV[optind], "mode") == "directory" then
showFileManager(ARGV[optind])
elseif lfs.attributes(ARGV[optind], "mode") == "file" then
showReader(ARGV[optind], optarg["p"])
end
UIManager:run()
elseif last_file and lfs.attributes(last_file, "mode") == "file" then
showReader(last_file, optarg["p"])
UIManager:run()
else
return showusage()
end
-- @TODO dirty workaround, find a way to force native system poll
-- screen orientation and upside down mode 09.03 2012
Screen:setRotationMode(Screen.native_rotation_mode)
input.closeAll()
if util.isEmulated()==0 then
os.execute("killall -cont cvm")
-- send double menu key press events to trigger screen refresh
os.execute("echo 'send 139' > /proc/keypad;echo 'send 139' > /proc/keypad")
end

View File

@@ -145,9 +145,9 @@ readerwindow = CenterContainer:new{
reader = ReaderUI:new{
dialog = readerwindow,
dimen = Geom:new{ w = Screen:getWidth() - 100, h = Screen:getHeight() - 100 },
document = DocumentRegistry:getProvider("test/2col.pdf")
--document = DocumentRegistry:getProvider("test/djvu3spec.djvu")
--document = DocumentRegistry:getProvider("./README.TXT")
document = DocumentRegistry:openDocument("test/2col.pdf")
--document = DocumentRegistry:openDocument("test/djvu3spec.djvu")
--document = DocumentRegistry:openDocument("./README.TXT")
}
readerwindow[1][1] = reader