mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Merge pull request #683 from houqp/new_ui_houqp
Bug fix & added simple TOC menu & bookmark support & notification widget
This commit is contained in:
@@ -68,6 +68,10 @@ function Device:hasNoKeyboard()
|
||||
return self:isTouchDevice() or (self.model == "Kindle4")
|
||||
end
|
||||
|
||||
function Device:hasKeyboard()
|
||||
return not self:hasNoKeyboard()
|
||||
end
|
||||
|
||||
function Device:isTouchDevice()
|
||||
if not self.model then
|
||||
self.model = self:getModel()
|
||||
|
||||
@@ -458,7 +458,7 @@ override this function to process the item selected in a different manner
|
||||
]]--
|
||||
function Menu:onMenuSelect(item)
|
||||
if item.sub_item_table == nil then
|
||||
UIManager:close(self)
|
||||
self.close_callback()
|
||||
self:onMenuChoice(item)
|
||||
else
|
||||
-- save menu title for later resume
|
||||
|
||||
52
frontend/ui/notification.lua
Normal file
52
frontend/ui/notification.lua
Normal file
@@ -0,0 +1,52 @@
|
||||
require "ui/ui"
|
||||
require "ui/widget"
|
||||
|
||||
--[[
|
||||
Widget that displays a tiny notification on top of screen
|
||||
--]]
|
||||
Notification = InputContainer:new{
|
||||
face = Font:getFace("infofont", 20),
|
||||
text = "Null Message",
|
||||
timeout = nil,
|
||||
|
||||
key_events = {
|
||||
AnyKeyPressed = { { Input.group.Any }, seqtext = "any key", doc = "close dialog" }
|
||||
}
|
||||
}
|
||||
|
||||
function Notification:init()
|
||||
-- we construct the actual content here because self.text is only available now
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = Geom:new{
|
||||
w = Screen:getWidth(),
|
||||
h = Screen:getHeight()/10,
|
||||
},
|
||||
ignore = "height",
|
||||
FrameContainer:new{
|
||||
background = 0,
|
||||
radius = 0,
|
||||
HorizontalGroup:new{
|
||||
align = "center",
|
||||
TextBoxWidget:new{
|
||||
text = self.text,
|
||||
face = self.face,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
function Notification:onShow()
|
||||
-- triggered by the UIManager after we got successfully shown (not yet painted)
|
||||
if self.timeout then
|
||||
UIManager:scheduleIn(self.timeout, function() UIManager:close(self) end)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function Notification:onAnyKeyPressed()
|
||||
-- triggered by our defined key events
|
||||
UIManager:close(self)
|
||||
return true
|
||||
end
|
||||
|
||||
148
frontend/ui/reader/readerbookmark.lua
Normal file
148
frontend/ui/reader/readerbookmark.lua
Normal file
@@ -0,0 +1,148 @@
|
||||
require "ui/notification"
|
||||
|
||||
ReaderBookmark = InputContainer:new{
|
||||
bm_menu_title = "Bookmarks",
|
||||
bookmarks = nil,
|
||||
}
|
||||
|
||||
function ReaderBookmark:init()
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events = {
|
||||
ShowToc = {
|
||||
{ "B" },
|
||||
doc = "show bookmarks" },
|
||||
}
|
||||
elseif Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
AddBookmark = {
|
||||
GestureRange:new{
|
||||
ges = "double_tap",
|
||||
range = Geom:new{
|
||||
x = Screen:getWidth()/2, y = 0,
|
||||
w = Screen:getWidth()/2,
|
||||
h = Screen:getHeight()/2
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function ReaderBookmark:onReadSettings(config)
|
||||
self.bookmarks = config:readSetting("bookmarks") or {}
|
||||
end
|
||||
|
||||
function ReaderBookmark:onCloseDocument()
|
||||
self.ui.doc_settings:saveSetting("bookmarks", self.bookmarks)
|
||||
end
|
||||
|
||||
function ReaderBookmark:onSetDimensions(dimen)
|
||||
self.dimen = dimen
|
||||
end
|
||||
|
||||
function ReaderBookmark:onAddBookmark()
|
||||
local pn_or_xp = nil
|
||||
if self.ui.document.getXPointer then
|
||||
pn_or_xp = self.ui.document:getXPointer()
|
||||
else
|
||||
pn_or_xp = self.view.state.page
|
||||
end
|
||||
|
||||
local noti_text = "Bookmark added."
|
||||
if not self:addBookmark(pn_or_xp) then
|
||||
noti_text = "Page already marked!"
|
||||
end
|
||||
UIManager:show(Notification:new{
|
||||
text = noti_text,
|
||||
timeout = 3
|
||||
})
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderBookmark:onShowBookmark()
|
||||
-- build up item_table
|
||||
for k, v in ipairs(self.bookmarks) do
|
||||
local page = v.page
|
||||
-- for CREngine, bookmark page is xpointer
|
||||
if type(page) == "string" then
|
||||
page = self.ui.document:getPageFromXPointer(v.page)
|
||||
end
|
||||
v.text = "Page "..page.." "..v.notes.." @ "..v.datetime
|
||||
end
|
||||
|
||||
local bm_menu = Menu:new{
|
||||
title = "Bookmarks",
|
||||
item_table = self.bookmarks,
|
||||
width = Screen:getWidth()-20,
|
||||
height = Screen:getHeight(),
|
||||
}
|
||||
-- buid up menu widget method as closure
|
||||
local doc = self.ui.document
|
||||
local sendEv = function(ev)
|
||||
self.ui:handleEvent(ev)
|
||||
end
|
||||
function bm_menu:onMenuChoice(item)
|
||||
if doc.info.has_pages then
|
||||
sendEv(Event:new("PageUpdate", item.page))
|
||||
elseif self.view.view_mode == "page" then
|
||||
sendEv(Event:new("PageUpdate", doc:getPageFromXPointer(item.page)))
|
||||
else
|
||||
sendEv(Event:new("PosUpdate", doc:getPosFromXPointer(item.page)))
|
||||
end
|
||||
end
|
||||
|
||||
local menu_container = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
bm_menu,
|
||||
}
|
||||
bm_menu.close_callback = function()
|
||||
UIManager:close(menu_container)
|
||||
end
|
||||
|
||||
UIManager:show(menu_container)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderBookmark:addToMainMenu(item_table)
|
||||
-- insert table to main reader menu
|
||||
table.insert(item_table, {
|
||||
text = self.bm_menu_title,
|
||||
callback = function()
|
||||
self:onShowBookmark()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
--[[
|
||||
return nil if page already marked, otherwise, return true
|
||||
for CREngine, bookmark page is xpointer instead of page number
|
||||
--]]
|
||||
function ReaderBookmark:addBookmark(pn_or_xp)
|
||||
for k,v in ipairs(self.bookmarks) do
|
||||
if v.page == pn_or_xp then
|
||||
return nil
|
||||
end
|
||||
end
|
||||
-- build notes from TOC
|
||||
local notes = self.ui.toc:getTocTitleByPage(pn_or_xp)
|
||||
if notes ~= "" then
|
||||
notes = "in "..notes
|
||||
end
|
||||
mark_item = {
|
||||
page = pn_or_xp,
|
||||
datetime = os.date("%Y-%m-%d %H:%M:%S"),
|
||||
notes = notes,
|
||||
}
|
||||
table.insert(self.bookmarks, mark_item)
|
||||
table.sort(self.bookmarks, function(a,b)
|
||||
return self:isBookmarkInSequence(a, b)
|
||||
end)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderBookmark:isBookmarkInSequence(a, b)
|
||||
return a.page < b.page
|
||||
end
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ function ReaderMenu:onShowMenu()
|
||||
end
|
||||
|
||||
local menu_container = CenterContainer:new{
|
||||
ignore = "height",
|
||||
dimen = Screen:getSize(),
|
||||
main_menu,
|
||||
}
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
ReaderPanning = InputContainer:new{
|
||||
key_events = {
|
||||
-- these will all generate the same event, just with different arguments
|
||||
MoveUp = { {"Up"}, doc = "move visible area up", event = "Panning", args = {0, -1} },
|
||||
MoveDown = { {"Down"}, doc = "move visible area down", event = "Panning", args = {0, 1} },
|
||||
MoveLeft = { {"Left"}, doc = "move visible area left", event = "Panning", args = {-1, 0} },
|
||||
MoveRight = { {"Right"}, doc = "move visible area right", event = "Panning", args = {1, 0} },
|
||||
},
|
||||
|
||||
-- defaults
|
||||
panning_steps = {
|
||||
normal = 50,
|
||||
@@ -16,6 +8,27 @@ ReaderPanning = InputContainer:new{
|
||||
},
|
||||
}
|
||||
|
||||
function ReaderPanning:init()
|
||||
if Device:isTouchDevice() then
|
||||
else
|
||||
self.key_events = {
|
||||
-- these will all generate the same event, just with different arguments
|
||||
MoveUp = {
|
||||
{ "Up" }, doc = "move visible area up",
|
||||
event = "Panning", args = {0, -1} },
|
||||
MoveDown = {
|
||||
{ "Down" }, doc = "move visible area down",
|
||||
event = "Panning", args = {0, 1} },
|
||||
MoveLeft = {
|
||||
{ "Left" }, doc = "move visible area left",
|
||||
event = "Panning", args = {-1, 0} },
|
||||
MoveRight = {
|
||||
{ "Right" }, doc = "move visible area right",
|
||||
event = "Panning", args = {1, 0} },
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderPanning:onSetDimensions(dimensions)
|
||||
self.dimen = dimensions
|
||||
end
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
ReaderToc = InputContainer:new{
|
||||
key_events = {
|
||||
ShowToc = { {"T"}, doc = "show Table of Content menu"},
|
||||
},
|
||||
dimen = Geom:new{ w = Screen:getWidth()-20, h = Screen:getHeight()-20},
|
||||
current_page = 0,
|
||||
current_pos = 0,
|
||||
toc_menu_title = "Table of contents",
|
||||
}
|
||||
|
||||
function ReaderToc:init()
|
||||
if not Device:hasNoKeyboard() then
|
||||
self.key_events = {
|
||||
ShowToc = {
|
||||
{ "T" },
|
||||
doc = "show Table of Content menu" },
|
||||
}
|
||||
end
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function ReaderToc:cleanUpTocTitle(title)
|
||||
return (title:gsub("\13", ""))
|
||||
end
|
||||
@@ -15,20 +21,24 @@ function ReaderToc:onSetDimensions(dimen)
|
||||
self.dimen = dimen
|
||||
end
|
||||
|
||||
--function ReaderToc:fillToc()
|
||||
--self.toc = self.doc:getToc()
|
||||
--end
|
||||
function ReaderToc:fillToc()
|
||||
self.toc = self.ui.document:getToc()
|
||||
end
|
||||
|
||||
-- getTocTitleByPage wrapper, so specific reader
|
||||
-- _getTocTitleByPage wrapper, so specific reader
|
||||
-- can tranform pageno according its need
|
||||
function ReaderToc:getTocTitleByPage(pageno)
|
||||
return self:_getTocTitleByPage(pageno)
|
||||
function ReaderToc:getTocTitleByPage(pn_or_xp)
|
||||
local page = pn_or_xp
|
||||
if type(pn_or_xp) == "string" then
|
||||
page = self.ui.document:getPageFromXPointer(pn_or_xp)
|
||||
end
|
||||
return self:_getTocTitleByPage(page)
|
||||
end
|
||||
|
||||
function ReaderToc:_getTocTitleByPage(pageno)
|
||||
if not self.toc then
|
||||
-- build toc when needed.
|
||||
self:fillToc()
|
||||
-- build toc when needed.
|
||||
self:fillToc()
|
||||
end
|
||||
|
||||
-- no table of content
|
||||
@@ -56,29 +66,36 @@ function ReaderToc:onShowToc()
|
||||
for _,v in ipairs(items) do
|
||||
v.text = (" "):rep(v.depth-1)..self:cleanUpTocTitle(v.title)
|
||||
end
|
||||
|
||||
local toc_menu = Menu:new{
|
||||
title = "Table of Contents",
|
||||
item_table = items,
|
||||
dimen = self.dimen,
|
||||
ui = self.ui
|
||||
ui = self.ui,
|
||||
width = Screen:getWidth()-20,
|
||||
height = Screen:getHeight(),
|
||||
}
|
||||
function toc_menu:onMenuChoice(item)
|
||||
self.ui:handleEvent(Event:new("PageUpdate", item.page))
|
||||
end
|
||||
|
||||
UIManager:show(toc_menu)
|
||||
local menu_container = CenterContainer:new{
|
||||
dimen = Screen:getSize(),
|
||||
toc_menu,
|
||||
}
|
||||
toc_menu.close_callback = function()
|
||||
UIManager:close(menu_container)
|
||||
end
|
||||
|
||||
UIManager:show(menu_container)
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderToc:onSetDimensions(dimen)
|
||||
self.dimen = dimen
|
||||
function ReaderToc:addToMainMenu(item_table)
|
||||
-- insert table to main reader menu
|
||||
table.insert(item_table, {
|
||||
text = self.toc_menu_title,
|
||||
callback = function()
|
||||
self:onShowToc()
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
function ReaderToc:onPageUpdate(new_page_no)
|
||||
self.current_page = new_page_no
|
||||
end
|
||||
|
||||
function ReaderToc:onPosUpdate(new_pos)
|
||||
self.current_pos = new_pos
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -122,6 +122,8 @@ function ReaderView:PanningUpdate(dx, dy)
|
||||
UIManager:setDirty(self.dialog)
|
||||
DEBUG("on pan: page_area", self.page_area)
|
||||
DEBUG("on pan: visible_area", self.visible_area)
|
||||
self.ui:handleEvent(
|
||||
Event:new("ViewRecalculate", self.visible_area, self.page_area))
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -6,6 +6,7 @@ require "ui/reader/readerrotation"
|
||||
require "ui/reader/readerpaging"
|
||||
require "ui/reader/readerrolling"
|
||||
require "ui/reader/readertoc"
|
||||
require "ui/reader/readerbookmark"
|
||||
require "ui/reader/readerfont"
|
||||
require "ui/reader/readermenu"
|
||||
|
||||
@@ -18,7 +19,6 @@ it works using data gathered from a document interface
|
||||
ReaderUI = InputContainer:new{
|
||||
key_events = {
|
||||
Close = { {"Home"}, doc = "close document", event = "Close" },
|
||||
Back = { {"Back"}, doc = "close document", event = "Close" },
|
||||
},
|
||||
|
||||
-- our own size
|
||||
@@ -41,6 +41,12 @@ function ReaderUI:init()
|
||||
self.dialog = self
|
||||
end
|
||||
|
||||
if Device:hasKeyboard() then
|
||||
self.key_events.Back = {
|
||||
{ "Back" }, doc = "close document",
|
||||
event = "Close" }
|
||||
end
|
||||
|
||||
self.doc_settings = DocSettings:open(self.document.file)
|
||||
|
||||
-- a view container (so it must be child #1!)
|
||||
@@ -56,18 +62,26 @@ function ReaderUI:init()
|
||||
view = self[1],
|
||||
ui = self
|
||||
}
|
||||
-- Toc menu controller
|
||||
self[3] = ReaderToc:new{
|
||||
-- reader menu controller
|
||||
self[3] = ReaderMenu:new{
|
||||
view = self[1],
|
||||
ui = self
|
||||
}
|
||||
self.menu = self[3] -- hold reference to menu widget
|
||||
-- Table of content controller
|
||||
self[4] = ReaderToc:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
}
|
||||
-- reader menu controller
|
||||
self[4] = ReaderMenu:new{
|
||||
self.toc = self[4] -- hold reference to bm widget
|
||||
-- bookmark controller
|
||||
local reader_bm = ReaderBookmark:new{
|
||||
dialog = self.dialog,
|
||||
view = self[1],
|
||||
ui = self
|
||||
}
|
||||
self.menu = self[4] -- hold reference to menu widget
|
||||
table.insert(self, reader_bm)
|
||||
|
||||
if self.document.info.has_pages then
|
||||
-- for page specific controller
|
||||
|
||||
@@ -126,9 +126,15 @@ function CenterContainer:paintTo(bb, x, y)
|
||||
-- throw error? paint to scrap buffer and blit partially?
|
||||
-- for now, we ignore this
|
||||
end
|
||||
self[1]:paintTo(bb,
|
||||
x + (self.dimen.w - contentSize.w)/2,
|
||||
y + (self.dimen.h - contentSize.h)/2)
|
||||
local x_pos = x
|
||||
local y_pos = y
|
||||
if self.ignore ~= "height" then
|
||||
y_pos = y + (self.dimen.h - contentSize.h)/2
|
||||
end
|
||||
if self.ignore ~= "width" then
|
||||
x_pos = x + (self.dimen.w - contentSize.w)/2
|
||||
end
|
||||
self[1]:paintTo(bb, x_pos, y_pos)
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -605,6 +611,10 @@ function InputContainer:_init()
|
||||
end
|
||||
end
|
||||
self.ges_events = new_ges_events
|
||||
|
||||
if not self.dimen then
|
||||
self.dimen = Geom:new{}
|
||||
end
|
||||
end
|
||||
|
||||
function InputContainer:paintTo(bb, x, y)
|
||||
|
||||
Reference in New Issue
Block a user