2
0
mirror of https://github.com/koreader/koreader synced 2024-11-20 03:25:34 +00:00
koreader/frontend/ui/widget/radiobutton.lua
NiLuJe 3060dc81af
Revamp "flash_ui" handling (#7118)
* Wherever possible, do an actual dumb invert on the Screen BB instead of repainting the widget, *then* inverting it (which is what the "invert" flag does).
* Instead of playing with nextTick/tickAfterNext delays, explicitly fence stuff with forceRePaint
* And, in the few cases where said Mk. 7 quirk kicks in, make the fences more marked by using a well-placed WAIT_FOR_UPDATE_COMPLETE

* Fix an issue in Button where show/hide & enable/disable where actually all toggles, which meant that duplicate calls or timing issues would do the wrong thing. (This broke dimming some icons, and mistakenly dropped the background from FM chevrons, for example).
* Speaking of, fix Button's hide/show to actually restore the background properly (there was a stupid typo in the variable name)
* Still in Button, fix the insanity of the double repaint on rounded buttons. Turns out it made sense, after all (and was related to said missing background, and bad interaction with invert & text with no background).
* KeyValuePage suffered from a similar issue with broken highlights (all black) because of missing backgrounds.
* In ConfigDialog, only instanciate IconButtons once (because every tab switch causes a full instantiation; and the initial display implies a full instanciation and an initial tab switch). Otherwise, both instances linger, and catch taps, and as such, double highlights.
* ConfigDialog: Restore the "don't repaint ReaderUI" when switching between similarly sized tabs (re #6131). I never could reproduce that on eInk, and I can't now on the emulator, so I'm assuming @poire-z fixed it during the swap to SVG icons.
* KeyValuePage: Only instanciate Buttons once (again, this is a widget that goes through a full init every page). Again, caused highlight/dimming issues because buttons were stacked.
* Menu: Ditto.
* TouchMenu: Now home of the gnarliest unhilight heuristics, because of the sheer amount of different things that can happen (and/or thanks to stuff not flagged covers_fullscreen properly ;p).

* Bump base
https://github.com/koreader/koreader-base/pull/1280
https://github.com/koreader/koreader-base/pull/1282
https://github.com/koreader/koreader-base/pull/1283
https://github.com/koreader/koreader-base/pull/1284

* Bump android-luajit-launcher
https://github.com/koreader/android-luajit-launcher/pull/284
https://github.com/koreader/android-luajit-launcher/pull/285
https://github.com/koreader/android-luajit-launcher/pull/286
https://github.com/koreader/android-luajit-launcher/pull/287
2021-01-10 01:51:09 +01:00

176 lines
5.2 KiB
Lua

--[[--
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,
max_width = self.max_width,
}
self._unchecked_widget = TextWidget:new{
text = "" .. self.text,
face = self.face,
max_width = self.max_width,
}
self._empty_widget = TextWidget:new{
text = "" .. self.text,
face = self.face,
max_width = self.max_width,
}
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()
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
-- While I'd like to only flash the button itself, we have to make do with flashing the full width of the TextWidget...
self.frame.invert = true
UIManager:widgetRepaint(self.frame, self.dimen.x, self.dimen.y)
UIManager:setDirty(nil, function()
return "fast", self.dimen
end)
-- Force the repaint *now*, so we don't have to delay the callback to see the invert...
UIManager:forceRePaint()
self.callback()
--UIManager:forceRePaint() -- Unnecessary, the check/uncheck process involves too many repaints already
--UIManager:waitForVSync()
self.frame.invert = false
UIManager:widgetRepaint(self.frame, self.dimen.x, self.dimen.y)
UIManager:setDirty(nil, function()
return "fast", self.dimen
end)
--UIManager:forceRePaint()
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:widgetRepaint(self.frame, self.dimen.x, self.dimen.y)
UIManager:setDirty(nil, function()
return "fast", self.dimen
end)
end
function RadioButton:unCheck()
self._radio_button = self._unchecked_widget
self.checked = false
self:update()
UIManager:widgetRepaint(self.frame, self.dimen.x, self.dimen.y)
UIManager:setDirty(nil, function()
return "fast", self.dimen
end)
end
return RadioButton