diff --git a/Makefile b/Makefile index 42fa72b3c..98d57980c 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,8 @@ KOR_BASE=koreader-base VERSION=$(shell git describe HEAD) # subdirectory we use to build the installation bundle -INSTALL_DIR=koreader-$(MACHINE) +INSTALL_DIR=koreader +INSTALL_DIR_KOBO=mnt/onboard/.kobo # files to link from main directory INSTALL_FILES=reader.lua frontend resources koreader.sh \ @@ -72,6 +73,42 @@ customupdate: all -x "koreader/resources/fonts/*" # @TODO write an installation script for KUAL (houqp) +koboupdate: all + # ensure that the binaries were built for ARM + file $(KOR_BASE)/koreader-base | grep ARM || exit 1 + file $(KOR_BASE)/extr | grep ARM || exit 1 + # remove old package and dir if any + rm -f koreader-kobo-$(VERSION).zip + rm -rf $(INSTALL_DIR) + # create new dir for package + mkdir -p $(INSTALL_DIR)/{history,screenshots,clipboard,libs} + cp -p README.md COPYING $(KOR_BASE)/{koreader-base,extr,sdcv} koreader.sh koreader_kobo.sh $(LUA_FILES) $(INSTALL_DIR) + $(STRIP) --strip-unneeded $(INSTALL_DIR)/koreader-base $(INSTALL_DIR)/extr $(INSTALL_DIR)/sdcv + mkdir $(INSTALL_DIR)/data $(INSTALL_DIR)/data/dict $(INSTALL_DIR)/data/tessdata + cp -L koreader-base/$(DJVULIB) $(KOR_BASE)/$(CRELIB) \ + $(KOR_BASE)/$(LUALIB) $(KOR_BASE)/$(K2PDFOPTLIB) \ + $(KOR_BASE)/$(LEPTONICALIB) $(KOR_BASE)/$(TESSERACTLIB) \ + $(INSTALL_DIR)/libs + $(STRIP) --strip-unneeded $(INSTALL_DIR)/libs/* + cp -rpL $(KOR_BASE)/data/*.css $(INSTALL_DIR)/data + cp -rpL $(KOR_BASE)/data/hyph $(INSTALL_DIR)/data/hyph + cp -rpL $(KOR_BASE)/fonts $(INSTALL_DIR) + cp -rp $(MO_DIR) $(INSTALL_DIR) + rm $(INSTALL_DIR)/fonts/droid/DroidSansFallbackFull.ttf + echo $(VERSION) > git-rev + cp -r git-rev resources $(INSTALL_DIR) + rm -r $(INSTALL_DIR)/resources/fonts + cp -rpL frontend $(INSTALL_DIR) + cp defaults.lua $(INSTALL_DIR) + mkdir $(INSTALL_DIR)/fonts/host + mkdir -p $(INSTALL_DIR_KOBO)/fmon + cp -rpL fmon $(INSTALL_DIR_KOBO) + cp -p resources/koreader.png $(INSTALL_DIR_KOBO)/.. + tar -zcvf KoboRoot.tgz mnt/ + zip -9 -r koreader-kobo-$(VERSION).zip $(INSTALL_DIR) KoboRoot.tgz + rm KoboRoot.tgz + rm -rf mnt/ + rm -rf $(INSTALL_DIR) pot: $(XGETTEXT_BIN) reader.lua `find frontend -iname "*.lua"` \ diff --git a/fmon/koreader.sh b/fmon/koreader.sh new file mode 100644 index 000000000..03ba8f433 --- /dev/null +++ b/fmon/koreader.sh @@ -0,0 +1 @@ +$root/.kobo/fmon/fmon $root/koreader.png $root/.kobo/koreader/koreader_kobo.sh & diff --git a/frontend/apps/filemanager/fm.lua b/frontend/apps/filemanager/fm.lua new file mode 100644 index 000000000..4396f2c00 --- /dev/null +++ b/frontend/apps/filemanager/fm.lua @@ -0,0 +1,87 @@ +require "ui/widget/filechooser" +require "apps/filemanager/fmhistory" +require "apps/filemanager/fmmenu" + + +FileManager = InputContainer:extend{ + title = _("FileManager"), + width = Screen:getWidth(), + height = Screen:getHeight(), + root_path = './', + -- our own size + dimen = Geom:new{ w = 400, h = 600 }, + onExit = function() end, +} + +function FileManager:init() + local exclude_dirs = {"%.sdr$"} + + self.show_parent = self.show_parent or self + + self.banner = FrameContainer:new{ + padding = 0, + bordersize = 0, + TextWidget:new{ + face = Font:getFace("tfont", 24), + text = self.title, + } + } + + local file_chooser = FileChooser:new{ + -- remeber to adjust the height when new item is added to the group + 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 + } + + function file_chooser:onFileSelect(file) + showReaderUI(file) + return true + end + + self.layout = VerticalGroup:new{ + self.banner, + file_chooser, + } + + local fm_ui = FrameContainer:new{ + padding = 0, + bordersize = 0, + background = 0, + self.layout, + } + + 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:handleEvent(Event:new("SetDimensions", self.dimen)) +end + + +function FileManager:onClose() + UIManager:close(self) + if self.onExit then + self:onExit() + end + return true +end diff --git a/frontend/apps/filemanager/fmhistory.lua b/frontend/apps/filemanager/fmhistory.lua new file mode 100644 index 000000000..2b9dcb265 --- /dev/null +++ b/frontend/apps/filemanager/fmhistory.lua @@ -0,0 +1,73 @@ +FileManagerHistory = InputContainer:extend{ + hist_menu_title = _("History"), +} + +function FileManagerHistory:init() + self.ui.menu:registerToMainMenu(self) +end + +function FileManagerHistory:onSetDimensions(dimen) + self.dimen = dimen +end + +function FileManagerHistory:onShowHist() + self:updateItemTable() + + local menu_container = CenterContainer:new{ + dimen = Screen:getSize(), + } + + local hist_menu = Menu:new{ + title = _("History"), + item_table = self.hist, + ui = self.ui, + width = Screen:getWidth()-50, + height = Screen:getHeight()-50, + show_parent = menu_container, + } + + table.insert(menu_container, hist_menu) + + hist_menu.close_callback = function() + UIManager:close(menu_container) + end + + 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, + }) +end + +function FileManagerHistory:updateItemTable() + function readHistDir(order_arg, re) + local pipe_out = io.popen("ls "..order_arg.." -1 ./history") + for f in pipe_out:lines() do + table.insert(re, { + dir = DocSettings:getPathFromHistory(f), + name = DocSettings:getNameFromHistory(f), + }) + end + end + + self.hist = {} + local last_files = {} + readHistDir("-c", last_files) + for _,v in pairs(last_files) do + table.insert(self.hist, { + text = v.name, + callback = function() + showReaderUI(v.dir .. "/" .. v.name) + end + }) + end +end + + diff --git a/frontend/apps/filemanager/fmmenu.lua b/frontend/apps/filemanager/fmmenu.lua new file mode 100644 index 000000000..b499fd9b9 --- /dev/null +++ b/frontend/apps/filemanager/fmmenu.lua @@ -0,0 +1,131 @@ +require "ui/widget/menu" +require "ui/widget/touchmenu" + +FileManagerMenu = InputContainer:extend{ + 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 = {} + + 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, + } + } + }, + } +end + +function FileManagerMenu:setUpdateItemTable() + for _, widget in pairs(self.registered_widgets) do + widget:addToMainMenu(self.tab_item_table) + end + + if Device:hasFrontlight() then + table.insert(self.tab_item_table.main, { + text = _("Frontlight settings"), + callback = function() + ReaderFrontLight:onShowFlDialog() + end + }) + 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 + }) +end + +function FileManagerMenu:onShowMenu() + if #self.tab_item_table.main == 0 then + self:setUpdateItemTable() + end + + 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, + } + + 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 + + menu_container[1] = main_menu + -- maintain a reference to menu_container + self.menu_container = menu_container + UIManager:show(menu_container) + + return true +end + +function FileManagerMenu:onTapShowMenu() + self:onShowMenu() + return true +end + +function FileManagerMenu:onSetDimensions(dimen) + -- 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) +end + diff --git a/frontend/lulip.lua b/frontend/lulip.lua new file mode 100644 index 000000000..aee1c65a5 --- /dev/null +++ b/frontend/lulip.lua @@ -0,0 +1,190 @@ +-- lulip: LuaJIT line level profiler +-- +-- Copyright (c) 2013 John Graham-Cumming +-- +-- License: http://opensource.org/licenses/MIT + +local io_lines = io.lines +local io_open = io.open +local pairs = pairs +local print = print +local debug = debug +local tonumber = tonumber +local setmetatable = setmetatable +local table_sort = table.sort +local table_insert = table.insert +local string_find = string.find +local string_sub = string.sub +local string_gsub = string.gsub +local string_format = string.format +local ffi = require("ffi") + +ffi.cdef[[ + typedef long time_t; + + typedef struct timeval { + time_t tv_sec; + time_t tv_usec; + } timeval; + + int gettimeofday(struct timeval* t, void* tzp); +]] + +module(...) + +local gettimeofday_struct = ffi.new("timeval") +local function gettimeofday() + ffi.C.gettimeofday(gettimeofday_struct, nil) + return tonumber(gettimeofday_struct.tv_sec) * 1000000 + tonumber(gettimeofday_struct.tv_usec) +end + +local mt = { __index = _M } + +-- new: create new profiler object +function new(self) + return setmetatable({ + + -- Time when start() and stop() were called in microseconds + + start_time = 0, + stop_time = 0, + + -- Per line timing information + + lines = {}, + + -- The current line being processed and when it was startd + + current_line = nil, + current_start = 0, + + -- List of files to ignore. Set patterns using dont() + + ignore = {}, + + -- List of short file names used as a cache + + short = {}, + + -- Maximum number of rows of output data, set using maxrows() + + rows = 20, + }, mt) +end + +-- event: called when a line is executed +function event(self, event, line) + local now = gettimeofday() + + local f = string_sub(debug.getinfo(3).source,2) + for i=1,#self.ignore do + if string_find(f, self.ignore[i], 1, true) then + return + end + end + + local short = self.short[f] + if not short then + local start = string_find(f, "[^/]+$") + self.short[f] = string_sub(f, start) + short = self.short[f] + end + + if self.current_line ~= nil then + self.lines[self.current_line][1] = + self.lines[self.current_line][1] + 1 + self.lines[self.current_line][2] = + self.lines[self.current_line][2] + (now - self.current_start) + end + + self.current_line = short .. ':' .. line + + if self.lines[self.current_line] == nil then + self.lines[self.current_line] = {0, 0.0, f} + end + + self.current_start = gettimeofday() +end + +-- dont: tell the profiler to ignore files that match these patterns +function dont(self, file) + table_insert(self.ignore, file) +end + +-- maxrows: set the maximum number of rows of output +function maxrows(self, max) + self.rows = max +end + +-- start: begin profiling +function start(self) + self:dont('lulip.lua') + self.start_time = gettimeofday() + self.current_line = nil + self.current_start = 0 + debug.sethook(function(e,l) self:event(e, l) end, "l") +end + +-- stop: end profiling +function stop(self) + self.stop_time = gettimeofday() + debug.sethook() +end + +-- readfile: turn a file into an array for line-level access +local function readfile(file) + local lines = {} + local ln = 1 + for line in io_lines(file) do + lines[ln] = string_gsub(line, "^%s*(.-)%s*$", "%1") + ln = ln + 1 + end + return lines +end + +-- dump: dump profile information to the named file +function dump(self, file) + local t = {} + for l,d in pairs(self.lines) do + table_insert(t, {line=l, data=d}) + end + table_sort(t, function(a,b) return a["data"][2] > b["data"][2] end) + + local files = {} + + local f = io_open(file, "w") + if not f then + print("Failed to open output file " .. file) + return + end + f:write([[ + + + + + + + + + + + +]]) + + for j=1,self.rows do + if not t[j] then break end + local l = t[j]["line"] + local d = t[j]["data"] + if not files[d[3]] then + files[d[3]] = readfile(d[3]) + end + local ln = tonumber(string_sub(l, string_find(l, ":", 1, true)+1)) + f:write(string_format([[ + +]], +l, d[1], d[2]/1000, files[d[3]][ln])) + end + f:write('
file:linecountelapsed (ms)line
%s%i%.3f%s
self.max and self.max or intensity + self.intensity = intensity +end + +function KindleFrontLight:init() + require "liblipclua" + self.lipc_handle = lipc.init("com.github.koreader") + if self.lipc_handle then + self.intensity = self.lipc_handle:get_int_property("com.lab126.powerd", "flIntensity") + end +end + +function KindleFrontLight:toggle() + local f = io.open(self.kpw_fl, "r") + local sysint = tonumber(f:read("*all"):match("%d+")) + f:close() + if sysint == 0 then + self:setIntensity(self.intensity) + else + os.execute("echo -n 0 > " .. self.kpw_fl) + end +end + +KindleFrontLight.intensityCheckBounds = BaseFrontLight.intensityCheckBounds + +function KindleFrontLight:setIntensity(intensity) + if self.lipc_handle ~= nil then + self:intensityCheckBounds(intensity) + self.lipc_handle:set_int_property("com.lab126.powerd", "flIntensity", self.intensity) + end +end + +function KoboFrontLight:init() + self.fl = kobolight.open() +end + +function KoboFrontLight:toggle() + if self.fl ~= nil then + self.fl:toggle() + end +end + +KoboFrontLight.intensityCheckBounds = BaseFrontLight.intensityCheckBounds + +function KoboFrontLight:setIntensity(intensity) + if self.fl ~= nil then + self:intensityCheckBounds(intensity) + self.fl:setBrightness(self.intensity) + end +end diff --git a/frontend/ui/inputevent.lua b/frontend/ui/inputevent.lua index a6bcaee9c..eb003e594 100644 --- a/frontend/ui/inputevent.lua +++ b/frontend/ui/inputevent.lua @@ -3,7 +3,6 @@ require "ui/device" require "ui/time" require "ui/gesturedetector" require "ui/geometry" -require "ui/reader/readerfrontlight" -- constants from EV_SYN = 0 @@ -273,9 +272,9 @@ function Input:init() if util.isEmulated() == 1 then self:initKeyMap() - os.remove("emu_event") - os.execute("mkfifo emu_event") - input.open("emu_event") + os.remove("/tmp/emu_event") + os.execute("mkfifo /tmp/emu_event") + input.open("/tmp/emu_event") -- SDL key codes self.event_map = self.sdl_event_map else @@ -316,12 +315,14 @@ function Input:init() end print(_("Auto-detected Kindle Touch")) elseif Device:isKobo() then + firm_rev = Device:getFirmVer() input.open("/dev/input/event1") Device:setTouchInputDev("/dev/input/event1") input.open("/dev/input/event0") -- Light button and sleep slider print(_("Auto-detected Kobo")) self:adjustKoboEventMap() - if dev_mod ~= 'Kobo_trilogy' then + if dev_mod ~= 'Kobo_trilogy' and firm_rev == "2.6.1" + or dev_mod == 'Kobo_dragon' then function Input:eventAdjustHook(ev) if ev.type == EV_ABS then if ev.code == ABS_X then @@ -339,6 +340,19 @@ function Input:init() end return ev end + else + function Input:eventAdjustHook(ev) + if ev.code == ABS_X then + -- We always have to substract from the physical x, + -- regardless of the orientation + if (Screen.width 24 and 24 or intensity - self.intensity = intensity - self.lipc_handle:set_int_property("com.lab126.powerd", "flIntensity", intensity) - UIManager:show(Notification:new{ - text = msg..intensity, - timeout = 1 - }) - end - if Device:isKobo() then - if self.fl == nil then - ReaderFrontLight:init() - end - if self.fl ~= nil then - self.fl:setBrightness(intensity) - self.intensity = intensity - end - end - return true +function ReaderFrontLight:addToMainMenu(tab_item_table) + -- insert fldial command to main reader menu + table.insert(tab_item_table.main, { + text = _("Frontlight settings"), + callback = function() + self:onShowFlDialog() + end, + }) end -function ReaderFrontLight:toggle() - if Device:isKobo() then - if self.fl == nil then - ReaderFrontLight:init() - end - if self.fl ~= nil then - self.fl:toggle() - end +function ReaderFrontLight:onShowFlDialog() + local fl = Device:getFrontlight() + self.fl_dialog = InputDialog:new{ + title = _("Frontlight Level"), + input_hint = ("(%d - %d)"):format(fl.min, fl.max), + buttons = { + { + { + text = _("Toggle"), + enabled = true, + callback = function() + fl:toggle() + end, + }, + { + text = _("Apply"), + enabled = true, + callback = function() + self:fldialIntensity() + end, + }, + { + text = _("OK"), + enabled = true, + callback = function() + self:fldialIntensity() + self:close() + end, + }, + + }, + }, + input_type = "number", + width = Screen:getWidth() * 0.8, + height = Screen:getHeight() * 0.2, + } + self.fl_dialog:onShowKeyboard() + UIManager:show(self.fl_dialog) +end + +function ReaderFrontLight:close() + self.fl_dialog:onClose() + G_reader_settings:saveSetting("frontlight_intensity", Device:getFrontlight().intensity) + UIManager:close(self.fl_dialog) +end + +function ReaderFrontLight:fldialIntensity() + local number = tonumber(self.fl_dialog:getInputText()) + if number ~= nil then + Device:getFrontlight():setIntensity(number) end - return true end diff --git a/frontend/ui/reader/readermenu.lua b/frontend/ui/reader/readermenu.lua index e0d297a56..157c17f3e 100644 --- a/frontend/ui/reader/readermenu.lua +++ b/frontend/ui/reader/readermenu.lua @@ -56,7 +56,6 @@ function ReaderMenu:setUpdateItemTable() 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() diff --git a/frontend/ui/reader/readerview.lua b/frontend/ui/reader/readerview.lua index 1967790a0..b6d1b652d 100644 --- a/frontend/ui/reader/readerview.lua +++ b/frontend/ui/reader/readerview.lua @@ -1,3 +1,4 @@ +require "ui/widget/group" require "ui/reader/readerflip" require "ui/reader/readerfooter" require "ui/reader/readerdogear" diff --git a/frontend/ui/readerui.lua b/frontend/ui/readerui.lua index 96b8fd079..171283245 100644 --- a/frontend/ui/readerui.lua +++ b/frontend/ui/readerui.lua @@ -108,13 +108,12 @@ function ReaderUI:init() } table.insert(self, highlight) -- goto - local goto = ReaderGoto:new{ + table.insert(self, ReaderGoto:new{ dialog = self.dialog, view = self[1], ui = self, document = self.document, - } - table.insert(self, goto) + }) -- dictionary local dict = ReaderDictionary:new{ dialog = self.dialog, @@ -129,14 +128,15 @@ function ReaderUI:init() view = self[1], ui = self } - -- frontlight controller - local reader_fl = ReaderFrontLight:new{ - dialog = self.dialog, - view = self[1], - ui = self - } table.insert(self.active_widgets, reader_ss) - table.insert(self.active_widgets, reader_fl) + if Device:getFrontlight() then + -- frontlight controller + table.insert(self, ReaderFrontLight:new{ + dialog = self.dialog, + view = self[1], + ui = self + }) + end if self.document.info.has_pages then -- for page specific controller diff --git a/frontend/ui/uimanager.lua b/frontend/ui/uimanager.lua index a54560616..68853b053 100644 --- a/frontend/ui/uimanager.lua +++ b/frontend/ui/uimanager.lua @@ -1,6 +1,7 @@ require "ui/geometry" require "ui/device" require "ui/inputevent" +require "ui/widget/container" require "ui/screen" require "debug" require "gettext" @@ -290,6 +291,8 @@ function UIManager:run() Device:usbPlugIn() elseif input_event == "NotCharging" then Device:usbPlugOut() + elseif input_event == "Light" then + Device:getFrontlight():toggle() else self:sendEvent(input_event) end diff --git a/frontend/ui/widget/base.lua b/frontend/ui/widget/base.lua index 6d4d85cb4..b66b6e49d 100644 --- a/frontend/ui/widget/base.lua +++ b/frontend/ui/widget/base.lua @@ -43,10 +43,24 @@ rather than class variables. --]] Widget = EventListener:new() -function Widget:new(o) +--[[ +Use this method to define a class that's inherited from current class. +It only setup the metabale (or prototype chain) and will not initiatie +a real instance, i.e. call self:init() +--]] +function Widget:extend(o) local o = o or {} setmetatable(o, self) self.__index = self + return o +end + +--[[ +Use this method to initiatie a instance of a class, don't use it for class +definition. +--]] +function Widget:new(o) + o = self:extend(o) -- Both o._init and o.init are called on object create. But o._init is used -- for base widget initialization (basic component used to build other -- widgets). While o.init is for higher level widgets, for example Menu diff --git a/frontend/ui/widget/filechooser.lua b/frontend/ui/widget/filechooser.lua index 38d70bbff..fc17fd1fd 100644 --- a/frontend/ui/widget/filechooser.lua +++ b/frontend/ui/widget/filechooser.lua @@ -1,8 +1,9 @@ require "ui/widget/menu" -FileChooser = Menu:new{ +FileChooser = Menu:extend{ height = Screen:getHeight(), width = Screen:getWidth(), + no_title = true, path = lfs.currentdir(), parent = nil, show_hidden = false, @@ -10,7 +11,8 @@ FileChooser = Menu:new{ } function FileChooser:init() - self:changeToPath(self.path) + self:updateItemTableFromPath(self.path) + Menu.init(self) -- call parent's init() end function FileChooser:compressPath(item_path) @@ -22,11 +24,12 @@ function FileChooser:compressPath(item_path) return path end -function FileChooser:changeToPath(path) +function FileChooser:updateItemTableFromPath(path) path = self:compressPath(path) local dirs = {} local files = {} self.path = path + for f in lfs.dir(self.path) do if self.show_hidden or not string.match(f, "^%.[^.]") then local filename = self.path.."/"..f @@ -53,15 +56,16 @@ function FileChooser:changeToPath(path) for _, file in ipairs(files) do table.insert(self.item_table, { text = file, path = self.path.."/"..file }) end +end - Menu.init(self) -- call parent's init() +function FileChooser:changeToPath(path) + self:updateItemTableFromPath(path) + self:updateItems(1) end function FileChooser:onMenuSelect(item) if lfs.attributes(item.path, "mode") == "directory" then - UIManager:close(self) self:changeToPath(item.path) - UIManager:show(self) else self:onFileSelect(item.path) end diff --git a/frontend/ui/widget/menu.lua b/frontend/ui/widget/menu.lua index fc157a2df..41649daed 100644 --- a/frontend/ui/widget/menu.lua +++ b/frontend/ui/widget/menu.lua @@ -238,6 +238,9 @@ Menu = FocusManager:new{ -- set this to true to not paint as popup menu is_borderless = false, + -- if you want to embed the menu widget into another widget, set + -- this to false + is_popout = true, -- set this to true to add close button has_close_button = true, -- close_callback is a function, which is executed when menu is closed @@ -260,7 +263,7 @@ function Menu:_recalculateDimen() -- we need to substract border, margin and padding self.item_dimen.w = self.item_dimen.w - 14 end - self.perpage = math.floor(self.dimen.h / self.item_dimen.h) - 2 + self.perpage = math.floor((self.dimen.h - self.dimen.x) / self.item_dimen.h) - 2 self.page_num = math.ceil(#self.item_table / self.perpage) end @@ -310,12 +313,15 @@ function Menu:init() self.page_info_text, self.page_info_right_chev } + -- group for menu layout local content = VerticalGroup:new{ - self.title_bar, self.item_group, self.page_info, } + if not self.no_title then + table.insert(content, 1, self.title_bar) + end -- maintain reference to content so we can change it later self.content_group = content @@ -348,16 +354,19 @@ function Menu:init() menu = self, }) end - self.ges_events.TapCloseAllMenus = { - GestureRange:new{ - ges = "tap", - range = Geom:new{ - x = 0, y = 0, - w = Screen:getWidth(), - h = Screen:getHeight(), + -- watch for outer region if it's a self contained widget + if self.is_popout then + self.ges_events.TapCloseAllMenus = { + GestureRange:new{ + ges = "tap", + range = Geom:new{ + x = 0, y = 0, + w = Screen:getWidth(), + h = Screen:getHeight(), + } } } - } + end self.ges_events.Swipe = { GestureRange:new{ ges = "swipe", @@ -399,6 +408,11 @@ function Menu:updateItems(select_number) self.content_group:resetLayout() self:_recalculateDimen() + -- default to select the first item + if not select_number then + select_number = 1 + end + for c = 1, self.perpage do -- calculate index in item_table local i = (self.page - 1) * self.perpage + c diff --git a/koreader-base b/koreader-base index 698fb1764..2dfda0da6 160000 --- a/koreader-base +++ b/koreader-base @@ -1 +1 @@ -Subproject commit 698fb1764ffc0eafbd5cdb2dcc6d8165cca8d8f0 +Subproject commit 2dfda0da69b721c0145b174cf3e5fb578c2894e1 diff --git a/koreader.sh b/koreader.sh index 81fff38e5..f10015fc7 100755 --- a/koreader.sh +++ b/koreader.sh @@ -36,7 +36,7 @@ fi #killall -stop cvm # finally call reader -./reader.lua "$1" 2> crash.log +./reader.lua "$@" 2> crash.log # clean up forked process in case the reader crashed killall reader.lua diff --git a/koreader_kobo.sh b/koreader_kobo.sh index 16e7b1dfb..2cd418578 100644 --- a/koreader_kobo.sh +++ b/koreader_kobo.sh @@ -14,7 +14,7 @@ export STARDICT_DATA_DIR="data/dict" killall nickel # finally call reader -./reader.lua "$1" 2> crash.log +./reader.lua /mnt/onboard 2> crash.log # continue with nickel diff --git a/reader.lua b/reader.lua index e90860bab..469476e1f 100755 --- a/reader.lua +++ b/reader.lua @@ -4,35 +4,22 @@ require "defaults" package.path = "./frontend/?.lua" package.cpath = "/usr/lib/lua/?.so" require "ui/uimanager" -require "ui/widget/filechooser" require "ui/widget/infomessage" require "ui/readerui" require "document/document" require "settings" require "dbg" require "gettext" +require "apps/filemanager/fm" - -HomeMenu = InputContainer:new{ - item_table = {}, - key_events = { - TapShowMenu = { {"Home"}, doc = _("Show Home Menu")}, - }, - ges_events = { - TapShowMenu = { - GestureRange:new{ - ges = "tap", - range = Geom:new{ - x = 0, y = 0, - w = Screen:getWidth(), - h = 25, - } - } - }, - }, -} +Profiler = nil function exitReader() + if Profiler ~= nil then + Profiler:stop() + Profiler:dump("./profile.html") + end + G_reader_settings:close() input.closeAll() @@ -58,70 +45,7 @@ function exitReader() os.exit(0) end -function HomeMenu:setUpdateItemTable() - function readHistDir(order_arg, re) - local pipe_out = io.popen("ls "..order_arg.." -1 ./history") - for f in pipe_out:lines() do - table.insert(re, { - dir = DocSettings:getPathFromHistory(f), - name = DocSettings:getNameFromHistory(f), - }) - end - end - - local hist_sub_item_table = {} - local last_files = {} - readHistDir("-c", last_files) - for _,v in pairs(last_files) do - table.insert(hist_sub_item_table, { - text = v.name, - callback = function() - showReader(v.dir .. "/" .. v.name) - end - }) - end - table.insert(self.item_table, { - text = _("Last documents"), - sub_item_table = hist_sub_item_table, - }) - - table.insert(self.item_table, { - text = _("Exit"), - callback = function() - exitReader() - end - }) -end - -function HomeMenu:onTapShowMenu() - self.item_table = {} - self:setUpdateItemTable() - - local menu_container = CenterContainer:new{ - ignore = "height", - dimen = Screen:getSize(), - } - - local home_menu = Menu:new{ - show_parent = menu_container, - title = _("Home menu"), - item_table = self.item_table, - width = Screen:getWidth() - 100, - } - - menu_container[1] = home_menu - - home_menu.close_callback = function () - UIManager:close(menu_container) - end - - UIManager:show(menu_container) - - return true -end - - -function showReader(file, pass) +function showReaderUI(file, pass) local document = DocumentRegistry:openDocument(file) if not document then UIManager:show(InfoMessage:new{ @@ -141,47 +65,14 @@ function showReader(file, pass) end function showHomePage(path) - local exclude_dirs = {"%.sdr$"} - - local HomePage = InputContainer:new{ - } - - local FileManager = FileChooser:new{ - show_parent = HomePage, - title = _("FileManager"), - path = path, - width = Screen:getWidth(), - height = Screen:getHeight(), - 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 + UIManager:show(FileManager:new{ + dimen = Screen:getSize(), + root_path = path, + onExit = function() + exitReader() + UIManager:quit() end - } - - table.insert(HomePage, FileManager) - table.insert(HomePage, HomeMenu) - - function FileManager:onFileSelect(file) - showReader(file) - return true - end - - function FileManager:onClose() - exitReader() - --UIManager:quit() - return true - end - - UIManager:show(HomePage) + }) end @@ -189,6 +80,7 @@ end -- option parsing: longopts = { debug = "d", + profile = "p", help = "h", } @@ -197,6 +89,7 @@ function showusage() print(_("Read all the books on your E-Ink reader")) print("") print(_("-d start in debug mode")) + print(_("-p [rows] enable Lua code profiling")) print(_("-h show this usage help")) print("") print(_("If you give the name of a directory instead of a file path, a file")) @@ -209,15 +102,38 @@ function showusage() return end -if ARGV[1] == "-h" then - return showusage() -end - local argidx = 1 -if ARGV[1] == "-d" then - Dbg:turnOn() +while argidx <= #ARGV do + local arg = ARGV[argidx] argidx = argidx + 1 -else + if arg == "--" then break end + -- parse longopts + if arg:sub(1,2) == "--" then + local opt = longopts[arg:sub(3)] + if opt ~= nil then arg = "-"..opt end + end + -- code for each option + if arg == "-h" then + return showusage() + elseif arg == "-d" then + Dbg:turnOn() + elseif arg == "-p" then + require "lulip" + Profiler = lulip:new() + pcall(function() + -- set maxrows only if the optional arg is numeric + Profiler:maxrows(ARGV[argidx] + 0) + argidx = argidx + 1 + end) + Profiler:start() + else + -- not a recognized option, should be a filename + argidx = argidx - 1 + break + end +end + +if not Dbg.is_on then DEBUG = function() end end @@ -238,16 +154,24 @@ local last_file = G_reader_settings:readSetting("lastfile") --@TODO we can read version here, refer to commit in master tree: (houqp) --87712cf0e43fed624f8a9f610be42b1fe174b9fe +do + local fl = Device:getFrontlight() + if fl and fl.restore_settings then + local intensity = G_reader_settings:readSetting("frontlight_intensity") + intensity = intensity or fl.intensity + fl:setIntensity(intensity) + end +end if ARGV[argidx] and ARGV[argidx] ~= "" then if lfs.attributes(ARGV[argidx], "mode") == "directory" then showHomePage(ARGV[argidx]) elseif lfs.attributes(ARGV[argidx], "mode") == "file" then - showReader(ARGV[argidx]) + showReaderUI(ARGV[argidx]) end UIManager:run() elseif last_file and lfs.attributes(last_file, "mode") == "file" then - showReader(last_file) + showReaderUI(last_file) UIManager:run() else return showusage() diff --git a/resources/koreader.png b/resources/koreader.png new file mode 100644 index 000000000..1e6043247 Binary files /dev/null and b/resources/koreader.png differ