mirror of https://github.com/koreader/koreader
[feat, UX] Add new OpenWithDialog based on RadioButton and RadioButtonTable (#3678)
Fixes #3659pull/3679/head
parent
f15732bbe5
commit
dc0dc7e962
@ -0,0 +1,157 @@
|
|||||||
|
--[[--
|
||||||
|
This widget displays an open with dialog.
|
||||||
|
]]
|
||||||
|
|
||||||
|
local Blitbuffer = require("ffi/blitbuffer")
|
||||||
|
local CenterContainer = require("ui/widget/container/centercontainer")
|
||||||
|
local CheckButton = require("ui/widget/checkbutton")
|
||||||
|
local FrameContainer = require("ui/widget/container/framecontainer")
|
||||||
|
local Geom = require("ui/geometry")
|
||||||
|
local InputDialog = require("ui/widget/inputdialog")
|
||||||
|
local LeftContainer = require("ui/widget/container/leftcontainer")
|
||||||
|
local LineWidget = require("ui/widget/linewidget")
|
||||||
|
local RadioButtonTable = require("ui/widget/radiobuttontable")
|
||||||
|
local Size = require("ui/size")
|
||||||
|
local VerticalGroup = require("ui/widget/verticalgroup")
|
||||||
|
local VerticalSpan = require("ui/widget/verticalspan")
|
||||||
|
local _ = require("gettext")
|
||||||
|
local Screen = require("device").screen
|
||||||
|
|
||||||
|
local OpenWithDialog = InputDialog:extend{}
|
||||||
|
|
||||||
|
function OpenWithDialog:init()
|
||||||
|
-- init title and buttons in base class
|
||||||
|
InputDialog.init(self)
|
||||||
|
|
||||||
|
self.radio_button_table = RadioButtonTable:new{
|
||||||
|
radio_buttons = self.radio_buttons,
|
||||||
|
width = self.width * 0.9,
|
||||||
|
focused = true,
|
||||||
|
scroll = false,
|
||||||
|
parent = self,
|
||||||
|
}
|
||||||
|
|
||||||
|
self._check_file_button = self._check_file_button or CheckButton:new{
|
||||||
|
text = _("Always use this engine for this file"),
|
||||||
|
callback = function()
|
||||||
|
if self._check_file_button.checked then
|
||||||
|
self._check_file_button:unCheck()
|
||||||
|
else
|
||||||
|
self._check_file_button:check()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
width = self.width * 0.9,
|
||||||
|
height = self.height,
|
||||||
|
|
||||||
|
parent = self,
|
||||||
|
}
|
||||||
|
self._always_file_toggle = LeftContainer:new{
|
||||||
|
bordersize = 0,
|
||||||
|
dimen = Geom:new{
|
||||||
|
w = self.width * 0.9,
|
||||||
|
h = self._check_file_button:getSize().h,
|
||||||
|
},
|
||||||
|
self._check_file_button,
|
||||||
|
}
|
||||||
|
|
||||||
|
self._check_global_button = self._check_global_button or CheckButton:new{
|
||||||
|
text = _("Always use this engine for file type"),
|
||||||
|
callback = function()
|
||||||
|
if self._check_global_button.checked then
|
||||||
|
self._check_global_button:unCheck()
|
||||||
|
else
|
||||||
|
self._check_global_button:check()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
width = self.width * 0.9,
|
||||||
|
height = self.height,
|
||||||
|
|
||||||
|
parent = self,
|
||||||
|
}
|
||||||
|
self._always_global_toggle = LeftContainer:new{
|
||||||
|
bordersize = 0,
|
||||||
|
dimen = Geom:new{
|
||||||
|
w = self.width * 0.9,
|
||||||
|
h = self._check_global_button:getSize().h,
|
||||||
|
},
|
||||||
|
self._check_global_button,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dialog_frame = FrameContainer:new{
|
||||||
|
radius = Size.radius.window,
|
||||||
|
padding = 0,
|
||||||
|
margin = 0,
|
||||||
|
background = Blitbuffer.COLOR_WHITE,
|
||||||
|
VerticalGroup:new{
|
||||||
|
align = "left",
|
||||||
|
self.title,
|
||||||
|
self.title_bar,
|
||||||
|
VerticalSpan:new{
|
||||||
|
width = Size.span.vertical_large*2,
|
||||||
|
},
|
||||||
|
CenterContainer:new{
|
||||||
|
dimen = Geom:new{
|
||||||
|
w = self.title_bar:getSize().w,
|
||||||
|
h = self.radio_button_table:getSize().h,
|
||||||
|
},
|
||||||
|
self.radio_button_table,
|
||||||
|
},
|
||||||
|
CenterContainer:new{
|
||||||
|
dimen = Geom:new{
|
||||||
|
w = self.title_bar:getSize().w,
|
||||||
|
h = Size.span.vertical_large*2,
|
||||||
|
},
|
||||||
|
LineWidget:new{
|
||||||
|
background = Blitbuffer.COLOR_GREY,
|
||||||
|
dimen = Geom:new{
|
||||||
|
w = self.width * 0.9,
|
||||||
|
h = Size.line.medium,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CenterContainer:new{
|
||||||
|
dimen = Geom:new{
|
||||||
|
w = self.title_bar:getSize().w,
|
||||||
|
h = self._always_file_toggle:getSize().h,
|
||||||
|
},
|
||||||
|
self._always_file_toggle,
|
||||||
|
},
|
||||||
|
CenterContainer:new{
|
||||||
|
dimen = Geom:new{
|
||||||
|
w = self.title_bar:getSize().w,
|
||||||
|
h = self._always_global_toggle:getSize().h,
|
||||||
|
},
|
||||||
|
self._always_global_toggle,
|
||||||
|
},
|
||||||
|
VerticalSpan:new{
|
||||||
|
width = Size.span.vertical_large*2,
|
||||||
|
},
|
||||||
|
-- buttons
|
||||||
|
CenterContainer:new{
|
||||||
|
dimen = Geom:new{
|
||||||
|
w = self.title_bar:getSize().w,
|
||||||
|
h = self.button_table:getSize().h,
|
||||||
|
},
|
||||||
|
self.button_table,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self._input_widget = self.radio_button_table
|
||||||
|
|
||||||
|
self[1] = CenterContainer:new{
|
||||||
|
dimen = Geom:new{
|
||||||
|
w = Screen:getWidth(),
|
||||||
|
h = Screen:getHeight(),
|
||||||
|
},
|
||||||
|
self.dialog_frame,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function OpenWithDialog:onCloseWidget()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return OpenWithDialog
|
@ -0,0 +1,167 @@
|
|||||||
|
--[[--
|
||||||
|
Widget that shows a radiobutton checked (`◉`) or unchecked (`◯`)
|
||||||
|
or nothing of the same size.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
local RadioButton = require("ui/widget/radiobutton")
|
||||||
|
local parent_widget = FrameContainer:new{}
|
||||||
|
table.insert(parent_widget, RadioButton:new{
|
||||||
|
checkable = false, -- shows nothing when false, defaults to true
|
||||||
|
checked = function() end, -- whether the box is checked
|
||||||
|
})
|
||||||
|
UIManager:show(parent_widget)
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
local Blitbuffer = require("ffi/blitbuffer")
|
||||||
|
local Device = require("device")
|
||||||
|
local Font = require("ui/font")
|
||||||
|
local FrameContainer = require("ui/widget/container/framecontainer")
|
||||||
|
local Geom = require("ui/geometry")
|
||||||
|
local GestureRange = require("ui/gesturerange")
|
||||||
|
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||||
|
local LeftContainer = require("ui/widget/container/leftcontainer")
|
||||||
|
local TextWidget = require("ui/widget/textwidget")
|
||||||
|
local UIManager = require("ui/uimanager")
|
||||||
|
|
||||||
|
local RadioButton = InputContainer:new{
|
||||||
|
checkable = true,
|
||||||
|
checked = false,
|
||||||
|
enabled = true,
|
||||||
|
face = Font:getFace("smallinfofont"),
|
||||||
|
background = Blitbuffer.COLOR_WHITE,
|
||||||
|
width = 0,
|
||||||
|
height = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
function RadioButton:init()
|
||||||
|
self._checked_widget = TextWidget:new{
|
||||||
|
text = "◉ " .. self.text,
|
||||||
|
face = self.face,
|
||||||
|
}
|
||||||
|
self._unchecked_widget = TextWidget:new{
|
||||||
|
text = "◯ " .. self.text,
|
||||||
|
face = self.face,
|
||||||
|
}
|
||||||
|
self._empty_widget = TextWidget:new{
|
||||||
|
text = "" .. self.text,
|
||||||
|
face = self.face,
|
||||||
|
}
|
||||||
|
self._widget_size = self._unchecked_widget:getSize()
|
||||||
|
if self.width == nil then
|
||||||
|
self.width = self._widget_size.w
|
||||||
|
end
|
||||||
|
self._radio_button = self.checkable
|
||||||
|
and (self.checked and self._checked_widget or self._unchecked_widget)
|
||||||
|
or self._empty_widget
|
||||||
|
self:update()
|
||||||
|
self.dimen = self.frame:getSize()
|
||||||
|
if Device:isTouchDevice() then
|
||||||
|
self.ges_events = {
|
||||||
|
TapCheckButton = {
|
||||||
|
GestureRange:new{
|
||||||
|
ges = "tap",
|
||||||
|
range = self.dimen,
|
||||||
|
},
|
||||||
|
doc = "Tap Button",
|
||||||
|
},
|
||||||
|
HoldCheckButton = {
|
||||||
|
GestureRange:new{
|
||||||
|
ges = "hold",
|
||||||
|
range = self.dimen,
|
||||||
|
},
|
||||||
|
doc = "Hold Button",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function RadioButton:update()
|
||||||
|
if self[1] then
|
||||||
|
self[1]:free()
|
||||||
|
end
|
||||||
|
self.frame = FrameContainer:new{
|
||||||
|
margin = self.margin,
|
||||||
|
bordersize = self.bordersize,
|
||||||
|
background = self.background,
|
||||||
|
radius = self.radius,
|
||||||
|
padding = self.padding,
|
||||||
|
LeftContainer:new{
|
||||||
|
dimen = Geom:new{
|
||||||
|
w = self.width,
|
||||||
|
h = self._widget_size.h
|
||||||
|
},
|
||||||
|
self._radio_button,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self[1] = self.frame
|
||||||
|
end
|
||||||
|
|
||||||
|
function RadioButton:onFocus()
|
||||||
|
self.frame.invert = true
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function RadioButton:onUnfocus()
|
||||||
|
self.frame.invert = false
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function RadioButton:onTapCheckButton()
|
||||||
|
if self.enabled and self.callback then
|
||||||
|
if G_reader_settings:isFalse("flash_ui") then
|
||||||
|
self.callback()
|
||||||
|
else
|
||||||
|
UIManager:scheduleIn(0.0, function()
|
||||||
|
self.invert = true
|
||||||
|
UIManager:setDirty(self.show_parent, function()
|
||||||
|
return "ui", self.dimen
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
UIManager:scheduleIn(0.1, function()
|
||||||
|
self.callback()
|
||||||
|
self.invert = false
|
||||||
|
UIManager:setDirty(self.show_parent, function()
|
||||||
|
return "ui", self.dimen
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
elseif self.tap_input then
|
||||||
|
self:onInput(self.tap_input)
|
||||||
|
elseif type(self.tap_input_func) == "function" then
|
||||||
|
self:onInput(self.tap_input_func())
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function RadioButton:onHoldCheckButton()
|
||||||
|
if self.enabled and self.hold_callback then
|
||||||
|
self.hold_callback()
|
||||||
|
elseif self.hold_input then
|
||||||
|
self:onInput(self.hold_input)
|
||||||
|
elseif type(self.hold_input_func) == "function" then
|
||||||
|
self:onInput(self.hold_input_func())
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function RadioButton:check(callback)
|
||||||
|
self._radio_button = self._checked_widget
|
||||||
|
self.checked = true
|
||||||
|
self:update()
|
||||||
|
UIManager:setDirty(self.parent, function()
|
||||||
|
return "ui", self.dimen
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function RadioButton:unCheck()
|
||||||
|
self._radio_button = self._unchecked_widget
|
||||||
|
self.checked = false
|
||||||
|
self:update()
|
||||||
|
UIManager:setDirty(self.parent, function()
|
||||||
|
return "ui", self.dimen
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return RadioButton
|
@ -0,0 +1,160 @@
|
|||||||
|
local Blitbuffer = require("ffi/blitbuffer")
|
||||||
|
local Device = require("device")
|
||||||
|
local FocusManager = require("ui/widget/focusmanager")
|
||||||
|
local Geom = require("ui/geometry")
|
||||||
|
local HorizontalGroup = require("ui/widget/horizontalgroup")
|
||||||
|
local LineWidget = require("ui/widget/linewidget")
|
||||||
|
local RadioButton = require("ui/widget/radiobutton")
|
||||||
|
local Size = require("ui/size")
|
||||||
|
local VerticalGroup = require("ui/widget/verticalgroup")
|
||||||
|
local VerticalSpan = require("ui/widget/verticalspan")
|
||||||
|
local dbg = require("dbg")
|
||||||
|
local Screen = Device.screen
|
||||||
|
|
||||||
|
local RadioButtonTable = FocusManager:new{
|
||||||
|
width = Screen:getWidth(),
|
||||||
|
radio_buttons = {
|
||||||
|
{
|
||||||
|
{text="Cancel", enabled=false, callback=nil},
|
||||||
|
{text="OK", enabled=true, callback=nil},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sep_width = Size.line.medium,
|
||||||
|
padding = Size.padding.button,
|
||||||
|
|
||||||
|
zero_sep = false,
|
||||||
|
button_font_face = "cfont",
|
||||||
|
button_font_size = 20,
|
||||||
|
|
||||||
|
_first_button = nil,
|
||||||
|
checked_button = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
function RadioButtonTable:init()
|
||||||
|
self.selected = { x = 1, y = 1 }
|
||||||
|
self.radio_buttons_layout = {}
|
||||||
|
self.container = VerticalGroup:new{ width = self.width }
|
||||||
|
table.insert(self, self.container)
|
||||||
|
|
||||||
|
if self.zero_sep then
|
||||||
|
-- If we're asked to add a first line, don't add a vspan before: caller
|
||||||
|
-- must do its own padding before.
|
||||||
|
-- Things look better when the first line is gray like the others.
|
||||||
|
self:addHorizontalSep(false, true, true)
|
||||||
|
else
|
||||||
|
self:addHorizontalSep(false, false, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
local row_cnt = #self.radio_buttons
|
||||||
|
|
||||||
|
for i = 1, row_cnt do
|
||||||
|
self.radio_buttons_layout[i] = {}
|
||||||
|
local horizontal_group = HorizontalGroup:new{}
|
||||||
|
local row = self.radio_buttons[i]
|
||||||
|
local column_cnt = #row
|
||||||
|
local sizer_space = self.sep_width * (column_cnt - 1) + 2
|
||||||
|
for j = 1, column_cnt do
|
||||||
|
local btn_entry = row[j]
|
||||||
|
local button = RadioButton:new{
|
||||||
|
text = btn_entry.text,
|
||||||
|
enabled = btn_entry.enabled,
|
||||||
|
checked = btn_entry.checked,
|
||||||
|
provider = btn_entry.provider,
|
||||||
|
|
||||||
|
width = (self.width - sizer_space)/column_cnt,
|
||||||
|
max_width = (self.width - sizer_space)/column_cnt - 2*self.sep_width - 2*self.padding,
|
||||||
|
bordersize = 0,
|
||||||
|
margin = 0,
|
||||||
|
padding = 0,
|
||||||
|
text_font_face = self.button_font_face,
|
||||||
|
text_font_size = self.button_font_size,
|
||||||
|
|
||||||
|
show_parent = self.show_parent or self,
|
||||||
|
parent = self.parent or self,
|
||||||
|
}
|
||||||
|
local button_callback = function()
|
||||||
|
self:_checkButton(button)
|
||||||
|
end
|
||||||
|
button.callback = button_callback
|
||||||
|
|
||||||
|
if i == 1 and j == 1 then
|
||||||
|
self._first_button = button
|
||||||
|
end
|
||||||
|
|
||||||
|
if button.checked and not self.checked_button then
|
||||||
|
self.checked_button = button
|
||||||
|
elseif dbg.is_on and
|
||||||
|
button.checked and self.checked_button then
|
||||||
|
error("RadioButtonGroup: multiple checked RadioButtons")
|
||||||
|
end
|
||||||
|
|
||||||
|
local button_dim = button:getSize()
|
||||||
|
local vertical_sep = LineWidget:new{
|
||||||
|
background = Blitbuffer.COLOR_GREY,
|
||||||
|
dimen = Geom:new{
|
||||||
|
w = self.sep_width,
|
||||||
|
h = button_dim.h,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.radio_buttons_layout[i][j] = button
|
||||||
|
table.insert(horizontal_group, button)
|
||||||
|
if j < column_cnt then
|
||||||
|
table.insert(horizontal_group, vertical_sep)
|
||||||
|
end
|
||||||
|
end -- end for each button
|
||||||
|
table.insert(self.container, horizontal_group)
|
||||||
|
--if i < row_cnt then
|
||||||
|
--self:addHorizontalSep(true, true, true)
|
||||||
|
--end
|
||||||
|
end -- end for each button line
|
||||||
|
self:addHorizontalSep(true, false, false)
|
||||||
|
|
||||||
|
-- check first entry unless otherwise specified
|
||||||
|
if not self.checked_button then
|
||||||
|
self._first_button:check()
|
||||||
|
self.checked_button = self._first_button
|
||||||
|
end
|
||||||
|
|
||||||
|
if Device:hasDPad() or Device:hasKeyboard() then
|
||||||
|
self.layout = self.radio_buttons_layout
|
||||||
|
self.layout[1][1]:onFocus()
|
||||||
|
self.key_events.SelectByKeyPress = { {{"Press", "Enter"}} }
|
||||||
|
else
|
||||||
|
self.key_events = {} -- deregister all key press event listeners
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function RadioButtonTable:addHorizontalSep(vspan_before, add_line, vspan_after, black_line)
|
||||||
|
if vspan_before then
|
||||||
|
table.insert(self.container,
|
||||||
|
VerticalSpan:new{ width = Size.span.vertical_default })
|
||||||
|
end
|
||||||
|
if add_line then
|
||||||
|
table.insert(self.container, LineWidget:new{
|
||||||
|
background = black_line and Blitbuffer.COLOR_BLACK or Blitbuffer.COLOR_GREY,
|
||||||
|
dimen = Geom:new{
|
||||||
|
w = self.width,
|
||||||
|
h = self.sep_width,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
end
|
||||||
|
if vspan_after then
|
||||||
|
table.insert(self.container,
|
||||||
|
VerticalSpan:new{ width = Size.span.vertical_default })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function RadioButtonTable:onSelectByKeyPress()
|
||||||
|
self:getFocusItem().callback()
|
||||||
|
end
|
||||||
|
|
||||||
|
function RadioButtonTable:_checkButton(button)
|
||||||
|
-- nothing to do
|
||||||
|
if button.checked then return end
|
||||||
|
|
||||||
|
self.checked_button:unCheck()
|
||||||
|
button:check()
|
||||||
|
self.checked_button = button
|
||||||
|
end
|
||||||
|
|
||||||
|
return RadioButtonTable
|
Loading…
Reference in New Issue