1
1
mirror of https://github.com/NixOS/mobile-nixos.git synced 2024-12-12 15:24:14 +03:00

lvgui: Use LVGUI::Native

Most of the changes are `s/LVGL::FFI/LVGUI::Native/`, but there are some
other notable changes.

Some correctness issues with nil usage where "" should have been used.

String handling is better, and does not require tacking on, for unknown
reason, a null at the end of the string.
This commit is contained in:
Samuel Dionne-Riel 2021-09-24 22:20:53 -04:00
parent a75f644101
commit a272d16eb2
9 changed files with 114 additions and 185 deletions

View File

@ -1,51 +1,3 @@
# FFI bindings for a couple of our hacks.
module LVGL::FFI
# TODO: Figure out when the following struct (and this typedef) are at the
# end, this segfaults...
typedef "lv_task_cb_t", "void (*lv_task_cb_t)(struct _lv_task_t *)"
LvTask = struct! [ # {{{
[:uint32_t, :period],
[:uint32_t, :last_run],
[:lv_task_cb_t, :task_cb],
["void *", :user_data],
[:uint8_t, :prio],
[:uint8_t, :once],
] # }}}
extern "void hal_init(const char*)"
# TODO: begin/rescue DLError and assume failing is we're not in simulator.
if lv_introspection_is_simulator
global!("int", "monitor_width")
global!("int", "monitor_height")
end
global!("int", "mn_hal_default_dpi")
global!("void *", "mn_hal_default_font")
extern "void lv_task_handler()"
def handle_lv_task(lv_task_p)
# Unwrap the lv_task struct we received
lv_task = LvTask.new(lv_task_p.to_i)
# This is the userdata that has been given
userdata = lv_task.user_data
# Side-step our inability to rehydrate an mruby Object properly
task = LVGL::Hacks::LVTask::REGISTRY[userdata.to_i]
# Call the task
task.call()
end
bound_method! :handle_lv_task, "void handle_lv_task_(lv_task_t * task)"
extern "lv_task_t * lv_task_create(lv_task_cb_t, uint32_t, lv_task_prio_t, void *)"
end
# FFI bindings for "hacks" for lv_lib_nanosvg
module LVGL::FFI
# lv_lib_nanosvg/lv_nanosvg.h
extern "void lv_nanosvg_init()"
end
module LVGL::Hacks
FONTS = {}
@@assets_path = nil
@ -68,36 +20,36 @@ module LVGL::Hacks
data_dir ||= File.join(XDG.data_dirs.first, assets_path)
LVGL::Hacks.set_assets_path(data_dir)
LVGL::FFI.hal_init(get_asset_path(""))
LVGL::FFI.lv_nanosvg_init()
LVGUI::Native.hal_init(get_asset_path(""))
LVGUI::Native.lv_nanosvg_init()
end
def self.monitor_height=(v)
if LVGL::Introspection.simulator?
LVGL::FFI.monitor_height = v
LVGUI::Native.monitor_height = v
end
end
def self.monitor_width=(v)
if LVGL::Introspection.simulator?
LVGL::FFI.monitor_width = v
LVGUI::Native.monitor_width = v
end
end
def self.dpi()
LVGL::FFI.mn_hal_default_dpi
LVGUI::Native.mn_hal_default_dpi
end
def self.default_font()
LVGL::FFI.mn_hal_default_font
LVGUI::Native.mn_hal_default_font
end
def self.theme_night()
LVGL::FFI.lv_theme_set_current(
LVGL::FFI.lv_theme_night_init(205, 0)
LVGUI::Native.lv_theme_set_current(
LVGUI::Native.lv_theme_night_init(205, nil)
)
end
def self.theme_nixos(font = 0, button_font = 0)
LVGL::FFI.lv_theme_set_current(
LVGL::FFI.lv_theme_nixos_init(font, button_font)
def self.theme_nixos(font = nil, button_font = nil)
LVGUI::Native.lv_theme_set_current(
LVGUI::Native.lv_theme_nixos_init(font, button_font)
)
end
@ -116,33 +68,28 @@ module LVGL::Hacks
if FONTS[id]
FONTS[id]
else
FONTS[id] = LVGL::FFI.lvgui_get_font(get_asset_path(file), size)
FONTS[id] = LVGUI::Native.lvgui_get_font(get_asset_path(file), size)
end
)
end
module LVTask
# Temp hack...
# I need to figure out how to use Fiddle's #to_value to rehydrate an mruby
# Object into its proper form.
REGISTRY = {
# userdata pointer int value => instance
}
def self.create_task(period, prio, task)
userdata = Fiddle::Pointer[task]
REGISTRY[userdata.to_i] = task
def self.create_task(period, prio, task_proc)
if LVGUI::Native::References[:lvgui_handle_lv_task_callback].nil?
raise "FATAL: bug in native impl of lvgui_handle_lv_task_callback (it is nil)..."
end
LVGL::FFI.lv_task_create(
LVGL::FFI["handle_lv_task"],
LVGUI::Native.lv_task_create(
LVGUI::Native::References[:lvgui_handle_lv_task_callback],
period,
prio,
userdata
task_proc
)
end
def self.handle_tasks()
#$stderr.puts "-> handle_tasks"
LVGL::FFI.lv_task_handler()
LVGUI::Native.lv_task_handler()
#$stderr.puts "<- handle_tasks"
end
end

View File

@ -1,14 +1,14 @@
module LVGL::Introspection
def self.debug?()
LVGL::FFI.lv_introspection_is_debug != 0
LVGUI::Native.lv_introspection_is_debug != 0
end
def self.simulator?()
LVGL::FFI.lv_introspection_is_simulator != 0
LVGUI::Native.lv_introspection_is_simulator != 0
end
def self.use_assert_style?()
LVGL::FFI.lv_introspection_use_assert_style != 0
LVGUI::Native.lv_introspection_use_assert_style != 0
end
def self.display_driver()
LVGL::FFI.lv_introspection_display_driver
LVGUI::Native.lv_introspection_display_driver
end
end

View File

@ -20,7 +20,7 @@ module LVGL
:TASK_PRIO,
:TA_STYLE,
].each do |enum_name|
const_set(enum_name, LVGL::FFI.const_get("LV_#{enum_name}".to_sym))
const_set(enum_name, LVGUI::Native.const_get("LV_#{enum_name}".to_sym))
LVGL.const_get(enum_name).module_exec do
def self.from_value(needle)
self.constants.find do |name|
@ -31,17 +31,21 @@ module LVGL
end
def self.ffi_call!(klass, meth, *args, _initiator_class: nil)
#puts("[TRACE] #{klass.name}##{meth}(#{args.map(&:inspect).join(", ")});")
_initiator_class ||= klass
if klass == Object
raise "Tried to ffi_call!(..., #{meth}) with a #{_initiator_class.name}, but could not find `#{meth}` in the ancestry."
end
unless klass.const_defined?(:LV_TYPE)
raise "Tried to ffi_call!(..., #{meth}) with a #{_initiator_class.name}, which does not define LV_TYPE"
raise "Tried to ffi_call!(..., #{meth}) with a #{klass.name} (ancestor of #{_initiator_class.name}), which does not define LV_TYPE"
end
ffi_name = "lv_#{klass.const_get(:LV_TYPE)}_#{meth}".to_sym
if LVGL::FFI.respond_to?(ffi_name)
if LVGUI::Native.respond_to?(ffi_name)
args = args.map do |arg|
case arg
when nil
0
nil
when false
0
when true
@ -54,7 +58,7 @@ module LVGL
end
end
end
return LVGL::FFI.send(ffi_name, *args)
return LVGUI::Native.send(ffi_name, *args)
else
if klass.superclass
return ffi_call!(klass.superclass, meth, *args, _initiator_class: _initiator_class)
@ -65,11 +69,11 @@ module LVGL
end
def self.layer_top()
LVObject.from_pointer(LVGL::FFI.lv_layer_top())
LVObject.from_pointer(LVGUI::Native.lv_layer_top())
end
def self.layer_sys()
LVObject.from_pointer(LVGL::FFI.lv_layer_sys())
LVObject.from_pointer(LVGUI::Native.lv_layer_sys())
end
class LVDisplay
@ -77,13 +81,13 @@ module LVGL
# Get default display
def self.get_default()
LVGL::FFI.lv_disp_get_default()
LVGUI::Native.lv_disp_get_default()
end
# Gets the current active screen.
def self.get_scr_act()
LVObject.from_pointer(
LVGL::FFI.lv_disp_get_scr_act(get_default())
LVGUI::Native.lv_disp_get_scr_act(get_default())
)
end
end
@ -92,8 +96,7 @@ module LVGL
LV_TYPE = :obj
# Hack...
# I need to figure out how to use Fiddle's #to_value to rehydrate an mruby
# Object into its proper form.
# I need to figure out how to rehydrate an mruby Object into its proper form.
REGISTRY = {
# @self_pointer int value => instance
}
@ -113,9 +116,10 @@ module LVGL
else
@self_pointer = pointer
end
REGISTRY[@self_pointer.to_i] = self
register_userdata
unless parent or pointer
LVGL::FFI.lv_disp_load_scr(@self_pointer)
LVGUI::Native.lv_disp_load_scr(@self_pointer)
end
end
@ -143,24 +147,40 @@ module LVGL
end
def glue_obj(value)
# (function needed since it's in the lv_page namespace and not lv_obj)
value =
if value
1
else
0
end
LVGL::FFI.lv_page_glue_obj(@self_pointer, value)
LVGUI::Native.lv_page_glue_obj(@self_pointer, value)
end
def method_missing(meth, *args)
LVGL.ffi_call!(self.class, meth, @self_pointer, *args)
end
def handle_lv_event(event)
if @__event_handler_proc
@__event_handler_proc.call(event)
end
end
def event_handler=(cb_proc)
# Hook the handler on-the-fly, assuming it wasn't set if we didn't have
# a handler proc.
unless @__event_handler_proc
LVGL.ffi_call!(self.class, :set_event_cb, @self_pointer, LVGL::FFI["handle_lv_event"])
if LVGUI::Native::References[:lvgui_handle_lv_event_callback].nil?
raise "FATAL: bug in native impl of lvgui_handle_lv_event_callback (it is nil)..."
end
LVGL.ffi_call!(
self.class,
:set_event_cb,
@self_pointer,
LVGUI::Native::References[:lvgui_handle_lv_event_callback]
)
end
@__event_handler_proc = cb_proc
end
@ -170,9 +190,8 @@ module LVGL
end
def register_userdata()
userdata = Fiddle::Pointer[self]
REGISTRY[@self_pointer.to_i] = self
LVGL.ffi_call!(self.class, :set_user_data, @self_pointer, userdata)
# Skip ffi_call!; it tries to be helpful with `self`.
LVGUI::Native.lv_obj_set_user_data(@self_pointer, self)
end
def get_parent()
@ -196,9 +215,6 @@ module LVGL
class LVContainer < LVObject
LV_TYPE = :cont
def set_layout(*args)
LVGL::FFI.lv_cont_set_layout(@self_pointer, *args)
end
def get_style(type)
# type is unused, see lvgl/src/lv_objx/lv_cont.h
@ -223,18 +239,6 @@ module LVGL
# type is unused, see lvgl/src/lv_objx/lv_label.h
super(style)
end
def set_text(text)
text ||= ""
# The "\0" thing is a bit scary; it seems that *something* related
# to C string and "\0" in either mruby or LVGL, likely mruby, may
# cause issues when using something like `split` to split a bigger
# string.
#
# My assumption is that the ruby string is not \0 completed, and
# given as-is to the C world via ffi.
LVGL.ffi_call!(self.class, :set_text, @self_pointer, text + "\0")
end
end
class LVImage < LVObject
@ -317,50 +321,6 @@ module LVGL
class LVTextArea < LVObject
LV_TYPE = :ta
def add_text(text)
# The "\0" thing is a bit scary; it seems that *something* related
# to C string and "\0" in either mruby or LVGL, likely mruby, may
# cause issues when using something like `split` to split a bigger
# string.
#
# My assumption is that the ruby string is not \0 completed, and
# given as-is to the C world via ffi.
LVGL.ffi_call!(self.class, :add_text, @self_pointer, text + "\0")
end
def set_text(text)
# The "\0" thing is a bit scary; it seems that *something* related
# to C string and "\0" in either mruby or LVGL, likely mruby, may
# cause issues when using something like `split` to split a bigger
# string.
#
# My assumption is that the ruby string is not \0 completed, and
# given as-is to the C world via ffi.
LVGL.ffi_call!(self.class, :set_text, @self_pointer, text + "\0")
end
def set_placeholder_text(text)
# The "\0" thing is a bit scary; it seems that *something* related
# to C string and "\0" in either mruby or LVGL, likely mruby, may
# cause issues when using something like `split` to split a bigger
# string.
#
# My assumption is that the ruby string is not \0 completed, and
# given as-is to the C world via ffi.
LVGL.ffi_call!(self.class, :set_placeholder_text, @self_pointer, text + "\0")
end
def set_accepted_chars(text)
# The "\0" thing is a bit scary; it seems that *something* related
# to C string and "\0" in either mruby or LVGL, likely mruby, may
# cause issues when using something like `split` to split a bigger
# string.
#
# My assumption is that the ruby string is not \0 completed, and
# given as-is to the C world via ffi.
LVGL.ffi_call!(self.class, :set_accepted_chars, @self_pointer, text + "\0")
end
def get_style(style_type)
style = LVGL.ffi_call!(self.class, :get_style, @self_pointer, style_type)
LVGL::LVStyle.from_pointer(style)
@ -392,7 +352,7 @@ module LVGL
# Wraps an +lv_style_t+ in a class with some light duty housekeeping.
class LVStyle
# Given a +Fiddle::Pointer+ pointing to an +lv_style_t+, instantiates
# Given an +OpaquePointer+ pointing to an +lv_style_t+, instantiates
# an LVStyle class, wrapping the struct.
def self.from_pointer(pointer)
instance = LVGL::LVStyle.new()
@ -406,8 +366,8 @@ module LVGL
# Allocates a new +lv_style_t+, and copies the styles using the LVGL
# +lv_style_copy+.
def initialize_copy(orig)
@self_pointer = LVGL::FFI.lvgui_allocate_lv_style()
LVGL::FFI.lv_style_copy(@self_pointer, orig.lv_style_pointer)
@self_pointer = LVGUI::Native.lvgui_allocate_lv_style()
LVGUI::Native.lv_style_copy(@self_pointer, orig.lv_style_pointer)
end
def lv_style_pointer()
@ -424,7 +384,8 @@ module LVGL
"lvgui_get_lv_style__#{meth}".to_sym
end
LVGL::FFI.send(meth, @self_pointer, *args)
#puts "[TRACE] #{self.class.name}##{meth}#(#{args.map(&:inspect).join(", ")})"
LVGUI::Native.send(meth, @self_pointer, *args)
end
private
@ -453,10 +414,10 @@ module LVGL
global_name = "lv_style_#{name}".downcase
const_name = "style_#{name}".upcase.to_sym
wrapped = self.from_pointer(
LVGL::FFI.handler.sym(global_name)
LVGUI::Native.send(global_name.to_sym)
)
const_set(const_name, wrapped)
end
end
end
class LVGroup
@ -477,10 +438,11 @@ module LVGL
else
@self_pointer = pointer
end
REGISTRY[@self_pointer.to_i] = self
register_userdata
end
# Given a +Fiddle::Pointer+ pointing to an +lv_group_t+, instantiates
# Given a +OpaquePointer+ pointing to an +lv_group_t+, instantiates
# an LVGroup class, wrapping the struct.
def self.from_pointer(pointer)
if REGISTRY[pointer.to_i]
@ -541,9 +503,7 @@ module LVGL
def register_userdata()
LVGL.ffi_call!(self.class, :remove_all_objs, @self_pointer)
userdata = Fiddle::Pointer[self]
REGISTRY[@self_pointer.to_i] = self
LVGL.ffi_call!(self.class, :set_user_data, @self_pointer, userdata)
LVGL.ffi_call!(self.class, :set_user_data, @self_pointer, self)
end
# Keep the previous focus group aside in memory, and empty the focus group.
@ -581,9 +541,24 @@ module LVGL
LVGL.ffi_call!(self.class, :add_obj, @self_pointer, ptr)
end
def handle_lv_focus()
if prc = @focus_handler_proc_stack.last
prc.call()
end
end
def _set_focus_handler(cb_proc)
if LVGUI::Native::References[:lvgui_handle_lv_focus_callback].nil?
raise "FATAL: bug in native impl of lvgui_handle_lv_focus_callback (it is nil)..."
end
# Hook the handler on-the-fly.
LVGL.ffi_call!(self.class, :set_focus_cb, @self_pointer, LVGL::FFI["handle_lv_focus"])
LVGL.ffi_call!(
self.class,
:set_focus_cb,
@self_pointer,
LVGUI::Native::References[:lvgui_handle_lv_focus_callback]
)
end
end
@ -591,34 +566,41 @@ module LVGL
class LVAnim
LV_TYPE = :anim
# Given a +Fiddle::Pointer+ pointing to an +lv_anim_t+, instantiates
# Given a +OpaquePointer+ pointing to an +lv_anim_t+, instantiates
# an LVAnim class, wrapping the struct.
def self.from_pointer(pointer)
instance = LVGL::LVAnim.new()
instance.instance_exec do
@self_pointer = pointer
@lv_anim_pointer = pointer
end
instance
end
def initialize()
@self_pointer = LVGL::FFI.lvgui_allocate_lv_anim()
@lv_anim_pointer = LVGUI::Native.lvgui_allocate_lv_anim()
self.init
end
def lv_anim_pointer()
@self_pointer
@lv_anim_pointer
end
def set_exec_cb(obj, cb_name)
fn = LVGL::FFI[cb_name.to_s]
raise "No function for #{cb_name} on LVGL::FFI" unless fn
LVGL.ffi_call!(self.class, "set_exec_cb", @self_pointer, obj.lv_obj_pointer, fn)
def set_exec_cb(target, cb_name)
if LVGUI::Native::References[cb_name].nil?
raise "No function for #{cb_name} on LVGUI::Native"
end
LVGL.ffi_call!(
self.class,
"set_exec_cb",
@lv_anim_pointer,
target.lv_obj_pointer,
LVGUI::Native::References[cb_name]
)
end
def method_missing(meth, *args)
LVGL.ffi_call!(self.class, meth, @self_pointer, *args)
LVGL.ffi_call!(self.class, meth, @lv_anim_pointer, *args)
end
module Path
@ -634,7 +616,7 @@ module LVGL
].each do |name|
const_set(
name.upcase.to_sym,
LVGL::FFI.handler.sym("lv_anim_path_#{name}".downcase)
LVGUI::Native.send("lv_anim_path_#{name}".downcase.to_sym)
)
end
end
@ -729,7 +711,7 @@ module LVGL
module LVColor
def self.mix(col1, col2, mix)
LVGL::FFI.lv_color_mix(col1, col2, mix)
LVGUI::Native.lv_color_mix(col1, col2, mix)
end
end
end

View File

@ -106,7 +106,7 @@ module LVGUI
LVGL::Hacks.init(assets_path: assets_path)
# Start the animation core
LVGL::FFI.lv_anim_core_init()
LVGUI::Native.lv_anim_core_init()
if theme == :nixos then
LVGL::Hacks.theme_nixos(LVGUI::Fonts.primary(), LVGUI::Fonts.secondary())
@ -128,12 +128,12 @@ module LVGUI
def self.focus_group()
LVGL::LVGroup.from_pointer(
LVGL::FFI.lvgui_get_focus_group
LVGUI::Native.lvgui_get_focus_group
)
end
def self.focus_ring_disable()
LVGL::FFI.lvgui_focus_ring_disable()
LVGUI::Native.lvgui_focus_ring_disable()
end
module Styles

View File

@ -69,7 +69,7 @@ module LVGUI
# Switch to this window
def present()
LVGL::FFI.lv_disp_load_scr(@screen.lv_obj_pointer)
LVGUI::Native.lv_disp_load_scr(@screen.lv_obj_pointer)
reset_focus_group
# Allow the window to do some work every time it is switched to.

View File

@ -9,7 +9,7 @@ class LVGUI::Clock < LVGUI::Widget
update_clock
# Then register a task to update regularly.
@task = LVGL::Hacks::LVTask.create_task(250, LVGL::TASK_PRIO::MID, ->() do
@task = LVGL::Hacks::LVTask.create_task(250, LVGL::TASK_PRIO::LOW, ->() do
update_clock
end)
end

View File

@ -50,7 +50,7 @@ class LVGUI::OptionSelection < LVGUI::Widget
label.set_long_mode(LVGL::LABEL_LONG::BREAK)
label.set_click(false)
end
set_label(nil)
set_label("")
# The chosen option label (second row, optional)
@chosen_option_label = LVGL::LVLabel.new(@label_container).tap do |label|
@ -61,7 +61,7 @@ class LVGUI::OptionSelection < LVGUI::Widget
label.set_long_mode(LVGL::LABEL_LONG::BREAK)
label.set_click(false)
end
set_chosen_option_label(nil)
set_chosen_option_label("")
# Drill down icon
@icon = LVGL::LVLabel.new(self).tap do |icon|

View File

@ -31,7 +31,7 @@ class LVGUI::SwitchLine < LVGUI::Widget
@main_label = LVGL::LVLabel.new(@label_container).tap do |label|
label.set_long_mode(LVGL::LABEL_LONG::BREAK)
end
set_label(nil)
set_label("")
# The description label (second row, optional)
@description_label = LVGL::LVLabel.new(@label_container).tap do |label|
@ -41,7 +41,7 @@ class LVGUI::SwitchLine < LVGUI::Widget
label.set_style(LVGL::LABEL_STYLE::MAIN, style)
label.set_long_mode(LVGL::LABEL_LONG::BREAK)
end
set_description(nil)
set_description("")
# Add the actual toggle control
@switch = LVGL::LVSwitch.new(self)

View File

@ -35,7 +35,7 @@ class LVGUI::TextArea < LVGUI::Widget
LVGUI::Keyboard.instance.show()
when LVGL::EVENT::INSERT
# Not exactly right, but right enough.
char = LVGL::FFI.lv_event_get_data().to_str(1)
char = LVGUI::Native.lv_event_get_data().ref_to_char()
# Assume there is only one input.
# Also assume Enter sends; that it is a single line.
if char == "\n"