mirror of https://github.com/koreader/koreader
separated dialog.lua into source files for each individual function
parent
1e9fdd818f
commit
5025be971d
@ -0,0 +1,45 @@
|
|||||||
|
require "ui/widget"
|
||||||
|
|
||||||
|
--[[
|
||||||
|
a button widget
|
||||||
|
]]
|
||||||
|
Button = WidgetContainer:new{
|
||||||
|
text = nil, -- mandatory
|
||||||
|
preselect = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function Button:init()
|
||||||
|
-- set FrameContainer content
|
||||||
|
self[1] = FrameContainer:new{
|
||||||
|
margin = 0,
|
||||||
|
bordersize = 3,
|
||||||
|
background = 0,
|
||||||
|
radius = 15,
|
||||||
|
padding = 2,
|
||||||
|
|
||||||
|
HorizontalGroup:new{
|
||||||
|
HorizontalSpan:new{ width = 8 },
|
||||||
|
TextWidget:new{
|
||||||
|
text = self.text,
|
||||||
|
face = Font:getFace("cfont", 20)
|
||||||
|
},
|
||||||
|
HorizontalSpan:new{ width = 8 },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.preselect then
|
||||||
|
self[1].color = 15
|
||||||
|
else
|
||||||
|
self[1].color = 5
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Button:onFocus()
|
||||||
|
self[1].color = 15
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function Button:onUnfocus()
|
||||||
|
self[1].color = 5
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,82 @@
|
|||||||
|
require "ui/widget"
|
||||||
|
require "ui/focusmanager"
|
||||||
|
require "ui/button"
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Widget that shows a message and OK/Cancel buttons
|
||||||
|
]]
|
||||||
|
ConfirmBox = FocusManager:new{
|
||||||
|
text = "no text",
|
||||||
|
width = nil,
|
||||||
|
ok_text = "OK",
|
||||||
|
cancel_text = "Cancel",
|
||||||
|
ok_callback = function() end,
|
||||||
|
cancel_callback = function() end,
|
||||||
|
}
|
||||||
|
|
||||||
|
function ConfirmBox:init()
|
||||||
|
-- calculate box width on the fly if not given
|
||||||
|
if not self.width then
|
||||||
|
self.width = Screen:getWidth() - 200
|
||||||
|
end
|
||||||
|
-- build bottons
|
||||||
|
self.key_events.Close = { {{"Home","Back"}}, doc = "cancel" }
|
||||||
|
self.key_events.Select = { {{"Enter","Press"}}, doc = "chose selected option" }
|
||||||
|
|
||||||
|
local ok_button = Button:new{
|
||||||
|
text = self.ok_text,
|
||||||
|
}
|
||||||
|
local cancel_button = Button:new{
|
||||||
|
text = self.cancel_text,
|
||||||
|
preselect = true
|
||||||
|
}
|
||||||
|
|
||||||
|
self.layout = { { ok_button, cancel_button } }
|
||||||
|
self.selected.x = 2 -- Cancel is default
|
||||||
|
|
||||||
|
self[1] = CenterContainer:new{
|
||||||
|
dimen = Screen:getSize(),
|
||||||
|
FrameContainer:new{
|
||||||
|
margin = 2,
|
||||||
|
background = 0,
|
||||||
|
padding = 10,
|
||||||
|
HorizontalGroup:new{
|
||||||
|
ImageWidget:new{
|
||||||
|
file = "resources/info-i.png"
|
||||||
|
},
|
||||||
|
HorizontalSpan:new{ width = 10 },
|
||||||
|
VerticalGroup:new{
|
||||||
|
align = "left",
|
||||||
|
TextBoxWidget:new{
|
||||||
|
text = self.text,
|
||||||
|
face = Font:getFace("cfont", 30),
|
||||||
|
width = self.width,
|
||||||
|
},
|
||||||
|
VerticalSpan:new{ width = 10 },
|
||||||
|
HorizontalGroup:new{
|
||||||
|
ok_button,
|
||||||
|
HorizontalSpan:new{ width = 10 },
|
||||||
|
cancel_button,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function ConfirmBox:onClose()
|
||||||
|
UIManager:close(self)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function ConfirmBox:onSelect()
|
||||||
|
DEBUG("selected:", self.selected.x)
|
||||||
|
if self.selected.x == 1 then
|
||||||
|
self:ok_callback()
|
||||||
|
else
|
||||||
|
self:cancel_callback()
|
||||||
|
end
|
||||||
|
UIManager:close(self)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,82 @@
|
|||||||
|
--[[
|
||||||
|
Wrapper Widget that manages focus for a whole dialog
|
||||||
|
|
||||||
|
supports a 2D model of active elements
|
||||||
|
|
||||||
|
e.g.:
|
||||||
|
layout = {
|
||||||
|
{ textinput, textinput },
|
||||||
|
{ okbutton, cancelbutton }
|
||||||
|
}
|
||||||
|
|
||||||
|
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>.
|
||||||
|
|
||||||
|
but notice that this does _not_ do the layout for you,
|
||||||
|
it rather defines an abstract layout.
|
||||||
|
]]
|
||||||
|
FocusManager = InputContainer:new{
|
||||||
|
selected = nil, -- defaults to x=1, y=1
|
||||||
|
layout = nil, -- mandatory
|
||||||
|
movement_allowed = { x = true, y = true }
|
||||||
|
}
|
||||||
|
|
||||||
|
function FocusManager:init()
|
||||||
|
self.selected = { x = 1, y = 1 }
|
||||||
|
self.key_events = {
|
||||||
|
-- these will all generate the same event, just with different arguments
|
||||||
|
FocusUp = { {"Up"}, doc = "move focus up", event = "FocusMove", args = {0, -1} },
|
||||||
|
FocusDown = { {"Down"}, doc = "move focus down", event = "FocusMove", args = {0, 1} },
|
||||||
|
FocusLeft = { {"Left"}, doc = "move focus left", event = "FocusMove", args = {-1, 0} },
|
||||||
|
FocusRight = { {"Right"}, doc = "move focus right", event = "FocusMove", args = {1, 0} },
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function FocusManager:onFocusMove(args)
|
||||||
|
local dx, dy = unpack(args)
|
||||||
|
|
||||||
|
if (dx ~= 0 and not self.movement_allowed.x)
|
||||||
|
or (dy ~= 0 and not self.movement_allowed.y) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
if not self.layout or not self.layout[self.selected.y] or not self.layout[self.selected.y][self.selected.x] then
|
||||||
|
return true
|
||||||
|
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
|
||||||
|
|
||||||
|
-- move cyclic in vertical direction
|
||||||
|
if self.selected.y + dy > #self.layout then
|
||||||
|
self.selected.y = 1
|
||||||
|
elseif self.selected.y + dy < 1 then
|
||||||
|
self.selected.y = #self.layout
|
||||||
|
else
|
||||||
|
self.selected.y = self.selected.y + dy
|
||||||
|
end
|
||||||
|
self.selected.x = self.selected.x + dx
|
||||||
|
|
||||||
|
if self.layout[self.selected.y][self.selected.x] ~= current_item
|
||||||
|
or not self.layout[self.selected.y][self.selected.x].is_inactive then
|
||||||
|
-- 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!)
|
||||||
|
UIManager:setDirty(self)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,54 @@
|
|||||||
|
require "ui/ui"
|
||||||
|
require "ui/widget"
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Widget that displays an informational message
|
||||||
|
|
||||||
|
it vanishes on key press or after a given timeout
|
||||||
|
]]
|
||||||
|
InfoMessage = InputContainer:new{
|
||||||
|
face = Font:getFace("infofont", 25),
|
||||||
|
text = "",
|
||||||
|
timeout = nil,
|
||||||
|
|
||||||
|
key_events = {
|
||||||
|
AnyKeyPressed = { { Input.group.Any }, seqtext = "any key", doc = "close dialog" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function InfoMessage:init()
|
||||||
|
-- we construct the actual content here because self.text is only available now
|
||||||
|
self[1] = CenterContainer:new{
|
||||||
|
dimen = Screen:getSize(),
|
||||||
|
FrameContainer:new{
|
||||||
|
margin = 2,
|
||||||
|
background = 0,
|
||||||
|
HorizontalGroup:new{
|
||||||
|
align = "center",
|
||||||
|
ImageWidget:new{
|
||||||
|
file = "resources/info-i.png"
|
||||||
|
},
|
||||||
|
HorizontalSpan:new{ width = 10 },
|
||||||
|
TextBoxWidget:new{
|
||||||
|
text = self.text,
|
||||||
|
face = Font:getFace("cfont", 30)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function InfoMessage: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 InfoMessage:onAnyKeyPressed()
|
||||||
|
-- triggered by our defined key events
|
||||||
|
UIManager:close(self)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
@ -1,264 +1,8 @@
|
|||||||
require "ui/widget"
|
require "ui/widget"
|
||||||
|
require "ui/focusmanager"
|
||||||
|
require "ui/infomessage"
|
||||||
require "ui/font"
|
require "ui/font"
|
||||||
|
|
||||||
--[[
|
|
||||||
Wrapper Widget that manages focus for a whole dialog
|
|
||||||
|
|
||||||
supports a 2D model of active elements
|
|
||||||
|
|
||||||
e.g.:
|
|
||||||
layout = {
|
|
||||||
{ textinput, textinput },
|
|
||||||
{ okbutton, cancelbutton }
|
|
||||||
}
|
|
||||||
|
|
||||||
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>.
|
|
||||||
|
|
||||||
but notice that this does _not_ do the layout for you,
|
|
||||||
it rather defines an abstract layout.
|
|
||||||
]]
|
|
||||||
FocusManager = InputContainer:new{
|
|
||||||
selected = nil, -- defaults to x=1, y=1
|
|
||||||
layout = nil, -- mandatory
|
|
||||||
movement_allowed = { x = true, y = true }
|
|
||||||
}
|
|
||||||
|
|
||||||
function FocusManager:init()
|
|
||||||
self.selected = { x = 1, y = 1 }
|
|
||||||
self.key_events = {
|
|
||||||
-- these will all generate the same event, just with different arguments
|
|
||||||
FocusUp = { {"Up"}, doc = "move focus up", event = "FocusMove", args = {0, -1} },
|
|
||||||
FocusDown = { {"Down"}, doc = "move focus down", event = "FocusMove", args = {0, 1} },
|
|
||||||
FocusLeft = { {"Left"}, doc = "move focus left", event = "FocusMove", args = {-1, 0} },
|
|
||||||
FocusRight = { {"Right"}, doc = "move focus right", event = "FocusMove", args = {1, 0} },
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function FocusManager:onFocusMove(args)
|
|
||||||
local dx, dy = unpack(args)
|
|
||||||
|
|
||||||
if (dx ~= 0 and not self.movement_allowed.x)
|
|
||||||
or (dy ~= 0 and not self.movement_allowed.y) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
if not self.layout or not self.layout[self.selected.y] or not self.layout[self.selected.y][self.selected.x] then
|
|
||||||
return true
|
|
||||||
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
|
|
||||||
|
|
||||||
-- move cyclic in vertical direction
|
|
||||||
if self.selected.y + dy > #self.layout then
|
|
||||||
self.selected.y = 1
|
|
||||||
elseif self.selected.y + dy < 1 then
|
|
||||||
self.selected.y = #self.layout
|
|
||||||
else
|
|
||||||
self.selected.y = self.selected.y + dy
|
|
||||||
end
|
|
||||||
self.selected.x = self.selected.x + dx
|
|
||||||
|
|
||||||
if self.layout[self.selected.y][self.selected.x] ~= current_item
|
|
||||||
or not self.layout[self.selected.y][self.selected.x].is_inactive then
|
|
||||||
-- 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!)
|
|
||||||
UIManager:setDirty(self)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--[[
|
|
||||||
a button widget
|
|
||||||
]]
|
|
||||||
Button = WidgetContainer:new{
|
|
||||||
text = nil, -- mandatory
|
|
||||||
preselect = false
|
|
||||||
}
|
|
||||||
|
|
||||||
function Button:init()
|
|
||||||
-- set FrameContainer content
|
|
||||||
self[1] = FrameContainer:new{
|
|
||||||
margin = 0,
|
|
||||||
bordersize = 3,
|
|
||||||
background = 0,
|
|
||||||
radius = 15,
|
|
||||||
padding = 2,
|
|
||||||
|
|
||||||
HorizontalGroup:new{
|
|
||||||
HorizontalSpan:new{ width = 8 },
|
|
||||||
TextWidget:new{
|
|
||||||
text = self.text,
|
|
||||||
face = Font:getFace("cfont", 20)
|
|
||||||
},
|
|
||||||
HorizontalSpan:new{ width = 8 },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if self.preselect then
|
|
||||||
self[1].color = 15
|
|
||||||
else
|
|
||||||
self[1].color = 5
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Button:onFocus()
|
|
||||||
self[1].color = 15
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function Button:onUnfocus()
|
|
||||||
self[1].color = 5
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--[[
|
|
||||||
Widget that shows a message and OK/Cancel buttons
|
|
||||||
]]
|
|
||||||
ConfirmBox = FocusManager:new{
|
|
||||||
text = "no text",
|
|
||||||
width = nil,
|
|
||||||
ok_text = "OK",
|
|
||||||
cancel_text = "Cancel",
|
|
||||||
ok_callback = function() end,
|
|
||||||
cancel_callback = function() end,
|
|
||||||
}
|
|
||||||
|
|
||||||
function ConfirmBox:init()
|
|
||||||
-- calculate box width on the fly if not given
|
|
||||||
if not self.width then
|
|
||||||
self.width = Screen:getWidth() - 200
|
|
||||||
end
|
|
||||||
-- build bottons
|
|
||||||
self.key_events.Close = { {{"Home","Back"}}, doc = "cancel" }
|
|
||||||
self.key_events.Select = { {{"Enter","Press"}}, doc = "chose selected option" }
|
|
||||||
|
|
||||||
local ok_button = Button:new{
|
|
||||||
text = self.ok_text,
|
|
||||||
}
|
|
||||||
local cancel_button = Button:new{
|
|
||||||
text = self.cancel_text,
|
|
||||||
preselect = true
|
|
||||||
}
|
|
||||||
|
|
||||||
self.layout = { { ok_button, cancel_button } }
|
|
||||||
self.selected.x = 2 -- Cancel is default
|
|
||||||
|
|
||||||
self[1] = CenterContainer:new{
|
|
||||||
dimen = Screen:getSize(),
|
|
||||||
FrameContainer:new{
|
|
||||||
margin = 2,
|
|
||||||
background = 0,
|
|
||||||
padding = 10,
|
|
||||||
HorizontalGroup:new{
|
|
||||||
ImageWidget:new{
|
|
||||||
file = "resources/info-i.png"
|
|
||||||
},
|
|
||||||
HorizontalSpan:new{ width = 10 },
|
|
||||||
VerticalGroup:new{
|
|
||||||
align = "left",
|
|
||||||
TextBoxWidget:new{
|
|
||||||
text = self.text,
|
|
||||||
face = Font:getFace("cfont", 30),
|
|
||||||
width = self.width,
|
|
||||||
},
|
|
||||||
VerticalSpan:new{ width = 10 },
|
|
||||||
HorizontalGroup:new{
|
|
||||||
ok_button,
|
|
||||||
HorizontalSpan:new{ width = 10 },
|
|
||||||
cancel_button,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function ConfirmBox:onClose()
|
|
||||||
UIManager:close(self)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function ConfirmBox:onSelect()
|
|
||||||
DEBUG("selected:", self.selected.x)
|
|
||||||
if self.selected.x == 1 then
|
|
||||||
self:ok_callback()
|
|
||||||
else
|
|
||||||
self:cancel_callback()
|
|
||||||
end
|
|
||||||
UIManager:close(self)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--[[
|
|
||||||
Widget that displays an informational message
|
|
||||||
|
|
||||||
it vanishes on key press or after a given timeout
|
|
||||||
]]
|
|
||||||
InfoMessage = InputContainer:new{
|
|
||||||
face = Font:getFace("infofont", 25),
|
|
||||||
text = "",
|
|
||||||
timeout = nil,
|
|
||||||
|
|
||||||
key_events = {
|
|
||||||
AnyKeyPressed = { { Input.group.Any }, seqtext = "any key", doc = "close dialog" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function InfoMessage:init()
|
|
||||||
-- we construct the actual content here because self.text is only available now
|
|
||||||
self[1] = CenterContainer:new{
|
|
||||||
dimen = Screen:getSize(),
|
|
||||||
FrameContainer:new{
|
|
||||||
margin = 2,
|
|
||||||
background = 0,
|
|
||||||
HorizontalGroup:new{
|
|
||||||
align = "center",
|
|
||||||
ImageWidget:new{
|
|
||||||
file = "resources/info-i.png"
|
|
||||||
},
|
|
||||||
HorizontalSpan:new{ width = 10 },
|
|
||||||
TextBoxWidget:new{
|
|
||||||
text = self.text,
|
|
||||||
face = Font:getFace("cfont", 30)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function InfoMessage: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 InfoMessage:onAnyKeyPressed()
|
|
||||||
-- triggered by our defined key events
|
|
||||||
UIManager:close(self)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
Widget that displays a shortcut icon for menu item
|
Widget that displays a shortcut icon for menu item
|
||||||
]]
|
]]
|
Loading…
Reference in New Issue