file reorganisation

all lua frontend files are now in the frontend/ directory.
all old code is cleaned up.
pull/2/merge
HW 12 years ago
parent 2a2a0828c8
commit 9e531fc2db

@ -1,187 +0,0 @@
require "keys"
Keydef = {
keycode = nil,
modifier = nil,
descr = nil
}
function Keydef:_new(obj)
-- obj definition
obj = obj or {}
setmetatable(obj, self)
self.__index = self
self.__tostring=Keydef.tostring
return obj
end
function Keydef:new(keycode,modifier,descr)
obj = Keydef:_new()
obj.keycode = keycode
obj.modifier = modifier
obj.descr = descr
return obj
end
function Keydef:display()
return (self.modifier or "")..(self.descr or "")
end
function Keydef:tostring()
return ((self.modifier and self.modifier.."+") or "").."["..(self.keycode or "").."]"..(self.descr or "")
end
Command = {
keydef = nil,
keygroup = nil,
func = nil,
help = nil,
order = nil
}
function Command:_new(obj)
-- obj definition
obj = obj or {}
setmetatable(obj, self)
self.__index = self
self.__tostring=Command.tostring
return obj
end
function Command:new(keydef, func, help, keygroup, order)
obj = Command:_new()
obj.keydef = keydef
obj.func = func
obj.help = help
obj.keygroup = keygroup
obj.order = order
--debug("creating command: ["..tostring(keydef).."] keygroup:["..(keygroup or "").."] help:"..help)
return obj
end
function Command:tostring()
return tostring(self.keydef)..": "..(self.help or "<no help defined>")
end
Commands = {
map = {},
size = 0
}
function Commands:add(keycode,modifier,keydescr,help,func)
if type(keycode) == "table" then
for i=1,#keycode,1 do
local keydef = Keydef:new(keycode[i],modifier,keydescr)
self:_addImpl(keydef,help,func)
end
else
local keydef = Keydef:new(keycode,modifier,keydescr)
self:_addImpl(keydef,help,func)
end
end
function Commands:addGroup(keygroup,keys,help,func)
for _k,keydef in pairs(keys) do
self:_addImpl(keydef,help,func,keygroup)
end
end
--@TODO handle MOD_ANY 06.04 2012 (houqp)
function Commands:del(keycode, modifier, keydescr)
local keydef = nil
if not keydescr then
for k,v in pairs(self.map) do
if v.keydef.keycode == keycode
and v.keydef.modifier == modifier then
keydef = k
break
end
end -- EOF for
else
keydef = Keydef:new(keycode, modifier, keydescr)
end -- EOF if
self.map[keydef] = nil
end
function Commands:delGroup(keygroup)
if keygroup then
for k,v in pairs(self.map) do
if v.keygroup == keygroup then
self.map[k] = nil
end
end -- EOF for
end
end
function Commands:_addImpl(keydef,help,func,keygroup)
if keydef.modifier==MOD_ANY then
self:addGroup(keygroup or keydef.descr,{Keydef:new(keydef.keycode,nil), Keydef:new(keydef.keycode,MOD_SHIFT), Keydef:new(keydef.keycode,MOD_ALT)},help,func)
elseif keydef.modifier==MOD_SHIFT_OR_ALT then
self:addGroup(keygroup or (MOD_SHIFT..MOD_ALT..(keydef.descr or "")),{Keydef:new(keydef.keycode,MOD_SHIFT), Keydef:new(keydef.keycode,MOD_ALT)},help,func)
else
local command = self.map[keydef]
if command == nil then
self.size = self.size + 1
command = Command:new(keydef,func,help,keygroup,self.size)
self.map[keydef] = command
else
command.func = func
command.help = help
command.keygroup = keygroup
end
end
end
function Commands:get(keycode,modifier)
return self.map[Keydef:new(keycode, modifier)]
end
function Commands:getByKeydef(keydef)
return self.map[keydef]
end
function Commands:new(obj)
-- obj definition
obj = obj or {}
obj.map = {}
obj.size = 0
setmetatable(obj, self)
self.__index = self
-- payload
local mt = {}
mt.__index = function(table, key)
return rawget(table,(key.modifier or "").."@#@"..(key.keycode or ""))
end
mt.__newindex = function(table, key, value)
return rawset(table,(key.modifier or "").."@#@"..(key.keycode or ""),value)
end
setmetatable(obj.map, mt)
obj:add(KEY_INTO_SCREEN_SAVER, nil, "Slider",
"toggle screen saver",
function()
Screen:saveCurrentBB()
InfoMessage:show("Going into screensaver... ", 0)
Screen.kpv_rotation_mode = Screen.cur_rotation_mode
fb:setOrientation(Screen.native_rotation_mode)
util.sleep(1)
os.execute("killall -cont cvm")
end
)
obj:add(KEY_OUTOF_SCREEN_SAVER, nil, "Slider",
"toggle screen saver",
function()
util.usleep(1500000)
os.execute("killall -stop cvm")
fb:setOrientation(Screen.kpv_rotation_mode)
Screen:restoreFromSavedBB()
fb:refresh(0)
end
)
return obj
end

@ -1,456 +0,0 @@
require "font"
require "unireader"
require "inputbox"
require "selectmenu"
CREReader = UniReader:new{
pos = nil,
percent = 0,
gamma_index = 15,
font_face = nil,
line_space_percent = 100,
}
function CREReader:init()
self:addAllCommands()
self:adjustCreReaderCommands()
-- 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
-- open a CREngine supported file and its settings store
function CREReader:open(filename)
local ok
local file_type = string.lower(string.match(filename, ".+%.([^.]+)"))
-- these two format use the same css file
if file_type == "html" then
file_type = "htm"
end
local style_sheet = "./data/"..file_type..".css"
ok, self.doc = pcall(cre.openDocument, filename, style_sheet,
G_width, G_height)
if not ok then
return false, self.doc -- will contain error message
end
self.doc:setDefaultInterlineSpace(self.line_space_percent)
return true
end
----------------------------------------------------
-- setting related methods
----------------------------------------------------
function CREReader:loadSpecialSettings()
local font_face = self.settings:readSetting("font_face")
self.font_face = font_face or "FreeSerif"
self.doc:setFontFace(self.font_face)
local gamma_index = self.settings:readSetting("gamma_index")
self.gamma_index = gamma_index or self.gamma_index
cre.setGammaIndex(self.gamma_index)
local line_space_percent = self.settings:readSetting("line_space_percent")
self.line_space_percent = line_space_percent or self.line_space_percent
end
function CREReader:getLastPageOrPos()
local last_percent = self.settings:readSetting("last_percent")
if last_percent then
return math.floor((last_percent * self.doc:getFullHeight()) / 10000)
else
return 0
end
end
function CREReader:saveSpecialSettings()
self.settings:saveSetting("font_face", self.font_face)
self.settings:saveSetting("gamma_index", self.gamma_index)
self.settings:saveSetting("line_space_percent", self.line_space_percent)
end
function CREReader:saveLastPageOrPos()
self.settings:saveSetting("last_percent", self.percent)
end
----------------------------------------------------
-- render related methods
----------------------------------------------------
-- we don't need setzoom in CREReader
function CREReader:setzoom(page, preCache)
return
end
function CREReader:redrawCurrentPage()
self:goto(self.pos)
end
-- there is no zoom mode in CREReader
function CREReader:setGlobalZoomMode()
return
end
----------------------------------------------------
-- goto related methods
----------------------------------------------------
function CREReader:goto(pos, is_ignore_jump, pos_type)
local prev_xpointer = self.doc:getXPointer()
local width, height = G_width, G_height
if pos_type == "xpointer" then
self.doc:gotoXPointer(pos)
pos = self.doc:getCurrentPos()
else -- pos_type is position within document
pos = math.min(pos, self.doc:getFullHeight() - height)
pos = math.max(pos, 0)
self.doc:gotoPos(pos)
end
-- add to jump history, distinguish jump from normal page turn
-- NOTE:
-- even though we have called gotoPos() or gotoXPointer() previously,
-- self.pos hasn't been updated yet here, so we can still make use of it.
if not is_ignore_jump then
if self.pos and math.abs(self.pos - pos) > height then
self:addJump(prev_xpointer)
end
end
self.doc:drawCurrentPage(self.nulldc, fb.bb)
debug("## self.show_overlap "..self.show_overlap)
if self.show_overlap < 0 then
fb.bb:dimRect(0,0, width, -self.show_overlap)
elseif self.show_overlap > 0 then
fb.bb:dimRect(0,height - self.show_overlap, width, self.show_overlap)
end
self.show_overlap = 0
if self.rcount >= self.rcountmax then
debug("full refresh")
self.rcount = 0
fb:refresh(0)
else
debug("partial refresh")
self.rcount = self.rcount + 1
fb:refresh(1)
end
self.pos = pos
self.pageno = self.doc:getCurrentPage()
self.percent = self.doc:getCurrentPercent()
end
function CREReader:gotoPercent(percent)
self:goto(percent * self.doc:getFullHeight() / 10000)
end
function CREReader:gotoTocEntry(entry)
self:goto(entry.xpointer, nil, "xpointer")
end
function CREReader:nextView()
self.show_overlap = -self.pan_overlap_vertical
return self.pos + G_height - self.pan_overlap_vertical
end
function CREReader:prevView()
self.show_overlap = self.pan_overlap_vertical
return self.pos - G_height + self.pan_overlap_vertical
end
----------------------------------------------------
-- jump history related methods
----------------------------------------------------
function CREReader:isSamePage(p1, p2)
return self.doc:getPageFromXPointer(p1) == self.doc:getPageFromXPointer(p2)
end
function CREReader:showJumpHist()
local menu_items = {}
for k,v in ipairs(self.jump_history) do
if k == self.jump_history.cur then
cur_sign = "*(Cur) "
else
cur_sign = ""
end
table.insert(menu_items,
cur_sign..v.datetime.." -> Page "
..self.doc:getPageFromXPointer(v.page).." "..v.notes)
end
if #menu_items == 0 then
showInfoMsgWithDelay(
"No jump history found.", 2000, 1)
else
-- if cur points to head, draw entry for current page
if self.jump_history.cur > #self.jump_history then
table.insert(menu_items,
"Current Page "..self.pageno)
end
jump_menu = SelectMenu:new{
menu_title = "Jump History",
item_array = menu_items,
}
item_no = jump_menu:choose(0, fb.bb:getHeight())
if item_no and item_no <= #self.jump_history then
local jump_item = self.jump_history[item_no]
self.jump_history.cur = item_no
self:goto(jump_item.page, true, "xpointer")
else
self:redrawCurrentPage()
end
end
end
----------------------------------------------------
-- bookmarks related methods
----------------------------------------------------
function CREReader:showBookMarks()
local menu_items = {}
-- build menu items
for k,v in ipairs(self.bookmarks) do
table.insert(menu_items,
"Page "..self.doc:getPageFromXPointer(v.page)
.." "..v.notes.." @ "..v.datetime)
end
if #menu_items == 0 then
showInfoMsgWithDelay(
"No bookmark found.", 2000, 1)
else
toc_menu = SelectMenu:new{
menu_title = "Bookmarks",
item_array = menu_items,
}
item_no = toc_menu:choose(0, fb.bb:getHeight())
if item_no then
self:goto(self.bookmarks[item_no].page, nil, "xpointer")
else
self:redrawCurrentPage()
end
end
end
----------------------------------------------------
-- TOC related methods
----------------------------------------------------
function CREReader:getTocTitleByPage(page_or_xpoint)
local page = 1
-- tranform xpointer to page
if type(page_or_xpoint) == "string" then
page = self.doc:getPageFromXPointer(page_or_xpoint)
else
page = page_or_xpoint
end
return self:_getTocTitleByPage(page)
end
function CREReader:getTocTitleOfCurrentPage()
return self:getTocTitleByPage(self.doc:getXPointer())
end
----------------------------------------------------
-- menu related methods
----------------------------------------------------
-- used in CREReader:showMenu()
function CREReader:_drawReadingInfo()
local ypos = G_height - 50
local load_percent = self.percent/100
fb.bb:paintRect(0, ypos, G_width, 50, 0)
ypos = ypos + 15
local face = Font:getFace("rifont", 22)
local cur_section = self:getTocTitleOfCurrentPage()
if cur_section ~= "" then
cur_section = "Section: "..cur_section
end
renderUtf8Text(fb.bb, 10, ypos+6, face,
"Position: "..load_percent.."%".." "..cur_section, true)
ypos = ypos + 15
blitbuffer.progressBar(fb.bb, 10, ypos, G_width - 20, 15,
5, 4, load_percent/100, 8)
end
function CREReader:adjustCreReaderCommands()
-- delete commands
self.commands:delGroup("[joypad]")
self.commands:del(KEY_G, nil, "G")
self.commands:del(KEY_J, MOD_SHIFT, "J")
self.commands:del(KEY_K, MOD_SHIFT, "K")
self.commands:del(KEY_Z, nil, "Z")
self.commands:del(KEY_Z, MOD_SHIFT, "Z")
self.commands:del(KEY_Z, MOD_ALT, "Z")
self.commands:del(KEY_A, nil, "A")
self.commands:del(KEY_A, MOD_SHIFT, "A")
self.commands:del(KEY_A, MOD_ALT, "A")
self.commands:del(KEY_S, nil, "S")
self.commands:del(KEY_S, MOD_SHIFT, "S")
self.commands:del(KEY_S, MOD_ALT, "S")
self.commands:del(KEY_D, nil, "D")
self.commands:del(KEY_D, MOD_SHIFT, "D")
self.commands:del(KEY_D, MOD_ALT, "D")
self.commands:del(KEY_X, nil, "X")
self.commands:del(KEY_F, MOD_SHIFT, "F")
self.commands:del(KEY_F, MOD_ALT, "F")
self.commands:del(KEY_N, nil, "N") -- highlight
self.commands:del(KEY_N, MOD_SHIFT, "N") -- show highlights
-- overwrite commands
self.commands:addGroup(MOD_SHIFT.."< >",{
Keydef:new(KEY_PGBCK,MOD_SHIFT),Keydef:new(KEY_PGFWD,MOD_SHIFT),
Keydef:new(KEY_LPGBCK,MOD_SHIFT),Keydef:new(KEY_LPGFWD,MOD_SHIFT)},
"increase/decrease font size",
function(self)
local delta = 1
local change = "increase"
if keydef.keycode == KEY_PGBCK or keydef.keycode == KEY_LPGBCK then
delta = -1
change = "decrease"
end
InfoMessage:show(change.." font size", 0)
self.doc:zoomFont(delta)
self:redrawCurrentPage()
end
)
self.commands:addGroup(MOD_ALT.."< >",{
Keydef:new(KEY_PGBCK,MOD_ALT),Keydef:new(KEY_PGFWD,MOD_ALT),
Keydef:new(KEY_LPGBCK,MOD_ALT),Keydef:new(KEY_LPGFWD,MOD_ALT)},
"increase/decrease line spacing",
function(self)
if keydef.keycode == KEY_PGBCK or keydef.keycode == KEY_LPGBCK then
self.line_space_percent = self.line_space_percent - 10
if self.line_space_percent < 100 then
self.line_space_percent = 100
end
else
self.line_space_percent = self.line_space_percent + 10
if self.line_space_percent > 200 then
self.line_space_percent = 200
end
end
InfoMessage:show("line spacing "..self.line_space_percent.."%", 0)
debug("line spacing set to", self.line_space_percent)
self.doc:setDefaultInterlineSpace(self.line_space_percent)
self:redrawCurrentPage()
end
)
local numeric_keydefs = {}
for i=1,10 do
numeric_keydefs[i]=Keydef:new(KEY_1+i-1, nil, tostring(i%10))
end
self.commands:addGroup("[1..0]", numeric_keydefs,
"jump to <key>*10% of document",
function(self, keydef)
debug('jump to position: '..
math.floor(self.doc:getFullHeight()*(keydef.keycode-KEY_1)/9)..
'/'..self.doc:getFullHeight())
self:goto(math.floor(self.doc:getFullHeight()*(keydef.keycode-KEY_1)/9))
end
)
self.commands:add(KEY_F, nil, "F",
"change document font",
function(self)
Screen:saveCurrentBB()
local face_list = cre.getFontFaces()
local fonts_menu = SelectMenu:new{
menu_title = "Fonts Menu",
item_array = face_list,
}
local item_no = fonts_menu:choose(0, G_height)
debug(face_list[item_no])
if item_no then
Screen:restoreFromSavedBB()
self.doc:setFontFace(face_list[item_no])
self.font_face = face_list[item_no]
InfoMessage:show("Redrawing with "..face_list[item_no], 0)
end
self:redrawCurrentPage()
end
)
self.commands:add(KEY_F, MOD_ALT, "F",
"Toggle font bolder attribute",
function(self)
self.doc:toggleFontBolder()
self:redrawCurrentPage()
end
)
self.commands:add(KEY_B, MOD_ALT, "B",
"add bookmark to current page",
function(self)
ok = self:addBookmark(self.doc:getXPointer())
if not ok then
showInfoMsgWithDelay("Page already marked!", 2000, 1)
else
showInfoMsgWithDelay("Page marked.", 2000, 1)
end
end
)
self.commands:add(KEY_BACK, nil, "Back",
"go backward in jump history",
function(self)
local prev_jump_no = self.jump_history.cur - 1
if prev_jump_no >= 1 then
self.jump_history.cur = prev_jump_no
self:goto(self.jump_history[prev_jump_no].page, true, "xpointer")
else
showInfoMsgWithDelay("Already first jump!", 2000, 1)
end
end
)
self.commands:add(KEY_BACK, MOD_SHIFT, "Back",
"go forward in jump history",
function(self)
local next_jump_no = self.jump_history.cur + 1
if next_jump_no <= #self.jump_history then
self.jump_history.cur = next_jump_no
self:goto(self.jump_history[next_jump_no].page, true, "xpointer")
else
showInfoMsgWithDelay("Already last jump!", 2000, 1)
end
end
)
self.commands:addGroup("vol-/+",
{Keydef:new(KEY_VPLUS,nil), Keydef:new(KEY_VMINUS,nil)},
"decrease/increase gamma",
function(self, keydef)
local delta = 1
if keydef.keycode == KEY_VMINUS then
delta = -1
end
cre.setGammaIndex(self.gamma_index+delta)
self.gamma_index = cre.getGammaIndex()
self:redrawCurrentPage()
end
)
self.commands:add(KEY_FW_UP, nil, "joypad up",
"pan "..self.shift_y.." pixels upwards",
function(self)
self:goto(self.pos - self.shift_y)
end
)
self.commands:add(KEY_FW_DOWN, nil, "joypad down",
"pan "..self.shift_y.." pixels downwards",
function(self)
self:goto(self.pos + self.shift_y)
end
)
end

@ -1,98 +0,0 @@
require "unireader"
DJVUReader = UniReader:new{}
-- open a DJVU file and its settings store
-- DJVU does not support password yet
function DJVUReader:open(filename)
local ok
ok, self.doc = pcall(djvu.openDocument, filename, self.cache_document_size)
if not ok then
return ok, self.doc -- this will be the error message instead
end
return ok
end
function DJVUReader:init()
self:addAllCommands()
self:adjustDjvuReaderCommand()
end
function DJVUReader:adjustDjvuReaderCommand()
self.commands:del(KEY_J, MOD_SHIFT, "J")
self.commands:del(KEY_K, MOD_SHIFT, "K")
end
----------------------------------------------------
-- highlight support
----------------------------------------------------
function DJVUReader:getText(pageno)
return self.doc:getPageText(pageno)
end
----------------------------------------------------
-- In djvulibre library, some coordinates starts from
-- lower left conner, i.e. y is upside down in kpv's
-- coordinate. So y0 should be taken with special care.
----------------------------------------------------
function DJVUReader:zoomedRectCoordTransform(x0, y0, x1, y1)
local x,y = self:screenOffset()
return
x0 * self.globalzoom + x,
self.cur_full_height - (y1 * self.globalzoom) + y,
(x1 - x0) * self.globalzoom,
(y1 - y0) * self.globalzoom
end
-- make sure at least part of the box can be seen in next/previous view
-- @FIXME only works in FIT_TO_CONTENT_WIDTH mode 21.04 2012 (houqp)
-- @TODO use zoomedRectCoordTransform in unireader, no need to overwrite
-- it in here.
function DJVUReader:_isBoxInNextView(box)
return self.cur_full_height - (box.y0 * self.globalzoom) > -self.offset_y + G_height
end
function DJVUReader:_isBoxInPrevView(box)
return self.cur_full_height - (box.y1 * self.globalzoom) < -self.offset_y
end
-- y axel in djvulibre starts from bottom
function DJVUReader:_isEntireWordInScreenHeightRange(w)
return (w ~= nil) and
(self.cur_full_height - (w.y1 * self.globalzoom) >=
-self.offset_y) and
(self.cur_full_height - (w.y0 * self.globalzoom) <=
-self.offset_y + G_height)
end
-- y axel in djvulibre starts from bottom
function DJVUReader:_isEntireLineInScreenHeightRange(l)
return (l ~= nil) and
(self.cur_full_height - (l.y1 * self.globalzoom) >=
-self.offset_y) and
(self.cur_full_height - (l.y0 * self.globalzoom) <=
-self.offset_y + G_height)
end
-- y axel in djvulibre starts from bottom
function DJVUReader:_isWordInScreenRange(w)
if not w then
return false
end
is_entire_word_out_of_screen_height =
(self.cur_full_height - (w.y0 * self.globalzoom) <=
-self.offset_y)
or (self.cur_full_height - (w.y1 * self.globalzoom) >=
-self.offset_y + G_height)
is_entire_word_out_of_screen_width =
(w.x0 * self.globalzoom >= -self.offset_x + G_width
or w.x1 * self.globalzoom <= -self.offset_x)
return (not is_entire_word_out_of_screen_height) and
(not is_entire_word_out_of_screen_width)
end

@ -1,243 +0,0 @@
require "rendertext"
require "keys"
require "graphics"
require "font"
require "filesearcher"
require "inputbox"
require "selectmenu"
FileChooser = {
-- Class vars:
-- spacing between lines
spacing = 40,
-- state buffer
dirs = nil,
files = nil,
items = 0,
path = "",
page = 1,
current = 1,
oldcurrent = 0,
exception_message = nil
}
function getAbsolutePath(aPath)
local abs_path
if not aPath then
abs_path = aPath
elseif aPath:match('^//') then
abs_path = aPath:sub(2)
elseif aPath:match('^/') then
abs_path = aPath
elseif #aPath == 0 then
abs_path = '/'
else
local curr_dir = lfs.currentdir()
abs_path = aPath
if lfs.chdir(aPath) then
abs_path = lfs.currentdir()
lfs.chdir(curr_dir)
end
--debug("rel: '"..aPath.."' abs:'"..abs_path.."'")
end
return abs_path
end
function FileChooser:readDir()
self.dirs = {}
self.files = {}
for f in lfs.dir(self.path) do
if lfs.attributes(self.path.."/"..f, "mode") == "directory" and f ~= "." and not (f==".." and self.path=="/") and not string.match(f, "^%.[^.]") then
--debug(self.path.." -> adding: '"..f.."'")
table.insert(self.dirs, f)
else
local file_type = string.lower(string.match(f, ".+%.([^.]+)") or "")
if file_type == "djvu"
or file_type == "pdf" or file_type == "xps" or file_type == "cbz"
or file_type == "epub" or file_type == "txt" or file_type == "rtf"
or file_type == "htm" or file_type == "html" or file_type == "mobi"
or file_type == "fb2" or file_type == "chm" or file_type == "doc"
or file_type == "zip" then
table.insert(self.files, f)
end
end
end
--@TODO make sure .. is sortted to the first item 16.02 2012
table.sort(self.dirs)
table.sort(self.files)
end
function FileChooser:setPath(newPath)
local curr_path = self.path
self.path = getAbsolutePath(newPath)
local readdir_ok, exc = pcall(self.readDir,self)
if(not readdir_ok) then
debug("readDir error: "..tostring(exc))
self.exception_message = exc
return self:setPath(curr_path)
else
self.items = #self.dirs + #self.files
if self.items == 0 then
return nil
end
self.page = 1
self.current = 1
return true
end
end
function FileChooser:choose(ypos, height)
local perpage = math.floor(height / self.spacing) - 2
local pagedirty = true
local markerdirty = false
local prevItem = function ()
if self.current == 1 then
if self.page > 1 then
self.current = perpage
self.page = self.page - 1
pagedirty = true
end
else
self.current = self.current - 1
markerdirty = true
end
end
local nextItem = function ()
if self.current == perpage then
if self.page < (self.items / perpage) then
self.current = 1
self.page = self.page + 1
pagedirty = true
end
else
if self.page ~= math.floor(self.items / perpage) + 1
or self.current + (self.page-1)*perpage < self.items then
self.current = self.current + 1
markerdirty = true
end
end
end
while true do
local cface = Font:getFace("cfont", 25)
local fface = Font:getFace("ffont", 16)
if pagedirty then
fb.bb:paintRect(0, ypos, fb.bb:getWidth(), height, 0)
local c
for c = 1, perpage do
local i = (self.page - 1) * perpage + c
if i <= #self.dirs then
-- resembles display in midnight commander: adds "/" prefix for directories
renderUtf8Text(fb.bb, 39, ypos + self.spacing*c, cface, "/", true)
renderUtf8Text(fb.bb, 50, ypos + self.spacing*c, cface, self.dirs[i], true)
elseif i <= self.items then
renderUtf8Text(fb.bb, 50, ypos + self.spacing*c, cface, self.files[i-#self.dirs], true)
end
end
all_page = math.ceil(self.items/perpage)
renderUtf8Text(fb.bb, 5, ypos + self.spacing * perpage + 42, fface,
"Page "..self.page.." of "..all_page, true)
local msg = self.exception_message and self.exception_message:match("[^%:]+:%d+: (.*)") or "Path: "..self.path
self.exception_message = nil
renderUtf8Text(fb.bb, 5, ypos + self.spacing * (perpage+1) + 27, fface, msg, true)
markerdirty = true
end
if markerdirty then
if not pagedirty then
if self.oldcurrent > 0 then
fb.bb:paintRect(30, ypos + self.spacing*self.oldcurrent + 10, fb.bb:getWidth() - 60, 3, 0)
fb:refresh(1, 30, ypos + self.spacing*self.oldcurrent + 10, fb.bb:getWidth() - 60, 3)
end
end
fb.bb:paintRect(30, ypos + self.spacing*self.current + 10, fb.bb:getWidth() - 60, 3, 15)
if not pagedirty then
fb:refresh(1, 30, ypos + self.spacing*self.current + 10, fb.bb:getWidth() - 60, 3)
end
self.oldcurrent = self.current
markerdirty = false
end
if pagedirty then
fb:refresh(0, 0, ypos, fb.bb:getWidth(), height)
pagedirty = false
end
local ev = input.saveWaitForEvent()
--debug("key code:"..ev.code)
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
if ev.code == KEY_FW_UP then
prevItem()
elseif ev.code == KEY_FW_DOWN then
nextItem()
elseif ev.code == KEY_F then -- invoke fontchooser menu
local fonts_menu = SelectMenu:new{
menu_title = "Fonts Menu",
item_array = Font:getFontList(),
}
local re, font = fonts_menu:choose(0, height)
if re then
Font.fontmap["cfont"] = font
Font:update()
end
pagedirty = true
elseif ev.code == KEY_S then -- invoke search input
keywords = InputBox:input(height-100, 100, "Search:")
if keywords then
-- call FileSearcher
--[[
This might looks a little bit dirty for using callback.
But I cannot come up with a better solution for renewing
the height argument according to screen rotation mode.
The callback might also be useful for calling system
settings menu in the future.
--]]
return nil, function()
InfoMessage:show("Searching...",0)
FileSearcher:init( self.path )
FileSearcher:choose(keywords)
end
end
pagedirty = true
elseif ev.code == KEY_PGFWD or ev.code == KEY_LPGFWD then
if self.page < (self.items / perpage) then
if self.current + self.page*perpage > self.items then
self.current = self.items - self.page*perpage
end
self.page = self.page + 1
pagedirty = true
else
self.current = self.items - (self.page-1)*perpage
markerdirty = true
end
elseif ev.code == KEY_PGBCK or ev.code == KEY_LPGBCK then
if self.page > 1 then
self.page = self.page - 1
pagedirty = true
else
self.current = 1
markerdirty = true
end
elseif ev.code == KEY_ENTER or ev.code == KEY_FW_PRESS then
local newdir = self.dirs[perpage*(self.page-1)+self.current]
if newdir == ".." then
local path = string.gsub(self.path, "(.*)/[^/]+/?$", "%1")
self:setPath(path)
elseif newdir then
local path = self.path.."/"..newdir
self:setPath(path)
else
return self.path.."/"..self.files[perpage*(self.page-1)+self.current - #self.dirs]
end
pagedirty = true
elseif ev.code == KEY_BACK or ev.code == KEY_HOME then
return nil
end
end
end
end

@ -1,318 +0,0 @@
require "rendertext"
require "keys"
require "graphics"
require "font"
FileSearcher = {
-- title height
title_H = 45,
-- spacing between lines
spacing = 40,
-- foot height
foot_H = 27,
-- state buffer
dirs = {},
files = {},
result = {},
items = 0,
page = 0,
current = 1,
oldcurrent = 1,
}
function FileSearcher:readDir()
self.dirs = {self.path}
self.files = {}
while #self.dirs ~= 0 do
new_dirs = {}
-- handle each dir
for __, d in pairs(self.dirs) do
-- handle files in d
for f in lfs.dir(d) do
local file_type = string.lower(string.match(f, ".+%.([^.]+)") or "")
if lfs.attributes(d.."/"..f, "mode") == "directory"
and f ~= "." and f~= ".." and not string.match(f, "^%.[^.]") then
table.insert(new_dirs, d.."/"..f)
elseif file_type == "djvu" or file_type == "pdf"
or file_type == "xps" or file_type == "cbz"
or file_type == "epub" or file_type == "txt"
or file_type == "rtf" or file_type == "htm"
or file_type == "html" or file_type == "mobi"
or file_type == "fb2" or file_type == "chm"
or file_type == "doc" or file_type == "zip" then
file_entry = {dir=d, name=f,}
table.insert(self.files, file_entry)
--debug("file:"..d.."/"..f)
end
end
end
self.dirs = new_dirs
end
end
function FileSearcher:setPath(newPath)
self.path = newPath
self:readDir()
self.items = #self.files
--@TODO check none found 19.02 2012
if self.items == 0 then
return nil
end
self.page = 1
self.current = 1
return true
end
function FileSearcher:setSearchResult(keywords)
self.result = {}
if keywords == " " then -- one space to show all files
self.result = self.files
else
for __,f in pairs(self.files) do
if string.find(string.lower(f.name), keywords) then
table.insert(self.result, f)
end
end
end
self.keywords = keywords
self.items = #self.result
self.page = 1
self.current = 1
end
function FileSearcher:init(search_path)
if search_path then
self:setPath(search_path)
else
self:setPath("/mnt/us/documents")
end
self:addAllCommands()
end
function FileSearcher:prevItem()
if self.current == 1 then
if self.page > 1 then
self.current = self.perpage
self.page = self.page - 1
self.pagedirty = true
end
else
self.current = self.current - 1
self.markerdirty = true
end
end
function FileSearcher:nextItem()
if self.current == self.perpage then
if self.page < (self.items / self.perpage) then
self.current = 1
self.page = self.page + 1
self.pagedirty = true
end
else
if self.page ~= math.floor(self.items / self.perpage) + 1
or self.current + (self.page-1)*self.perpage < self.items then
self.current = self.current + 1
self.markerdirty = true
end
end
end
function FileSearcher:addAllCommands()
self.commands = Commands:new{}
self.commands:add(KEY_FW_UP, nil, "joypad up",
"goto previous item",
function(self)
self:prevItem()
end
)
self.commands:add(KEY_FW_DOWN, nil, "joypad down",
"goto next item",
function(self)
self:nextItem()
end
)
self.commands:add({KEY_PGFWD, KEY_LPGFWD}, nil, ">",
"next page",
function(self)
if self.page < (self.items / self.perpage) then
if self.current + self.page*self.perpage > self.items then
self.current = self.items - self.page*self.perpage
end
self.page = self.page + 1
self.pagedirty = true
else
self.current = self.items - (self.page-1)*self.perpage
self.markerdirty = true
end
end
)
self.commands:add({KEY_PGBCK, KEY_LPGBCK}, nil, "<",
"previous page",
function(self)
if self.page > 1 then
self.page = self.page - 1
self.pagedirty = true
else
self.current = 1
self.markerdirty = true
end
end
)
self.commands:add(KEY_S, nil, "S",
"invoke search inputbox",
function(self)
old_keywords = self.keywords
self.keywords = InputBox:input(G_height - 100, 100,
"Search:", old_keywords)
if self.keywords then
self:setSearchResult(self.keywords)
else
self.keywords = old_keywords
end
self.pagedirty = true
end
)
self.commands:add(KEY_F, nil, "F",
"font menu",
function(self)
local fonts_menu = SelectMenu:new{
menu_title = "Fonts Menu",
item_array = Font:getFontList(),
}
local re, font = fonts_menu:choose(0, G_height)
if re then
Font.fontmap["cfont"] = font
Font:update()
end
self.pagedirty = true
end
)
self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "",
"select item",
function(self)
file_entry = self.result[self.perpage*(self.page-1)+self.current]
file_full_path = file_entry.dir .. "/" .. file_entry.name
openFile(file_full_path)
--reset height and item index if screen has been rotated
local item_no = self.perpage * (self.page - 1) + self.current
self.perpage = math.floor(G_height / self.spacing) - 2
self.current = item_no % self.perpage
self.page = math.floor(item_no / self.perpage) + 1
self.pagedirty = true
end
)
self.commands:add({KEY_BACK, KEY_HOME}, nil, "",
"back to file browser",
function(self)
return "break"
end
)
end
function FileSearcher:choose(keywords)
self.perpage = math.floor(G_height / self.spacing) - 2
self.pagedirty = true
self.markerdirty = false
-- if given keywords, set new result according to keywords.
-- Otherwise, display the previous search result.
if keywords then
self:setSearchResult(keywords)
end
while true do
local cface = Font:getFace("cfont", 22)
local tface = Font:getFace("tfont", 25)
local fface = Font:getFace("ffont", 16)
if self.pagedirty then
self.markerdirty = true
fb.bb:paintRect(0, 0, G_width, G_height, 0)
-- draw menu title
renderUtf8Text(fb.bb, 30, 0 + self.title_H, tface,
"Search Result for: "..self.keywords, true)
-- draw results
local c
if self.items == 0 then -- nothing found
y = self.title_H + self.spacing * 2
renderUtf8Text(fb.bb, 20, y, cface,
"Sorry, no match found.", true)
renderUtf8Text(fb.bb, 20, y + self.spacing, cface,
"Please try a different keyword.", true)
self.markerdirty = false
else -- found something, draw it
for c = 1, self.perpage do
local i = (self.page - 1) * self.perpage + c
if i <= self.items then
y = self.title_H + (self.spacing * c)
renderUtf8Text(fb.bb, 50, y, cface,
self.result[i].name, true)
end
end
end
-- draw footer
y = self.title_H + (self.spacing * self.perpage) + self.foot_H
x = (G_width / 2) - 50
all_page = math.ceil(self.items/self.perpage)
renderUtf8Text(fb.bb, x, y, fface,
"Page "..self.page.." of "..all_page, true)
end
if self.markerdirty then
if not self.pagedirty then
if self.oldcurrent > 0 then
y = self.title_H + (self.spacing * self.oldcurrent) + 10
fb.bb:paintRect(30, y, G_width - 60, 3, 0)
fb:refresh(1, 30, y, G_width - 60, 3)
end
end
-- draw new marker line
y = self.title_H + (self.spacing * self.current) + 10
fb.bb:paintRect(30, y, G_width - 60, 3, 15)
if not self.pagedirty then
fb:refresh(1, 30, y, G_width - 60, 3)
end
self.oldcurrent = self.current
self.markerdirty = false
end
if self.pagedirty then
fb:refresh(0)
self.pagedirty = false
end
local ev = input.saveWaitForEvent()
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
keydef = Keydef:new(ev.code, getKeyModifier())
debug("key pressed: "..tostring(keydef))
command = self.commands:getByKeydef(keydef)
if command ~= nil then
debug("command to execute: "..tostring(command))
ret_code = command.func(self, keydef)
else
debug("command not found: "..tostring(command))
end
if ret_code == "break" then
break
end
if self.selected_item ~= nil then
debug("# selected "..self.selected_item)
return self.selected_item
end
end -- if
end -- while true
return nil
end

@ -95,7 +95,7 @@ end
require "cache"
require "geometry"
require "ui/geometry"
PdfDocument = Document:new{

@ -1,6 +1,5 @@
require "widget"
require "font"
require "commands"
require "ui/widget"
require "ui/font"
--[[
Wrapper Widget that manages focus for a whole dialog

@ -1,3 +1,4 @@
require "settings" -- for debug()
Font = {
fontmap = {

@ -1,4 +1,4 @@
require "event"
require "ui/event"
-- constants from <linux/input.h>
EV_KEY = 1

@ -1,5 +1,3 @@
require "ui"
ReaderView = WidgetContainer:new{
document = nil,

@ -1,9 +1,9 @@
require "ui"
require "readerview"
require "readerzooming"
require "readerpanning"
require "readerrotation"
require "readerpaging"
require "ui/ui"
require "ui/reader/readerview"
require "ui/reader/readerzooming"
require "ui/reader/readerpanning"
require "ui/reader/readerrotation"
require "ui/reader/readerpaging"
--[[
This is an abstraction for a reader interface

@ -1,8 +1,8 @@
require "geometry"
require "inputevent"
require "widget"
require "screen"
require "dialog"
require "ui/geometry"
require "ui/inputevent"
require "ui/widget"
require "ui/screen"
require "ui/dialog"
require "settings" -- for debug(), TODO: put debug() somewhere else

@ -1,9 +1,9 @@
require "rendertext"
require "graphics"
require "image"
require "event"
require "inputevent"
require "font"
require "ui/rendertext"
require "ui/graphics"
require "ui/image"
require "ui/event"
require "ui/inputevent"
require "ui/font"
--[[
This is a generic Widget interface

@ -1,128 +0,0 @@
require "rendertext"
require "keys"
require "graphics"
require "font"
require "inputbox"
require "selectmenu"
require "commands"
HelpPage = {
-- Other Class vars:
-- spacing between lines
spacing = 25,
-- state buffer
commands = nil,
items = 0,
page = 1,
-- font for displaying keys
fsize = 20,
face = Font:getFace("hpkfont", 20),
-- font for displaying help messages
hfsize = 20,
hface = Font:getFace("hfont", 20),
-- font for paging display
ffsize = 15,
fface = Font:getFace("pgfont", 15)
}
-- Other Class vars:
function HelpPage:show(ypos, height, commands)
self.commands = {}
self.items = 0
local keys = {}
for k,v in pairs(commands.map) do
local key = v.keygroup or v.keydef:display()
--debug("order: "..v.order.." command: "..tostring(v.keydef).." - keygroup:"..(v.keygroup or "nil").." -keys[key]:"..(keys[key] or "nil"))
if keys[key] == nil then
keys[key] = 1
table.insert(self.commands,{shortcut=key,help=v.help,order=v.order})
self.items = self.items + 1
end
end
table.sort(self.commands,function(w1,w2) return w1.order<w2.order end)
local face_height, face_ascender = self.face.ftface:getHeightAndAscender()
--local hface_height, hface_ascender = self.hface.ftface:getHeightAndAscender()
local fface_height, fface_ascender = self.fface.ftface:getHeightAndAscender()
--debug(face_height.."-"..face_ascender)
--debug(fface_height.."-"..fface_ascender)
face_height = math.ceil(face_height)
face_ascender = math.ceil(face_ascender)
fface_height = math.ceil(fface_height)
fface_ascender = math.ceil(fface_ascender)
local spacing = face_height + 5
local perpage = math.floor( (height - ypos - 1 * (fface_height + 5)) / spacing )
local is_pagedirty = true
while true do
if is_pagedirty then
fb.bb:paintRect(0, ypos, fb.bb:getWidth(), height, 0)
local c
local max_x = 0
for c = 1, perpage do
local x = 5
local i = (self.page - 1) * perpage + c
if i <= self.items then
local key = self.commands[i].shortcut
for _k,aMod in pairs(MOD_TABLE) do
local modStart, modEnd = key:find(aMod.v)
debug("key:"..key.." v:"..aMod.v.." d:"..aMod.d.." modstart:"..(modStart or "nil"))
if(modStart ~= nil) then
key = key:sub(1,modStart-1)..key:sub(modEnd+1)
local box = sizeUtf8Text( x, fb.bb:getWidth(), self.face, aMod.d, true)
fb.bb:paintRect(x, ypos + spacing*c - box.y_top, box.x, box.y_top + box.y_bottom, 4)
local pen_x = renderUtf8Text(fb.bb, x, ypos + spacing*c, self.face, aMod.d.." + ", true)
x = x + pen_x
max_x = math.max(max_x, pen_x)
end
end
debug("key:"..key)
local box = sizeUtf8Text( x, fb.bb:getWidth(), self.face, key , true)
fb.bb:paintRect(x, ypos + spacing*c - box.y_top, box.x, box.y_top + box.y_bottom, 4)
local pen_x = renderUtf8Text(fb.bb, x, ypos + spacing*c, self.face, key, true)
x = x + pen_x
max_x = math.max(max_x, x)
end
end
for c = 1, perpage do
local i = (self.page - 1) * perpage + c
if i <= self.items then
renderUtf8Text(fb.bb, max_x + 20, ypos + spacing*c, self.hface, self.commands[i].help, true)
end
end
renderUtf8Text(fb.bb, 5, height - fface_height + fface_ascender - 5, self.fface,
"Page "..self.page.." of "..math.ceil(self.items / perpage).." - Back to close this page", true)
end
if is_pagedirty then
fb:refresh(0, 0, ypos, fb.bb:getWidth(), height)
is_pagedirty = false
end
local ev = input.saveWaitForEvent()
--debug("key code:"..ev.code)
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then
if ev.code == KEY_PGFWD or ev.code == KEY_LPGFWD then
if self.page < (self.items / perpage) then
self.page = self.page + 1
is_pagedirty = true
end
elseif ev.code == KEY_PGBCK or ev.code == KEY_LPGBCK then
if self.page > 1 then
self.page = self.page - 1
is_pagedirty = true
end
elseif ev.code == KEY_BACK or ev.code == KEY_HOME then
return nil
end
end
end
end

@ -1,402 +0,0 @@
require "font"
require "rendertext"
require "keys"
require "graphics"
----------------------------------------------------
-- General inputbox
----------------------------------------------------
InputBox = {
-- Class vars:
h = 100,
input_slot_w = nil,
input_start_x = 145,
input_start_y = nil,
input_cur_x = nil, -- points to the start of next input pos
input_bg = 0,
input_string = "",
shiftmode = false,
altmode = false,
cursor = nil,
-- font for displaying input content
-- we have to use mono here for better distance controlling
face = Font:getFace("infont", 25),
fheight = 25,
fwidth = 15,
commands = nil,
initialized = false,
}
function InputBox:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function InputBox:init()
if not self.initialized then
self:addAllCommands()
self.initialized = true
end
end
function InputBox:refreshText()
-- clear previous painted text
fb.bb:paintRect(140, self.input_start_y-19,
self.input_slot_w, self.fheight, self.input_bg)
-- paint new text
renderUtf8Text(fb.bb, self.input_start_x, self.input_start_y,
self.face,
self.input_string, 0)
end
function InputBox:addChar(char)
self.cursor:clear()
-- draw new text
local cur_index = (self.cursor.x_pos + 3 - self.input_start_x)
/ self.fwidth
self.input_string = self.input_string:sub(1, cur_index)..char..
self.input_string:sub(cur_index+1)
self:refreshText()
self.input_cur_x = self.input_cur_x + self.fwidth
-- draw new cursor
self.cursor:moveHorizontal(self.fwidth)
self.cursor:draw()
fb:refresh(1, self.input_start_x-5, self.input_start_y-25,
self.input_slot_w, self.h-25)
end
function InputBox:delChar()
if self.input_start_x == self.input_cur_x then
return
end
local cur_index = (self.cursor.x_pos + 3 - self.input_start_x)
/ self.fwidth
if cur_index == 0 then return end
self.cursor:clear()
-- draw new text
self.input_string = self.input_string:sub(1, cur_index-1)..
self.input_string:sub(cur_index+1, -1)
self:refreshText()
self.input_cur_x = self.input_cur_x - self.fwidth
--fill last character with blank rectangle
fb.bb:paintRect(self.input_cur_x, self.input_start_y-19,
self.fwidth, self.fheight, self.input_bg)
fb:refresh(1, self.input_cur_x, self.input_start_y-19, self.fwidth, self.fheight)
self.input_string = self.input_string:sub(0,-2)
-- draw new cursor
self.cursor:moveHorizontal(-self.fwidth)
self.cursor:draw()
fb:refresh(1, self.input_start_x-5, self.input_start_y-25,
self.input_slot_w, self.h-25)
end
function InputBox:clearText()
self.cursor:clear()
self.input_string = ""
self:refreshText()
self.cursor.x_pos = self.input_start_x - 3
self.cursor:draw()
fb:refresh(1, self.input_start_x-5, self.input_start_y-25,
self.input_slot_w, self.h-25)
end
function InputBox:drawHelpMsg(ypos, w, h)
return
end
function InputBox:drawBox(ypos, w, h, title)
-- draw input border
fb.bb:paintRect(20, ypos, w, h, 5)
-- draw input slot
fb.bb:paintRect(140, ypos + 10, w - 130, h - 20, self.input_bg)
-- draw input title
renderUtf8Text(fb.bb, 35, self.input_start_y, self.face,
title, true)
end
----------------------------------------------------------------------
-- InputBox:input()
--
-- @title: input prompt for the box
-- @d_text: default to nil (used to set default text in input slot)
-- @is_hint: if this arg is true, default text will be used as hint
-- message for input
----------------------------------------------------------------------
function InputBox:input(ypos, height, title, d_text, is_hint)
self:init()
-- do some initilization
self.ypos = ypos
self.h = height
self.input_start_y = ypos + 35
self.input_cur_x = self.input_start_x
self.input_slot_w = fb.bb:getWidth() - 170
self.cursor = Cursor:new {
x_pos = self.input_start_x - 3,
y_pos = ypos + 13,
h = 30,
}
-- draw box and content
w = fb.bb:getWidth() - 40
h = height - 45
self:drawHelpMsg(ypos, w, h)
self:drawBox(ypos, w, h, title)
if d_text then
if is_hint then
-- print hint text
fb.bb:paintRect(140, self.input_start_y-19,
self.input_slot_w, self.fheight, self.input_bg)
renderUtf8Text(fb.bb, self.input_start_x+5, self.input_start_y,
self.face,
d_text, 0)
fb.bb:dimRect(140, self.input_start_y-19,
self.input_slot_w, self.fheight, self.input_bg)
else
self.input_string = d_text
self.input_cur_x = self.input_cur_x + (self.fwidth * d_text:len())
self.cursor.x_pos = self.cursor.x_pos + (self.fwidth * d_text:len())
self:refreshText()
end
end
self.cursor:draw()
fb:refresh(1, 20, ypos, w, h)
while true do
local ev = input.saveWaitForEvent()
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
keydef = Keydef:new(ev.code, getKeyModifier())
debug("key pressed: "..tostring(keydef))
command = self.commands:getByKeydef(keydef)
if command ~= nil then
debug("command to execute: "..tostring(command))
ret_code = command.func(self, keydef)
else
debug("command not found: "..tostring(command))
end
if ret_code == "break" then
ret_code = nil
break
end
end -- if
end -- while
local return_str = self.input_string
self.input_string = ""
return return_str
end
function InputBox:addAllCommands()
if self.commands then
-- we only initialize once
return
end
self.commands = Commands:new{}
INPUT_KEYS = {
{KEY_Q, "q"}, {KEY_W, "w"}, {KEY_E, "e"}, {KEY_R, "r"}, {KEY_T, "t"},
{KEY_Y, "y"}, {KEY_U, "u"}, {KEY_I, "i"}, {KEY_O, "o"}, {KEY_P, "p"},
{KEY_A, "a"}, {KEY_S, "s"}, {KEY_D, "d"}, {KEY_F, "f"}, {KEY_G, "g"},
{KEY_H, "h"}, {KEY_J, "j"}, {KEY_K, "k"}, {KEY_L, "l"},
{KEY_Z, "z"}, {KEY_X, "x"}, {KEY_C, "c"}, {KEY_V, "v"}, {KEY_B, "b"},
{KEY_N, "n"}, {KEY_M, "m"},
{KEY_1, "1"}, {KEY_2, "2"}, {KEY_3, "3"}, {KEY_4, "4"}, {KEY_5, "5"},
{KEY_6, "6"}, {KEY_7, "7"}, {KEY_8, "8"}, {KEY_9, "9"}, {KEY_0, "0"},
{KEY_SPACE, " "},
-- DXG keys
{KEY_DOT, "."}, {KEY_SLASH, "/"},
}
for k,v in ipairs(INPUT_KEYS) do
self.commands:add(v[1], nil, "",
"input "..v[2],
function(self)
self:addChar(v[2])
end
)
end
self.commands:add(KEY_FW_LEFT, nil, "",
"move cursor left",
function(self)
if (self.cursor.x_pos + 3) > self.input_start_x then
self.cursor:moveHorizontalAndDraw(-self.fwidth)
fb:refresh(1, self.input_start_x-5, self.ypos,
self.input_slot_w, self.h)
end
end
)
self.commands:add(KEY_FW_RIGHT, nil, "",
"move cursor right",
function(self)
if (self.cursor.x_pos + 3) < self.input_cur_x then
self.cursor:moveHorizontalAndDraw(self.fwidth)
fb:refresh(1, self.input_start_x-5, self.ypos,
self.input_slot_w, self.h)
end
end
)
self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "",
"submit input content",
function(self)
if self.input_string == "" then
self.input_string = nil
end
return "break"
end
)
self.commands:add(KEY_DEL, nil, "",
"delete one character",
function(self)
self:delChar()
end
)
self.commands:add(KEY_DEL, MOD_SHIFT, "",
"empty inputbox",
function(self)
self:clearText()
end
)
self.commands:add({KEY_BACK, KEY_HOME}, nil, "",
"cancel inputbox",
function(self)
self.input_string = nil
return "break"
end
)
end
----------------------------------------------------
-- Inputbox for numbers only
-- Designed by eLiNK
----------------------------------------------------
NumInputBox = InputBox:new{
initialized = false,
commands = Commands:new{},
}
function NumInputBox:addAllCommands()
self.commands = Commands:new{}
INPUT_NUM_KEYS = {
{KEY_Q, "1"}, {KEY_W, "2"}, {KEY_E, "3"}, {KEY_R, "4"}, {KEY_T, "5"},
{KEY_Y, "6"}, {KEY_U, "7"}, {KEY_I, "8"}, {KEY_O, "9"}, {KEY_P, "0"},
{KEY_1, "1"}, {KEY_2, "2"}, {KEY_3, "3"}, {KEY_4, "4"}, {KEY_5, "5"},
{KEY_6, "6"}, {KEY_7, "7"}, {KEY_8, "8"}, {KEY_9, "9"}, {KEY_0, "0"},
}
for k,v in ipairs(INPUT_NUM_KEYS) do
self.commands:add(v[1], nil, "",
"input "..v[2],
function(self)
self:addChar(v[2])
end
)
end -- for
self.commands:add(KEY_FW_LEFT, nil, "",
"move cursor left",
function(self)
if (self.cursor.x_pos + 3) > self.input_start_x then
self.cursor:moveHorizontalAndDraw(-self.fwidth)
fb:refresh(1, self.input_start_x-5, self.ypos,
self.input_slot_w, self.h)
end
end
)
self.commands:add(KEY_FW_RIGHT, nil, "",
"move cursor right",
function(self)
if (self.cursor.x_pos + 3) < self.input_cur_x then
self.cursor:moveHorizontalAndDraw(self.fwidth)
fb:refresh(1, self.input_start_x-5, self.ypos,
self.input_slot_w, self.h)
end
end
)
self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "",
"submit input content",
function(self)
if self.input_string == "" then
self.input_string = nil
end
return "break"
end
)
self.commands:add(KEY_DEL, nil, "",
"delete one character",
function(self)
self:delChar()
end
)
self.commands:add(KEY_DEL, MOD_SHIFT, "",
"empty inputbox",
function(self)
self:clearText()
end
)
self.commands:add({KEY_BACK, KEY_HOME}, nil, "",
"cancel inputbox",
function(self)
self.input_string = nil
return "break"
end
)
end
function NumInputBox:drawHelpMsg(ypos, w, h)
local w = 415
local y = ypos - 60
local x = (G_width - w) / 2
local h = 50
local bw = 2
local face = Font:getFace("scfont", 22)
fb.bb:paintRect(x, y, w, h, 15)
fb.bb:paintRect(x+bw, y+bw, w-2*bw, h-2*bw, 0)
local font_y = y + 22
local font_x = x + 22
INPUT_NUM_KEYS = {
{"Q", "1"}, {"W", "2"}, {"E", "3"}, {"R", "4"}, {"T", "5"},
{"Y", "6"}, {"U", "7"}, {"I", "8"}, {"O", "9"}, {"P", "0"},
}
for k,v in ipairs(INPUT_NUM_KEYS) do
renderUtf8Text(fb.bb, font_x, font_y, face,
v[1], true)
renderUtf8Text(fb.bb, font_x, font_y + 22, face,
v[2], true)
font_x = font_x + 40
end
fb:refresh(1, x, y, w, h)
end

@ -1,278 +0,0 @@
--[[
This file contains settings related to key codes
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
This file is based on include/keydefs.h from "launchpad"
application, which is
Copyright (C) 2010 Andy M. aka h1uke h1ukeguy @ gmail.com
and was licensed under the GPLv2
]]--
Keys = {
altmode = false,
shiftmode = false,
}
KEY_1 = 2
KEY_2 = 3
KEY_3 = 4
KEY_4 = 5
KEY_5 = 6
KEY_6 = 7
KEY_7 = 8
KEY_8 = 9
KEY_9 = 10
KEY_0 = 11
KEY_Q = 16
KEY_W = 17
KEY_E = 18
KEY_R = 19
KEY_T = 20
KEY_Y = 21
KEY_U = 22
KEY_I = 23
KEY_O = 24
KEY_P = 25
KEY_A = 30
KEY_S = 31
KEY_D = 32
KEY_F = 33
KEY_G = 34
KEY_H = 35
KEY_J = 36
KEY_K = 37
KEY_L = 38
KEY_DEL = 14
KEY_Z = 44
KEY_X = 45
KEY_C = 46
KEY_V = 47
KEY_B = 48
KEY_N = 49
KEY_M = 50
KEY_DOT = 52
KEY_SLASH = 53
KEY_ENTER = 28
KEY_SHIFT = 42
KEY_ALT = 56
KEY_SPACE = 57
KEY_AA = 90
KEY_SYM = 94
KEY_VPLUS = 115
KEY_VMINUS = 114
KEY_HOME = 98
KEY_PGBCK = 109
KEY_PGFWD = 124
KEY_MENU = 139
KEY_BACK = 91
KEY_FW_LEFT = 105
KEY_FW_RIGHT = 106
KEY_FW_UP = 122
KEY_FW_DOWN = 123
KEY_FW_PRESS = 92
KEY_INTO_SCREEN_SAVER = 10000
KEY_OUTOF_SCREEN_SAVER = 10001
-- constants from <linux/input.h>
EV_KEY = 1
-- event values
EVENT_VALUE_KEY_PRESS = 1
EVENT_VALUE_KEY_REPEAT = 2
EVENT_VALUE_KEY_RELEASE = 0
-- modifiers
MOD_SHIFT = "_Shift_"
MOD_ALT = "_Alt_"
MOD_SHIFT_OR_ALT = "_ShiftAlt_"
MOD_ANY = "_Any_"
MOD_SHIFT_DISPLAY = "Shift"
MOD_ALT_DISPLAY = "Alt"
MOD_TABLE = {MOD_SHIFT={v=MOD_SHIFT,d=MOD_SHIFT_DISPLAY},MOD_ALT={v=MOD_ALT,d=MOD_ALT_DISPLAY}}
function getKeyModifier()
return Keys.altmode and MOD_ALT or Keys.shiftmode and MOD_SHIFT
end
function setK3Keycodes()
KEY_AA = 190
KEY_SYM = 126
KEY_HOME = 102
KEY_BACK = 158
KEY_PGFWD = 191
KEY_LPGBCK = 193
KEY_LPGFWD = 104
KEY_VPLUS = 115
KEY_VMINUS = 114
KEY_FW_UP = 103
KEY_FW_DOWN = 108
KEY_FW_PRESS = 194
end
function setEmuKeycodes()
KEY_PGFWD = 117
KEY_PGBCK = 112
KEY_LPGBCK = 72 -- F6
KEY_LPGFWD = 73 -- F7
KEY_HOME = 110 -- home
KEY_BACK = 22 -- backspace
KEY_DEL = 119 -- Delete
KEY_MENU = 67 -- F1
KEY_FW_UP = 111
KEY_FW_DOWN = 116
KEY_FW_LEFT = 113
KEY_FW_RIGHT = 114
KEY_FW_PRESS = 115 -- end for now (above arrows)
KEY_SPACE = 65
KEY_ENTER = 36
KEY_1 = 10
KEY_2 = 11
KEY_3 = 12
KEY_4 = 13
KEY_5 = 14
KEY_6 = 15
KEY_7 = 16
KEY_8 = 17
KEY_9 = 18
KEY_0 = 19
KEY_Q = 24
KEY_W = 25
KEY_E = 26
KEY_R = 27
KEY_T = 28
KEY_Y = 29
KEY_U = 30
KEY_I = 31
KEY_O = 32
KEY_P = 33
KEY_A = 38
KEY_S = 39
KEY_D = 40
KEY_F = 41
KEY_G = 42
KEY_H = 43
KEY_J = 44
KEY_K = 45
KEY_L = 46
KEY_Z = 52
KEY_X = 53
KEY_C = 54
KEY_V = 55
KEY_B = 56
KEY_N = 57
KEY_M = 58
KEY_DOT = 60
KEY_SLASH = 61
KEY_AA = 105 -- right alt
KEY_SYM = 62 -- right shift
KEY_SHIFT = 50 -- left shift
KEY_ALT = 64 -- left alt
KEY_VPLUS = 95 -- F11
KEY_VMINUS = 96 -- F12
end
function adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then
if ev.code == KEY_SHIFT then
Keys.shiftmode = true
elseif ev.code == KEY_ALT then
Keys.altmode = true
end
elseif ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_RELEASE then
if ev.code == KEY_SHIFT then
Keys.shiftmode = false
elseif ev.code == KEY_ALT then
Keys.altmode = false
end
end
-- adjust five way key according to rotation mode
local code = ev.code
if Screen.cur_rotation_mode == 0 then
return code
elseif Screen.cur_rotation_mode == 1 then
if code == KEY_FW_UP then
return KEY_FW_RIGHT
elseif code == KEY_FW_RIGHT then
return KEY_FW_DOWN
elseif code == KEY_FW_DOWN then
return KEY_FW_LEFT
elseif code == KEY_FW_LEFT then
return KEY_FW_UP
else
return code
end
elseif Screen.cur_rotation_mode == 2 then
if code == KEY_FW_UP then
return KEY_FW_DOWN
elseif code == KEY_FW_RIGHT then
return KEY_FW_LEFT
elseif code == KEY_FW_DOWN then
return KEY_FW_UP
elseif code == KEY_FW_LEFT then
return KEY_FW_RIGHT
else
return code
end
elseif Screen.cur_rotation_mode == 3 then
if code == KEY_FW_UP then
return KEY_FW_LEFT
elseif code == KEY_FW_RIGHT then
return KEY_FW_UP
elseif code == KEY_FW_DOWN then
return KEY_FW_RIGHT
elseif code == KEY_FW_LEFT then
return KEY_FW_DOWN
else
return code
end
end
-- This should not happen.
debug("# Unrecognizable rotation mode "..Screen.cur_rotation_mode.."!")
return nil
end
-- wrapper for input.waitForEvents that will retry for some cases
function input.saveWaitForEvent(timeout)
local retry = true
while retry do
local ok, ev = pcall(input.waitForEvent, timeout)
if not ok then
debug("got error waiting for events:", ev)
if ev == "Waiting for input failed: 4\n" then
-- EINTR, we got interrupted. Try and restart
retry = true
else
retry = false
end
else
return ev
end
end
end

@ -1,47 +0,0 @@
require "unireader"
require "inputbox"
PDFReader = UniReader:new{}
-- open a PDF file and its settings store
function PDFReader:open(filename)
-- muPDF manages its own cache, set second parameter
-- to the maximum size you want it to grow
local ok
ok, self.doc = pcall(pdf.openDocument, filename, self.cache_document_size)
if not ok then
return false, self.doc -- will contain error message
end
if self.doc:needsPassword() then
local password = InputBox:input(G_height-100, 100, "Pass:")
if not password or not self.doc:authenticatePassword(password) then
self.doc:close()
self.doc = nil
return false, "wrong or missing password"
end
-- password wrong or not entered
end
local ok, err = pcall(self.doc.getPages, self.doc)
if not ok then
-- for PDFs, they might trigger errors later when accessing page tree
self.doc:close()
self.doc = nil
return false, "damaged page tree"
end
return true
end
----------------------------------------------------
-- highlight support
----------------------------------------------------
function PDFReader:getText(pageno)
local ok, page = pcall(self.doc.openPage, self.doc, pageno)
if not ok then
-- TODO: error handling
return nil
end
local text = page:getPageText()
--debug("## page:getPageText "..dump(text)) -- performance impact on device
page:close()
return text
end

@ -1,179 +0,0 @@
#!./kpdfview
--[[
KindlePDFViewer: a reader implementation
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
]]--
require "alt_getopt"
require "pdfreader"
require "djvureader"
require "crereader"
require "filechooser"
require "settings"
require "screen"
require "keys"
require "commands"
require "dialog"
-- option parsing:
longopts = {
password = "p",
goto = "g",
gamma = "G",
debug = "d",
help = "h"
}
function openFile(filename)
local file_type = string.lower(string.match(filename, ".+%.([^.]+)"))
local reader = nil
if file_type == "djvu" then
reader = DJVUReader
elseif file_type == "pdf" or file_type == "xps" or file_type == "cbz" then
reader = PDFReader
elseif file_type == "epub" or file_type == "txt" or file_type == "rtf" or file_type == "htm" or file_type == "html" or file_type == "fb2" or file_type == "chm" or file_type == "mobi" or file_type == "doc" or file_type == "zip" then
reader = CREReader
end
if reader then
InfoMessage:show("Opening document, please wait... ", 0)
reader:preLoadSettings(filename)
local ok, err = reader:open(filename)
if ok then
reader:loadSettings(filename)
page_num = reader:getLastPageOrPos()
reader:goto(tonumber(page_num), true)
reader_settings:saveSetting("lastfile", filename)
return reader:inputLoop()
else
InfoMessage:show("Error opening document.", 0)
util.sleep(2)
end
end
return true -- on failed attempts, we signal to keep running
end
function showusage()
print("usage: ./reader.lua [OPTION] ... path")
print("Read PDFs and DJVUs on your E-Ink reader")
print("")
print("-p, --password=PASSWORD set password for reading PDF document")
print("-g, --goto=page start reading on page")
print("-G, --gamma=GAMMA set gamma correction")
print("-d, --debug start in debug mode")
print(" (floating point notation, e.g. \"1.5\")")
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 PDF|DJVU 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: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
if util.isEmulated()==1 then
input.open("")
-- SDL key codes
setEmuKeycodes()
else
input.open("slider")
input.open("/dev/input/event0")
input.open("/dev/input/event1")
-- 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")
setK3Keycodes()
end
end
fb = einkfb.open("/dev/fb0")
G_width, G_height = fb:getSize()
-- read current rotation mode
Screen:updateRotationMode()
Screen.native_rotation_mode = Screen.cur_rotation_mode
-- set up reader's setting: font
reader_settings = DocSettings:open(".reader")
fontmap = reader_settings:readSetting("fontmap")
if fontmap ~= nil then
Font.fontmap = fontmap
end
-- initialize global settings shared among all readers
UniReader:initGlobalSettings(reader_settings)
-- initialize specific readers
PDFReader:init()
DJVUReader:init()
CREReader:init()
-- display directory or open file
local patharg = reader_settings:readSetting("lastfile")
if ARGV[optind] and lfs.attributes(ARGV[optind], "mode") == "directory" then
local running = true
FileChooser:setPath(ARGV[optind])
while running do
local file, callback = FileChooser:choose(0, G_height)
if callback then
callback()
else
if file ~= nil then
running = openFile(file)
print(file)
else
running = false
end
end
end
elseif ARGV[optind] and lfs.attributes(ARGV[optind], "mode") == "file" then
openFile(ARGV[optind], optarg["p"])
elseif patharg and lfs.attributes(patharg, "mode") == "file" then
openFile(patharg, optarg["p"])
else
return showusage()
end
-- save reader settings
reader_settings:saveSetting("fontmap", Font.fontmap)
reader_settings:close()
-- @TODO dirty workaround, find a way to force native system poll
-- screen orientation and upside down mode 09.03 2012
fb:setOrientation(Screen.native_rotation_mode)
input.closeAll()
if util.isEmulated()==0 then
os.execute("killall -cont cvm")
os.execute('echo "send '..KEY_MENU..'" > /proc/keypad;echo "send '..KEY_MENU..'" > /proc/keypad')
end

@ -1,343 +0,0 @@
require "rendertext"
require "keys"
require "graphics"
require "font"
require "commands"
SelectMenu = {
-- font for displaying item names
fsize = 22,
-- font for page title
tfsize = 25,
-- font for paging display
ffsize = 16,
-- font for item shortcut
sface = Font:getFace("scfont", 22),
-- title height
title_H = 40,
-- spacing between lines
spacing = 36,
-- foot height
foot_H = 27,
menu_title = "No Title",
no_item_msg = "No items found.",
item_array = {},
items = 0,
item_shortcuts = {
"Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P",
"A", "S", "D", "F", "G", "H", "J", "K", "L", "Del",
"Z", "X", "C", "V", "B", "N", "M", ".", "Sym", "Ent",
},
last_shortcut = 0,
-- state buffer
page = 1,
current = 1,
oldcurrent = 0,
selected_item = nil,
commands = nil,
}
function SelectMenu:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
o.items = #o.item_array
o.page = 1
o.current = 1
o.oldcurrent = 0
o.selected_item = nil
-- increase spacing for DXG so we don't have more than 30 shortcuts
if fb.bb:getHeight() == 1200 then
o.spacing = 37
end
o:addAllCommands()
return o
end
function SelectMenu:getItemIndexByShortCut(c, perpage)
if c == nil then return end -- unused key
for _k,_v in ipairs(self.item_shortcuts) do
if _v == c and _k <= self.last_shortcut then
return (perpage * (self.page - 1) + _k)
end
end
end
function SelectMenu:addAllCommands()
self.commands = Commands:new{}
self.commands:add(KEY_FW_UP, nil, "",
"previous item",
function(sm)
if sm.current == 1 then
if sm.page > 1 then
sm.current = sm.perpage
sm.page = sm.page - 1
sm.pagedirty = true
end
else
sm.current = sm.current - 1
sm.markerdirty = true
end
end
)
self.commands:add(KEY_FW_DOWN, nil, "",
"next item",
function(sm)
if sm.current == sm.perpage then
if sm.page < (sm.items / sm.perpage) then
sm.current = 1
sm.page = sm.page + 1
sm.pagedirty = true
end
else
if sm.page ~= math.floor(sm.items / sm.perpage) + 1
or sm.current + (sm.page - 1) * sm.perpage < sm.items then
sm.current = sm.current + 1
sm.markerdirty = true
end
end
end
)
self.commands:add({KEY_PGFWD, KEY_LPGFWD}, nil, "",
"next page",
function(sm)
if sm.page < (sm.items / sm.perpage) then
if sm.current + sm.page * sm.perpage > sm.items then
sm.current = sm.items - sm.page * sm.perpage
end
sm.page = sm.page + 1
sm.pagedirty = true
else
sm.current = sm.items - (sm.page - 1) * sm.perpage
sm.markerdirty = true
end
end
)
self.commands:add({KEY_PGBCK, KEY_LPGBCK}, nil, "",
"previous page",
function(sm)
if sm.page > 1 then
sm.page = sm.page - 1
sm.pagedirty = true
else
sm.current = 1
sm.markerdirty = true
end
end
)
self.commands:add(KEY_FW_PRESS, nil, "",
"select menu item",
function(sm)
if sm.items == 0 then
return "break"
else
self.selected_item = (sm.perpage * (sm.page - 1) + sm.current)
end
end
)
local KEY_Q_to_P = {}
for i = KEY_Q, KEY_P do
table.insert(KEY_Q_to_P, Keydef:new(i, nil, ""))
end
self.commands:addGroup("Q to P", KEY_Q_to_P,
"Select menu item with Q to E key as shortcut",
function(sm, keydef)
sm.selected_item = sm:getItemIndexByShortCut(
sm.item_shortcuts[ keydef.keycode - KEY_Q + 1 ], sm.perpage)
end
)
local KEY_A_to_L = {}
for i = KEY_A, KEY_L do
table.insert(KEY_A_to_L, Keydef:new(i, nil, ""))
end
self.commands:addGroup("A to L", KEY_A_to_L,
"Select menu item with A to L key as shortcut",
function(sm, keydef)
sm.selected_item = sm:getItemIndexByShortCut(
sm.item_shortcuts[ keydef.keycode - KEY_A + 11 ], sm.perpage)
end
)
local KEY_Z_to_M = {}
for i = KEY_Z, KEY_M do
table.insert(KEY_Z_to_M, Keydef:new(i, nil, ""))
end
self.commands:addGroup("Z to M", KEY_Z_to_M,
"Select menu item with Z to M key as shortcut",
function(sm, keydef)
sm.selected_item = sm:getItemIndexByShortCut(
sm.item_shortcuts[ keydef.keycode - KEY_Z + 21 ], sm.perpage)
end
)
self.commands:add(KEY_DEL, nil, "",
"Select menu item with del key as shortcut",
function(sm)
sm.selected_item = sm:getItemIndexByShortCut("Del", sm.perpage)
end
)
self.commands:add(KEY_DOT, nil, "",
"Select menu item with dot key as shortcut",
function(sm)
sm.selected_item = sm:getItemIndexByShortCut(".", sm.perpage)
end
)
self.commands:add({KEY_SYM, KEY_SLASH}, nil, "",
"Select menu item with sym/slash key as shortcut",
function(sm)
-- DXG has slash after dot
sm.selected_item = sm:getItemIndexByShortCut("Sym", sm.perpage)
end
)
self.commands:add(KEY_ENTER, nil, "",
"Select menu item with enter key as shortcut",
function(sm)
sm.selected_item = sm:getItemIndexByShortCut("Ent", sm.perpage)
end
)
self.commands:add(KEY_BACK, nil, "",
"Exit menu",
function(sm)
return "break"
end
)
end
function SelectMenu:clearCommands()
self.commands = Commands:new{}
self.commands:add(KEY_BACK, nil, "",
"Exit menu",
function(sm)
return "break"
end)
end
------------------------------------------------
-- return the index of selected item
------------------------------------------------
function SelectMenu:choose(ypos, height)
self.perpage = math.floor(height / self.spacing) - 2
self.pagedirty = true
self.markerdirty = false
self.last_shortcut = 0
while true do
local cface = Font:getFace("cfont", 22)
local tface = Font:getFace("tfont", 25)
local fface = Font:getFace("ffont", 16)
if self.pagedirty then
self.markerdirty = true
-- draw menu title
fb.bb:paintRect(0, ypos, fb.bb:getWidth(), self.title_H + 10, 0)
fb.bb:paintRect(10, ypos + 10, fb.bb:getWidth() - 20, self.title_H, 5)
local x = 20
local y = ypos + self.title_H
renderUtf8Text(fb.bb, x, y, tface, self.menu_title, true)
-- draw items
fb.bb:paintRect(0, ypos + self.title_H + 10, fb.bb:getWidth(), height - self.title_H, 0)
if self.items == 0 then
y = ypos + self.title_H + (self.spacing * 2)
renderUtf8Text(fb.bb, 30, y, cface,
"Oops... Bad news for you:", true)
y = y + self.spacing
renderUtf8Text(fb.bb, 30, y, cface,
self.no_item_msg, true)
self.markerdirty = false
self:clearCommands()
else
local c
for c = 1, self.perpage do
local i = (self.page - 1) * self.perpage + c
if i <= self.items then
y = ypos + self.title_H + (self.spacing * c)
-- paint shortcut indications
if c <= 10 or c > 20 then
blitbuffer.paintBorder(fb.bb, 10, y-22, 29, 29, 2, 15)
else
fb.bb:paintRect(10, y-22, 29, 29, 3)
end
if self.item_shortcuts[c] ~= nil and
string.len(self.item_shortcuts[c]) == 3 then
-- debug "Del", "Sym and "Ent"
renderUtf8Text(fb.bb, 13, y, fface,
self.item_shortcuts[c], true)
else
renderUtf8Text(fb.bb, 18, y, self.sface,
self.item_shortcuts[c], true)
end
self.last_shortcut = c
renderUtf8Text(fb.bb, 50, y, cface,
self.item_array[i], true)
end -- if i <= self.items
end -- for c=1, self.perpage
end -- if self.items == 0
-- draw footer
y = ypos + self.title_H + (self.spacing * self.perpage)
+ self.foot_H + 5
x = (fb.bb:getWidth() / 2) - 50
renderUtf8Text(fb.bb, x, y, fface,
"Page "..self.page.." of "..
(math.ceil(self.items / self.perpage)), true)
end
if self.markerdirty then
if not self.pagedirty then
if self.oldcurrent > 0 then
y = ypos + self.title_H + (self.spacing * self.oldcurrent) + 8
fb.bb:paintRect(45, y, fb.bb:getWidth() - 60, 3, 0)
fb:refresh(1, 45, y, fb.bb:getWidth() - 60, 3)
end
end
-- draw new marker line
y = ypos + self.title_H + (self.spacing * self.current) + 8
fb.bb:paintRect(45, y, fb.bb:getWidth() - 60, 3, 15)
if not self.pagedirty then
fb:refresh(1, 45, y, fb.bb:getWidth() - 60, 3)
end
self.oldcurrent = self.current
self.markerdirty = false
end
if self.pagedirty then
fb:refresh(0, 0, ypos, fb.bb:getWidth(), height)
self.pagedirty = false
end
local ev = input.saveWaitForEvent()
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then
keydef = Keydef:new(ev.code, getKeyModifier())
debug("key pressed: "..tostring(keydef))
command = self.commands:getByKeydef(keydef)
if command ~= nil then
debug("command to execute: "..tostring(command))
ret_code = command.func(self, keydef)
else
debug("command not found: "..tostring(command))
end
if ret_code == "break" then
break
end
if self.selected_item ~= nil then
debug("# selected "..self.selected_item)
return self.selected_item, self.item_array[self.selected_item]
end
end -- EOF if
end -- EOF while
return nil
end

File diff suppressed because it is too large Load Diff

@ -1,6 +1,8 @@
require "ui"
require "readerui"
require "document"
print(package.path)
package.path = "./frontend/?.lua"
require "ui/ui"
require "ui/readerui"
require "document/document"
TestGrid = Widget:new{}

Loading…
Cancel
Save