You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koreader/frontend/ui/widget/naturallightwidget.lua

411 lines
14 KiB
Lua

local Blitbuffer = require("ffi/blitbuffer")
local Button = require("ui/widget/button")
local CenterContainer = require("ui/widget/container/centercontainer")
local Device = require("device")
local Font = require("ui/font")
local FrameContainer = require("ui/widget/container/framecontainer")
local Geom = require("ui/geometry")
local HorizontalGroup = require("ui/widget/horizontalgroup")
local HorizontalSpan = require("ui/widget/horizontalspan")
local InputText = require("ui/widget/inputtext")
local Size = require("ui/size")
local TextBoxWidget = require("ui/widget/textboxwidget")
local TitleBar = require("ui/widget/titlebar")
local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local _ = require("gettext")
local Screen = Device.screen
Clarify our OOP semantics across the codebase (#9586) Basically: * Use `extend` for class definitions * Use `new` for object instantiations That includes some minor code cleanups along the way: * Updated `Widget`'s docs to make the semantics clearer. * Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283) * Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass). * Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events. * Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier. * Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references. * ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak). * Terminal: Make sure the shell is killed on plugin teardown. * InputText: Fix Home/End/Del physical keys to behave sensibly. * InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...). * OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of. * ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed! * Kobo: Minor code cleanups.
2 years ago
local NaturalLightWidget = WidgetContainer:extend{
is_always_active = true,
width = nil,
height = nil,
textbox_width = 0.1,
button_width = 0.07,
text_width = 0.3,
white_gain = nil,
white_offset = nil,
red_gain = nil,
red_offset = nil,
green_gain = nil,
green_offset = nil,
exponent = nil,
fl_widget = nil,
old_values = nil
}
function NaturalLightWidget:init()
self.medium_font_face = Font:getFace("ffont")
self.nl_bar = {}
self.screen_width = Screen:getWidth()
self.screen_height = Screen:getHeight()
self.span = math.ceil(self.screen_height * 0.01)
self.width = math.floor(self.screen_width * 0.95)
self.button_width = 0.08 * self.width
self.textbox_width = 0.1 * self.width
self.text_width = 0.2 * self.width
self.powerd = Device:getPowerDevice()
self:update()
end
function NaturalLightWidget:applyValues()
self.powerd.fl.white_gain = self.white_gain[2]:getText()
self.powerd.fl.white_offset = self.white_offset[2]:getText()
self.powerd.fl.red_gain = self.red_gain[2]:getText()
self.powerd.fl.red_offset = self.red_offset[2]:getText()
self.powerd.fl.green_gain = self.green_gain[2]:getText()
self.powerd.fl.green_offset = self.green_offset[2]:getText()
self.powerd.fl.exponent = self.exponent[2]:getText()
self.powerd.fl:setNaturalBrightness()
end
-- Create an InputText with '-' and '+' button next to it. Tapping
-- those buttons will de/increase by 'step', and 'step/10' on hold.
function NaturalLightWidget:adaptableNumber(initial, step)
local minus_number_plus = HorizontalGroup:new{ align = "center" }
local input_text = InputText:new{
parent = self,
text = initial,
input_type = "number",
hint = "",
width = self.textbox_width,
enter_callback = function()
self:closeKeyboard()
self:applyValues()
UIManager:setDirty(self._current_input, "fast")
end
}
input_text:unfocus()
local button_minus = Button:new{
text = "",
margin = Size.margin.small,
radius = 0,
width = self.button_width,
show_parent = self,
callback = function()
self:closeKeyboard()
self:setValueTextBox(input_text, input_text:getText() - step)
self:applyValues()
end,
hold_callback = function()
self:closeKeyboard()
self:setValueTextBox(input_text, input_text:getText() - step/10.0)
self:applyValues()
end,
}
local button_plus = Button:new{
text = "",
margin = Size.margin.small,
radius = 0,
width = self.button_width,
show_parent = self,
callback = function()
self:closeKeyboard()
self:setValueTextBox(input_text, input_text:getText() + step)
self:applyValues()
end,
hold_callback = function()
self:closeKeyboard()
self:setValueTextBox(input_text, input_text:getText() + step/10)
self:applyValues()
end,
}
table.insert(minus_number_plus, button_minus)
table.insert(minus_number_plus, input_text)
table.insert(minus_number_plus, button_plus)
-- Sanitize the returned value so as not to upset sysfs_light...
function input_text:getText()
-- Also, while we're here, make sure we actually return a number, because InputText doesn't for... reasons.
return tonumber(self.text) or initial
end
return minus_number_plus
end
-- Get current values that are used in sysfs_light
function NaturalLightWidget:getCurrentValues()
return {white_gain =
self.powerd.fl.white_gain,
white_offset =
self.powerd.fl.white_offset,
red_gain =
self.powerd.fl.red_gain,
red_offset =
self.powerd.fl.red_offset,
green_gain =
self.powerd.fl.green_gain,
green_offset =
self.powerd.fl.green_offset,
exponent =
self.powerd.fl.exponent}
end
function NaturalLightWidget:update()
local title_bar = TitleBar:new{
title = _("Natural light configuration"),
width = self.width,
align = "left",
with_bottom_line = true,
bottom_v_padding = 0,
close_callback = function()
self:setAllValues(self.old_values)
self:onClose()
end,
show_parent = self,
}
local main_content = FrameContainer:new{
padding = Size.padding.button,
margin = Size.margin.small,
bordersize = 0,
self:createMainContent(self.width, math.floor(self.screen_height * 0.2))
}
self.nl_frame = FrameContainer:new{
radius = Size.radius.window,
bordersize = Size.border.window,
padding = 0,
margin = 0,
background = Blitbuffer.COLOR_WHITE,
VerticalGroup:new{
align = "left",
title_bar,
CenterContainer:new{
dimen = Geom:new{
w = self.width,
h = main_content:getSize().h,
},
main_content,
},
}
}
self[1] = WidgetContainer:new{
align = "top",
Clarify our OOP semantics across the codebase (#9586) Basically: * Use `extend` for class definitions * Use `new` for object instantiations That includes some minor code cleanups along the way: * Updated `Widget`'s docs to make the semantics clearer. * Removed `should_restrict_JIT` (it's been dead code since https://github.com/koreader/android-luajit-launcher/pull/283) * Minor refactoring of LuaSettings/LuaData/LuaDefaults/DocSettings to behave (mostly, they are instantiated via `open` instead of `new`) like everything else and handle inheritance properly (i.e., DocSettings is now a proper LuaSettings subclass). * Default to `WidgetContainer` instead of `InputContainer` for stuff that doesn't actually setup key/gesture events. * Ditto for explicit `*Listener` only classes, make sure they're based on `EventListener` instead of something uselessly fancier. * Unless absolutely necessary, do not store references in class objects, ever; only values. Instead, always store references in instances, to avoid both sneaky inheritance issues, and sneaky GC pinning of stale references. * ReaderUI: Fix one such issue with its `active_widgets` array, with critical implications, as it essentially pinned *all* of ReaderUI's modules, including their reference to the `Document` instance (i.e., that was a big-ass leak). * Terminal: Make sure the shell is killed on plugin teardown. * InputText: Fix Home/End/Del physical keys to behave sensibly. * InputContainer/WidgetContainer: If necessary, compute self.dimen at paintTo time (previously, only InputContainers did, which might have had something to do with random widgets unconcerned about input using it as a baseclass instead of WidgetContainer...). * OverlapGroup: Compute self.dimen at *init* time, because for some reason it needs to do that, but do it directly in OverlapGroup instead of going through a weird WidgetContainer method that it was the sole user of. * ReaderCropping: Under no circumstances should a Document instance member (here, self.bbox) risk being `nil`ed! * Kobo: Minor code cleanups.
2 years ago
dimen = Geom:new{
x = 0, y = 0,
w = self.screen_width,
h = self.screen_height,
},
FrameContainer:new{
bordersize = 0,
self.nl_frame,
},
}
end
function NaturalLightWidget:createMainContent(width, height)
self.fl_container = CenterContainer:new{
dimen = Geom:new{ w = width, h = height },
}
self.white_gain = self:adaptableNumber(self.powerd.fl.white_gain, 1)
self.white_offset = self:adaptableNumber(self.powerd.fl.white_offset, 1)
self.red_gain = self:adaptableNumber(self.powerd.fl.red_gain, 1)
self.red_offset = self:adaptableNumber(self.powerd.fl.red_offset, 1)
self.green_gain = self:adaptableNumber(self.powerd.fl.green_gain, 1)
self.green_offset = self:adaptableNumber(self.powerd.fl.green_offset, 1)
self.exponent = self:adaptableNumber(self.powerd.fl.exponent, 0.1)
local separator = HorizontalSpan:new{ width = Size.span.horizontal_default }
local vspan = VerticalSpan:new{ width = Size.span.vertical_large * 2}
local vertical_group = VerticalGroup:new{ align = "center" }
local title_group = HorizontalGroup:new{ align = "center" }
local white_group = HorizontalGroup:new{ align = "center" }
local red_group = HorizontalGroup:new{ align = "center" }
local green_group = HorizontalGroup:new{ align = "center" }
local exponent_group = HorizontalGroup:new{ align = "center" }
local button_group = HorizontalGroup:new{ align = "center" }
local text_gain = TextBoxWidget:new{
text = _("Amplification"),
face = self.medium_font_face,
bold = true,
width = self.textbox_width + 2 * self.button_width
}
local text_offset = TextBoxWidget:new{
text = _("Offset"),
face = self.medium_font_face,
bold = true,
width = self.textbox_width + self.button_width
}
local text_white = TextBoxWidget:new{
text = _("White"),
face = self.medium_font_face,
bold = true,
width = self.text_width
}
local text_red = TextBoxWidget:new{
text = _("Red"),
face = self.medium_font_face,
bold = true,
width = self.text_width
}
local text_green = TextBoxWidget:new{
text = _("Green"),
face = self.medium_font_face,
bold = true,
width = self.text_width
}
local text_exponent = TextBoxWidget:new{
text = _("Exponent"),
face = self.medium_font_face,
bold = true,
width = self.text_width
}
local button_defaults = Button:new{
text = "Restore Defaults",
margin = Size.margin.small,
radius = 0,
width = math.floor(self.width * 0.35),
show_parent = self,
callback = function()
self:setAllValues({white_gain = 25,
white_offset = -25,
red_gain = 24,
red_offset = 0,
green_gain = 24,
green_offset = -65,
exponent = 0.25})
end,
}
local button_cancel = Button:new{
text = "Cancel",
margin = Size.margin.small,
radius = 0,
width = math.floor(self.width * 0.2),
show_parent = self,
callback = function()
self:setAllValues(self.old_values)
self:onClose()
end,
}
local button_ok = Button:new{
text = "Save",
margin = Size.margin.small,
radius = 0,
width = math.floor(self.width * 0.2),
show_parent = self,
callback = function()
G_reader_settings:saveSetting("natural_light_config",
self:getCurrentValues())
self:onClose()
end,
}
table.insert(title_group, HorizontalSpan:new{
width = self.text_width + self.button_width
})
table.insert(title_group, text_gain)
table.insert(title_group, separator)
table.insert(title_group, HorizontalSpan:new{
width = self.button_width
})
table.insert(title_group, text_offset)
table.insert(white_group, text_white)
table.insert(white_group, self.white_gain)
table.insert(white_group, separator)
table.insert(white_group, self.white_offset)
table.insert(red_group, text_red)
table.insert(red_group, self.red_gain)
table.insert(red_group, separator)
table.insert(red_group, self.red_offset)
table.insert(green_group, text_green)
table.insert(green_group, self.green_gain)
table.insert(green_group, separator)
table.insert(green_group, self.green_offset)
table.insert(exponent_group, text_exponent)
table.insert(exponent_group, self.exponent)
table.insert(button_group, button_defaults)
table.insert(button_group, HorizontalSpan:new{
width = 0.05*self.width
})
table.insert(button_group, button_cancel)
table.insert(button_group, button_ok)
table.insert(vertical_group, title_group)
table.insert(vertical_group, white_group)
table.insert(vertical_group, red_group)
table.insert(vertical_group, green_group)
table.insert(vertical_group, vspan)
table.insert(vertical_group, exponent_group)
table.insert(vertical_group, vspan)
table.insert(vertical_group, button_group)
table.insert(self.fl_container, vertical_group)
-- Reset container height to what it actually contains
self.fl_container.dimen.h = vertical_group:getSize().h
return self.fl_container
end
function NaturalLightWidget:setAllValues(values)
self:setValueTextBox(self.white_gain[2], values.white_gain)
self:setValueTextBox(self.white_offset[2], values.white_offset)
self:setValueTextBox(self.red_gain[2], values.red_gain)
self:setValueTextBox(self.red_offset[2], values.red_offset)
self:setValueTextBox(self.green_gain[2], values.green_gain)
self:setValueTextBox(self.green_offset[2], values.green_offset)
self:setValueTextBox(self.exponent[2], values.exponent)
self:applyValues()
end
function NaturalLightWidget:setValueTextBox(widget, val)
widget:focus()
widget:setText(tostring(val))
widget:unfocus()
end
function NaturalLightWidget:onCloseWidget()
self:closeKeyboard()
UIManager:setDirty(nil, function()
Tame some ButtonTable users into re-using Buttontable instances if possible (#7166) * QuickDictLookup, ImageViewer, NumberPicker: Smarter `update` that will re-use most of the widget's layout instead of re-instantiating all the things. * SpinWidget/DoubleSpinWidget: The NumberPicker change above renders a hack to preserve alpha on these widgets almost unnecessary. Also fixed said hack to also apply to the center, value button. * Button: Don't re-instantiate the frame in setText/setIcon when unnecessary (e.g., no change at all, or no layout change). * Button: Add a refresh method that repaints and refreshes a *specific* Button (provided it's been painted once) all on its lonesome. * ConfigDialog: Free everything that's going to be re-instatiated on update * A few more post #7118 fixes: * SkimTo: Always flag the chapter nav buttons as vsync * Button: Fix the highlight on rounded buttons when vsync is enabled (e.g., it's now entirely visible, instead of showing a weird inverted corner glitch). * Some more heuristic tweaks in Menu/TouchMenu/Button/IconButton * ButtonTable: fix the annoying rounding issue I'd noticed in #7054 ;). * Enable dithering in TextBoxWidget (e.g., in the Wikipedia full view). This involved moving the HW dithering align fixup to base, where it always ought to have been ;). * Switch a few widgets that were using "partial" on close to "ui", or, more rarely, "flashui". The intent being to limit "partial" purely to the Reader, because it has a latency cost when mixed with other refreshes, which happens often enough in UI ;). * Minor documentation tweaks around UIManager's `setDirty` to reflect that change. * ReaderFooter: Force a footer repaint on resume if it is visible (otherwise, just update it). * ReaderBookmark: In the same vein, don't repaint an invisible footer on bookmark count changes.
3 years ago
return "flashui", self.nl_frame.dimen
end)
end
function NaturalLightWidget:onShow()
UIManager:setDirty(self, function()
return "ui", self.nl_frame.dimen
end)
-- Store values in case user cancels
self.old_values = self:getCurrentValues()
return true
end
function NaturalLightWidget:onClose()
UIManager:close(self)
return true
end
function NaturalLightWidget:onShowKeyboard()
if self._current_input then
self._current_input:onShowKeyboard()
self._current_input:focus()
end
end
function NaturalLightWidget:onCloseKeyboard()
if self._current_input then
self._current_input:onCloseKeyboard()
self._current_input:unfocus()
-- Make sure the cursor is deleted
UIManager:setDirty(self._current_input, "fast")
end
end
function NaturalLightWidget:onSwitchFocus(inputbox)
self:onCloseKeyboard()
self._current_input = inputbox
self:applyValues()
self:onShowKeyboard()
end
function NaturalLightWidget:closeKeyboard()
if self._current_input then
self._current_input:onCloseKeyboard()
self._current_input:unfocus()
end
end
return NaturalLightWidget