mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Kindle4NT improvements (#3745)
* [device][kindle4] add fake event to kindle4 * modify focusmanager to allow for more complex layout The focusmanager now naviguate the layout by avoiding nil value instead of relying on table lenght. It should be completely backward compatible * add Dpad naviguation to the touchmenu * fix crash because virtualkeyboard on non touch device the kindle4NT has no keyboard nor touch, the fix open the virtual keyboard so koreader dont crash but it's not useable * Enable device with keys to use the touchmenu * Don't get stuck in reader progress statistics plugin * [underlinecontainer] Fix and remove unused function References #1898.
This commit is contained in:
committed by
Frans de Jonge
parent
9849d89f0e
commit
e8aab49ee9
@@ -362,7 +362,12 @@ function FileManager:init()
|
||||
end
|
||||
|
||||
if Device:hasKeys() then
|
||||
self.key_events.Close = { {"Home"}, doc = "Close file manager" }
|
||||
self.key_events.Home = { {"Home"}, doc = "go home" }
|
||||
if not Device:isSDL() then
|
||||
--if not in the desktop emulator
|
||||
--remove the old Back key to exit koreader
|
||||
self.file_chooser.key_events.Close = nil
|
||||
end
|
||||
end
|
||||
|
||||
self:handleEvent(Event:new("SetDimensions", self.dimen))
|
||||
@@ -788,4 +793,8 @@ function FileManager:moveFile(from, to)
|
||||
return util.execute(self.mv_bin, from, to) == 0
|
||||
end
|
||||
|
||||
function FileManager:onHome()
|
||||
return self:goHome()
|
||||
end
|
||||
|
||||
return FileManager
|
||||
|
||||
@@ -306,7 +306,7 @@ function FileManagerMenu:onShowMenu()
|
||||
}
|
||||
|
||||
local main_menu
|
||||
if Device:isTouchDevice() then
|
||||
if Device:isTouchDevice() or Device:hasDPad() then
|
||||
local TouchMenu = require("ui/widget/touchmenu")
|
||||
main_menu = TouchMenu:new{
|
||||
width = Screen:getWidth(),
|
||||
|
||||
@@ -53,7 +53,6 @@ function ReaderMenu:init()
|
||||
self.registered_widgets = {}
|
||||
|
||||
if Device:hasKeys() then
|
||||
self.key_events = { Close = { { "Back" }, doc = "close menu" }, }
|
||||
if Device:isTouchDevice() then
|
||||
self.key_events.TapShowMenu = { { "Menu" }, doc = "show menu", }
|
||||
else
|
||||
@@ -241,7 +240,7 @@ function ReaderMenu:onShowReaderMenu(tab_index)
|
||||
}
|
||||
|
||||
local main_menu
|
||||
if Device:isTouchDevice() then
|
||||
if Device:isTouchDevice() or Device:hasDPad() then
|
||||
local TouchMenu = require("ui/widget/touchmenu")
|
||||
main_menu = TouchMenu:new{
|
||||
width = Screen:getWidth(),
|
||||
@@ -294,8 +293,10 @@ function ReaderMenu:_getTabIndexFromLocation(ges)
|
||||
if self.tab_item_table == nil then
|
||||
self:setUpdateItemTable()
|
||||
end
|
||||
if not ges then
|
||||
return self.last_tab_index
|
||||
-- if the start position is far right
|
||||
if ges.pos.x > 2 * Screen:getWidth() / 3 then
|
||||
elseif ges.pos.x > 2 * Screen:getWidth() / 3 then
|
||||
return #self.tab_item_table
|
||||
-- if the start position is far left
|
||||
elseif ges.pos.x < Screen:getWidth() / 3 then
|
||||
|
||||
@@ -52,11 +52,6 @@ local T = require("ffi/util").template
|
||||
|
||||
local ReaderUI = InputContainer:new{
|
||||
name = "ReaderUI",
|
||||
|
||||
key_events = {
|
||||
Close = { { "Home" },
|
||||
doc = "close document", event = "Close" },
|
||||
},
|
||||
active_widgets = {},
|
||||
|
||||
-- if we have a parent container, it must be referenced for now
|
||||
@@ -97,14 +92,17 @@ function ReaderUI:init()
|
||||
self.dialog = self
|
||||
end
|
||||
|
||||
if Device:hasKeys() then
|
||||
self.key_events.Back = {
|
||||
{ "Back" }, doc = "close document",
|
||||
event = "Close" }
|
||||
end
|
||||
|
||||
self.doc_settings = DocSettings:open(self.document.file)
|
||||
|
||||
if Device:hasKeys() then
|
||||
self.key_events.Home = { {"Home"}, doc = "open file browser" }
|
||||
if Device:isSDL() then
|
||||
--if in the desktop emulator
|
||||
--add the old Back key to exit koreader
|
||||
self.key_events.Close = { {"Back"}, doc = "Exit koreader" }
|
||||
end
|
||||
end
|
||||
|
||||
-- a view container (so it must be child #1!)
|
||||
-- all paintable widgets need to be a child of reader view
|
||||
self:registerModule("view", ReaderView:new{
|
||||
@@ -622,4 +620,8 @@ function ReaderUI:dealWithLoadDocumentFailure()
|
||||
error("crengine failed recognizing or parsing this file: unsupported or invalid document")
|
||||
end
|
||||
|
||||
function ReaderUI:onHome()
|
||||
return self:showFileManager()
|
||||
end
|
||||
|
||||
return ReaderUI
|
||||
|
||||
@@ -317,6 +317,7 @@ function Kindle4:init()
|
||||
}
|
||||
self.input.open("/dev/input/event0")
|
||||
self.input.open("/dev/input/event1")
|
||||
self.input.open("fake_events")
|
||||
Kindle.init(self)
|
||||
end
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ local Blitbuffer = require("ffi/blitbuffer")
|
||||
local Button = require("ui/widget/button")
|
||||
local CenterContainer = require("ui/widget/container/centercontainer")
|
||||
local CloseButton = require("ui/widget/closebutton")
|
||||
local Device = require("device")
|
||||
local Font = require("ui/font")
|
||||
local FrameContainer = require("ui/widget/container/framecontainer")
|
||||
local Geom = require("ui/geometry")
|
||||
@@ -25,7 +26,7 @@ local VerticalGroup = require("ui/widget/verticalgroup")
|
||||
local VerticalSpan = require("ui/widget/verticalspan")
|
||||
local util = require("util")
|
||||
local _ = require("gettext")
|
||||
local Screen = require("device").screen
|
||||
local Screen = Device.screen
|
||||
local template = require("ffi/util").template
|
||||
|
||||
local stats_book = {}
|
||||
@@ -82,6 +83,15 @@ function BookStatusWidget:init()
|
||||
show_parent = self,
|
||||
readonly = self.readonly,
|
||||
}
|
||||
|
||||
if Device:hasKeys() then
|
||||
self.key_events = {
|
||||
--don't get locked in on non touch devices
|
||||
AnyKeyPressed = { { Device.input.group.Any },
|
||||
seqtext = "any key", doc = "close dialog" }
|
||||
}
|
||||
end
|
||||
|
||||
local screen_size = Screen:getSize()
|
||||
self[1] = FrameContainer:new{
|
||||
width = screen_size.w,
|
||||
|
||||
@@ -18,10 +18,6 @@ local UnderlineContainer = WidgetContainer:new{
|
||||
}
|
||||
|
||||
function UnderlineContainer:getSize()
|
||||
return self:getContentSize()
|
||||
end
|
||||
|
||||
function UnderlineContainer:getContentSize()
|
||||
local contentSize = self[1]:getSize()
|
||||
return Geom:new{
|
||||
w = contentSize.w,
|
||||
@@ -36,7 +32,7 @@ function UnderlineContainer:paintTo(bb, x, y)
|
||||
w = container_size.w,
|
||||
h = container_size.h
|
||||
}
|
||||
local content_size = self:getContentSize()
|
||||
local content_size = self[1]:getSize()
|
||||
local p_y = y
|
||||
if self.vertical_align == "center" then
|
||||
p_y = math.floor((container_size.h - content_size.h) / 2) + y
|
||||
|
||||
@@ -9,18 +9,16 @@ supports a 2D model of active elements
|
||||
|
||||
e.g.:
|
||||
layout = {
|
||||
{ textinput, textinput },
|
||||
{ okbutton, cancelbutton }
|
||||
{ textinput, textinput, item },
|
||||
{ okbutton, cancelbutton, item },
|
||||
{ nil, item, nil },
|
||||
{ nil, item, nil },
|
||||
{ nil, item, nil },
|
||||
}
|
||||
|
||||
this is a dialog with 2 rows. in the top row, there is the
|
||||
single (!) widget <textinput>. when the focus is in this
|
||||
group, left/right movement seems (!) to be doing nothing.
|
||||
|
||||
in the second row, there are two widgets and you can move
|
||||
left/right. also, you can go up from both to reach <textinput>,
|
||||
and from that go down and (depending on internat coordinates)
|
||||
reach either <okbutton> or <cancelbutton>.
|
||||
Navigate the layout by trying to avoid not set or nil value.
|
||||
Provide a simple wrap around in the vertical direction.
|
||||
The first element of the first table must be valid to ensure
|
||||
to not get stuck in an invalid position.
|
||||
|
||||
but notice that this does _not_ do the layout for you,
|
||||
it rather defines an abstract layout.
|
||||
@@ -57,30 +55,17 @@ function FocusManager:onFocusMove(args)
|
||||
end
|
||||
local current_item = self.layout[self.selected.y][self.selected.x]
|
||||
while true do
|
||||
if self.selected.x + dx > #self.layout[self.selected.y]
|
||||
or self.selected.x + dx < 1 then
|
||||
break -- abort when we run into horizontal borders
|
||||
end
|
||||
|
||||
-- call widget wrap callbacks in vertical direction
|
||||
if self.selected.y + dy > #self.layout then
|
||||
if not self:onWrapLast() then
|
||||
break
|
||||
end
|
||||
elseif self.selected.y + dy < 1 then
|
||||
if not self:onWrapFirst() then
|
||||
if not self.layout[self.selected.y + dy] then
|
||||
--vertical borders, try to wraparound
|
||||
if not self:wrapAround(dy) then
|
||||
break
|
||||
end
|
||||
elseif not self.layout[self.selected.y + dy][self.selected.x + dx] then
|
||||
--vertical border, no wraparound
|
||||
break
|
||||
else
|
||||
self.selected.y = self.selected.y + dy
|
||||
if #self.layout[self.selected.y] == 0 then -- horizontal separator
|
||||
self.selected.y = self.selected.y + dy -- skip it
|
||||
end
|
||||
end
|
||||
self.selected.x = self.selected.x + dx
|
||||
if self.selected.x > #self.layout[self.selected.y] then
|
||||
-- smaller nb of items on new row than on prev row
|
||||
self.selected.x = #self.layout[self.selected.y]
|
||||
self.selected.x = self.selected.x + dx
|
||||
end
|
||||
|
||||
if self.layout[self.selected.y][self.selected.x] ~= current_item
|
||||
@@ -88,24 +73,28 @@ function FocusManager:onFocusMove(args)
|
||||
-- we found a different object to focus
|
||||
current_item:handleEvent(Event:new("Unfocus"))
|
||||
self.layout[self.selected.y][self.selected.x]:handleEvent(Event:new("Focus"))
|
||||
-- trigger a repaint (we need to be the registered widget!)
|
||||
-- trigger a fast repaint, this seem to not count toward a fullscreen eink resfresh
|
||||
-- TODO: is this really needed?
|
||||
UIManager:setDirty(self.show_parent or self, "partial")
|
||||
UIManager:setDirty(self.show_parent or self, "fast")
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function FocusManager:onWrapFirst()
|
||||
self.selected.y = #self.layout
|
||||
return true
|
||||
end
|
||||
|
||||
function FocusManager:onWrapLast()
|
||||
self.selected.y = 1
|
||||
return true
|
||||
function FocusManager:wrapAround(dy)
|
||||
--go to the last valid item directly above or below the current item
|
||||
--return false if none could be found
|
||||
local y = self.selected.y
|
||||
while self.layout[y - dy] and self.layout[y - dy][self.selected.x] do
|
||||
y = y - dy
|
||||
end
|
||||
if y ~= self.selected.y then
|
||||
self.selected.y = y
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function FocusManager:getFocusItem()
|
||||
|
||||
@@ -124,4 +124,19 @@ function IconButton:onHoldIconButton()
|
||||
return true
|
||||
end
|
||||
|
||||
function IconButton:onFocus()
|
||||
--quick and dirty, need better way to show focus
|
||||
self.image.invert=true
|
||||
return true
|
||||
end
|
||||
|
||||
function IconButton:onUnfocus()
|
||||
self.image.invert=false
|
||||
return true
|
||||
end
|
||||
|
||||
function IconButton:onTapSelect()
|
||||
self:onTapIconButton()
|
||||
end
|
||||
|
||||
return IconButton
|
||||
|
||||
@@ -88,6 +88,9 @@ if Device.isTouchDevice() then
|
||||
end)
|
||||
end
|
||||
end
|
||||
elseif not Device.hasKeyboard() then
|
||||
Keyboard = require("ui/widget/virtualkeyboard")
|
||||
function InputText:initEventListener() end --do nothing but doesn't crash for now
|
||||
else
|
||||
Keyboard = require("ui/widget/physicalkeyboard")
|
||||
function InputText:initEventListener() end
|
||||
|
||||
@@ -6,6 +6,8 @@ local Button = require("ui/widget/button")
|
||||
local CenterContainer = require("ui/widget/container/centercontainer")
|
||||
local CheckMark = require("ui/widget/checkmark")
|
||||
local Device = require("device")
|
||||
local Event = require("ui/event")
|
||||
local FocusManager = require("ui/widget/focusmanager")
|
||||
local Font = require("ui/font")
|
||||
local FrameContainer = require("ui/widget/container/framecontainer")
|
||||
local Geom = require("ui/geometry")
|
||||
@@ -20,12 +22,14 @@ local RightContainer = require("ui/widget/container/rightcontainer")
|
||||
local Size = require("ui/size")
|
||||
local TextWidget = require("ui/widget/textwidget")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local UnderlineContainer = require("ui/widget/container/underlinecontainer")
|
||||
local VerticalGroup = require("ui/widget/verticalgroup")
|
||||
local VerticalSpan = require("ui/widget/verticalspan")
|
||||
local util = require("ffi/util")
|
||||
local _ = require("gettext")
|
||||
local Screen = Device.screen
|
||||
local getMenuText = require("util").getMenuText
|
||||
local Input = Device.input
|
||||
local Screen = Device.screen
|
||||
|
||||
--[[
|
||||
TouchMenuItem widget
|
||||
@@ -97,7 +101,27 @@ function TouchMenuItem:init()
|
||||
},
|
||||
},
|
||||
}
|
||||
self[1] = self.item_frame
|
||||
|
||||
self._underline_container = UnderlineContainer:new{
|
||||
vertical_align = "center",
|
||||
dimen =self.dimen,
|
||||
self.item_frame
|
||||
}
|
||||
|
||||
self[1] = self._underline_container
|
||||
function self:isEnabled()
|
||||
return item_enabled ~= false and true
|
||||
end
|
||||
end
|
||||
|
||||
function TouchMenuItem:onFocus()
|
||||
self._underline_container.color = Blitbuffer.COLOR_BLACK
|
||||
return true
|
||||
end
|
||||
|
||||
function TouchMenuItem:onUnfocus()
|
||||
self._underline_container.color = Blitbuffer.COLOR_WHITE
|
||||
return true
|
||||
end
|
||||
|
||||
function TouchMenuItem:onTapSelect(arg, ges)
|
||||
@@ -202,9 +226,11 @@ function TouchMenuBar:init()
|
||||
callback = nil,
|
||||
padding_left = icon_padding,
|
||||
padding_right = icon_padding,
|
||||
menu = self.menu,
|
||||
}
|
||||
|
||||
table.insert(self.icon_widgets, ib)
|
||||
table.insert(self.menu.layout, ib) -- for the focusmanager
|
||||
|
||||
-- we have to use local variable here for closure callback
|
||||
local _start_seg = end_seg + icon_sep_width
|
||||
@@ -319,7 +345,7 @@ end
|
||||
--[[
|
||||
TouchMenu widget for hierarchical menus
|
||||
--]]
|
||||
local TouchMenu = InputContainer:new{
|
||||
local TouchMenu = FocusManager:new{
|
||||
tab_item_table = {},
|
||||
-- for returnning in multi-level menus
|
||||
item_table_stack = nil,
|
||||
@@ -351,6 +377,8 @@ function TouchMenu:init()
|
||||
end
|
||||
end
|
||||
|
||||
self.layout = {}
|
||||
|
||||
self.ges_events.TapCloseAllMenus = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
@@ -368,7 +396,10 @@ function TouchMenu:init()
|
||||
}
|
||||
}
|
||||
|
||||
self.key_events.Close = { {"Back"}, doc = "close touch menu" }
|
||||
self.key_events.Back = { {"Back"}, doc = "back to upper menu or close touchmenu" }
|
||||
self.key_events.NextPage = { {Input.group.PgFwd}, doc = "next page" }
|
||||
self.key_events.PrevPage = { {Input.group.PgBack}, doc = "previous page" }
|
||||
self.key_events.Press = { {"Press"}, doc = "chose selected item" }
|
||||
|
||||
local icons = {}
|
||||
for _,v in ipairs(self.tab_item_table) do
|
||||
@@ -509,7 +540,9 @@ function TouchMenu:updateItems()
|
||||
local old_dimen = self.dimen and self.dimen:copy()
|
||||
self:_recalculatePageLayout()
|
||||
self.item_group:clear()
|
||||
self.layout = {}
|
||||
table.insert(self.item_group, self.bar)
|
||||
table.insert(self.layout, self.bar.icon_widgets) --for the focusmanager
|
||||
|
||||
for c = 1, self.perpage do
|
||||
-- calculate index in item_table
|
||||
@@ -526,6 +559,9 @@ function TouchMenu:updateItems()
|
||||
show_parent = self.show_parent,
|
||||
}
|
||||
table.insert(self.item_group, item_tmp)
|
||||
if item_tmp:isEnabled() then
|
||||
table.insert(self.layout, {[self.cur_tab] = item_tmp}) --for the focusmanager
|
||||
end
|
||||
if item.separator and c ~= self.perpage then
|
||||
-- insert split line
|
||||
table.insert(self.item_group, self.split_line)
|
||||
@@ -553,6 +589,7 @@ function TouchMenu:updateItems()
|
||||
-- recalculate dimen based on new layout
|
||||
self.dimen.w = self.width
|
||||
self.dimen.h = self.item_group:getSize().h + self.bordersize*2 + self.padding*2
|
||||
self.selected = { x = self.cur_tab, y = 1 } --reset the position of the focusmanager
|
||||
|
||||
UIManager:setDirty("all", function()
|
||||
local refresh_dimen =
|
||||
@@ -707,4 +744,12 @@ function TouchMenu:onClose()
|
||||
self:closeMenu()
|
||||
end
|
||||
|
||||
function TouchMenu:onBack()
|
||||
self:backToUpperMenu()
|
||||
end
|
||||
|
||||
function TouchMenu:onPress()
|
||||
self:getFocusItem():handleEvent(Event:new("TapSelect"))
|
||||
end
|
||||
|
||||
return TouchMenu
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
local Blitbuffer = require("ffi/blitbuffer")
|
||||
local CenterContainer = require("ui/widget/container/centercontainer")
|
||||
local CloseButton = require("ui/widget/closebutton")
|
||||
local Device = require("device")
|
||||
local Font = require("ui/font")
|
||||
local FrameContainer = require("ui/widget/container/framecontainer")
|
||||
local Geom = require("ui/geometry")
|
||||
@@ -18,7 +19,7 @@ local VerticalGroup = require("ui/widget/verticalgroup")
|
||||
local VerticalSpan = require("ui/widget/verticalspan")
|
||||
local util = require("util")
|
||||
local _ = require("gettext")
|
||||
local Screen = require("device").screen
|
||||
local Screen = Device.screen
|
||||
|
||||
local LINE_COLOR = Blitbuffer.gray(0.4)
|
||||
local BG_COLOR = Blitbuffer.gray(0.2)
|
||||
@@ -46,6 +47,13 @@ function ReaderProgress:init()
|
||||
UIManager:setDirty(self, function()
|
||||
return "ui", self.dimen
|
||||
end)
|
||||
if Device:hasKeys() then
|
||||
self.key_events = {
|
||||
--don't get locked in on non touch devices
|
||||
AnyKeyPressed = { { Device.input.group.Any },
|
||||
seqtext = "any key", doc = "close dialog" }
|
||||
}
|
||||
end
|
||||
self[1] = FrameContainer:new{
|
||||
width = self.width,
|
||||
height = self.height,
|
||||
|
||||
Reference in New Issue
Block a user