libui 0.3.0.pre2-x86_64-linux → 0.3.0.pre3-x86_64-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +114 -218
- data/lib/libui/area_handler.rb +155 -0
- data/lib/libui/callback_registry.rb +123 -0
- data/lib/libui/draw_values.rb +143 -0
- data/lib/libui/ffi.rb +37 -2
- data/lib/libui/font.rb +13 -0
- data/lib/libui/libui_base.rb +23 -29
- data/lib/libui/path.rb +70 -0
- data/lib/libui/platform.rb +12 -12
- data/lib/libui/table_model.rb +175 -0
- data/lib/libui/version.rb +1 -1
- data/lib/libui.rb +601 -2
- data/vendor/libui.x86_64.so +0 -0
- metadata +8 -2
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
module LibUI
|
|
2
|
+
# A Ruby value. to_native allocates a fresh uiTableValue whose ownership is
|
|
3
|
+
# transferred to libui-ng when returned from CellValue.
|
|
4
|
+
class TableValue
|
|
5
|
+
attr_reader :type, :value
|
|
6
|
+
|
|
7
|
+
def initialize(type, value)
|
|
8
|
+
@type = Integer(type)
|
|
9
|
+
@value = value
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_native
|
|
13
|
+
case type
|
|
14
|
+
when TableValueTypeString
|
|
15
|
+
raise TypeError, 'string table value must be a String' unless value.is_a?(String)
|
|
16
|
+
LibUI.new_table_value_string(value)
|
|
17
|
+
when TableValueTypeImage
|
|
18
|
+
raise TypeError, 'image table value must be a pointer or nil' unless value.nil? || value.is_a?(Fiddle::Pointer)
|
|
19
|
+
LibUI.new_table_value_image(value)
|
|
20
|
+
when TableValueTypeInt
|
|
21
|
+
LibUI.new_table_value_int(Integer(value))
|
|
22
|
+
when TableValueTypeColor
|
|
23
|
+
unless value.is_a?(Array) && value.length == 4 && value.all? { |part| part.is_a?(Numeric) }
|
|
24
|
+
raise TypeError, 'color table value must be an RGBA array'
|
|
25
|
+
end
|
|
26
|
+
LibUI.new_table_value_color(*value)
|
|
27
|
+
else
|
|
28
|
+
raise ArgumentError, "unknown table value type: #{type}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.from_native(pointer)
|
|
33
|
+
return nil if pointer.nil? || pointer.to_i.zero?
|
|
34
|
+
|
|
35
|
+
type = LibUI.table_value_get_type(pointer)
|
|
36
|
+
value = case type
|
|
37
|
+
when TableValueTypeString then LibUI.table_value_string(pointer)
|
|
38
|
+
when TableValueTypeImage then LibUI.table_value_image(pointer)
|
|
39
|
+
when TableValueTypeInt then LibUI.table_value_int(pointer)
|
|
40
|
+
when TableValueTypeColor then LibUI.table_value_color(pointer)
|
|
41
|
+
else raise ArgumentError, "unknown table value type: #{type}"
|
|
42
|
+
end
|
|
43
|
+
new(type, value)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class TableModelHandler
|
|
48
|
+
attr_reader :column_types
|
|
49
|
+
|
|
50
|
+
def initialize(column_types:, rows:, cell_value: nil, set_cell_value: nil)
|
|
51
|
+
unless column_types.is_a?(Array) && column_types.all? { |type| type.is_a?(Integer) && (0..3).cover?(type) }
|
|
52
|
+
raise ArgumentError, 'column_types must be an array of table value types'
|
|
53
|
+
end
|
|
54
|
+
unless rows.is_a?(Array) || rows.respond_to?(:call)
|
|
55
|
+
raise TypeError, 'rows must be an Array or a row-count callback'
|
|
56
|
+
end
|
|
57
|
+
if rows.respond_to?(:call) && !cell_value
|
|
58
|
+
raise ArgumentError, 'cell_value is required when rows is a callback'
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
@column_types = column_types.dup.freeze
|
|
62
|
+
@rows = rows
|
|
63
|
+
@cell_value = cell_value || ->(row, column) { @rows.fetch(row).fetch(column) }
|
|
64
|
+
@set_cell_value = set_cell_value || (rows.is_a?(Array) ? ->(row, column, value) { @rows.fetch(row)[column] = value } : nil)
|
|
65
|
+
@native = FFI::TableModelHandler.malloc
|
|
66
|
+
@native.to_ptr.free = Fiddle::RUBY_FREE
|
|
67
|
+
@closures = {}
|
|
68
|
+
install_callbacks
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def to_ptr
|
|
72
|
+
@native.to_ptr
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def install_callbacks
|
|
78
|
+
pointer = Fiddle::TYPE_VOIDP
|
|
79
|
+
integer = Fiddle::TYPE_INT
|
|
80
|
+
@closures[:num_columns] = callback(integer, [pointer, pointer]) { @column_types.length }
|
|
81
|
+
@closures[:column_type] = callback(integer, [pointer, pointer, integer]) do |_handler, _model, column|
|
|
82
|
+
@column_types.fetch(column)
|
|
83
|
+
end
|
|
84
|
+
@closures[:num_rows] = callback(integer, [pointer, pointer]) do
|
|
85
|
+
@rows.respond_to?(:call) ? Integer(@rows.call) : @rows.length
|
|
86
|
+
end
|
|
87
|
+
@closures[:cell_value] = callback(pointer, [pointer, pointer, integer, integer]) do |_handler, _model, row, column|
|
|
88
|
+
type = @column_types.fetch(column)
|
|
89
|
+
begin
|
|
90
|
+
value = @cell_value.call(row, column)
|
|
91
|
+
table_value = value.is_a?(TableValue) ? value : TableValue.new(type, value)
|
|
92
|
+
raise TypeError, 'table value type does not match model column' unless table_value.type == type
|
|
93
|
+
table_value.to_native.to_i
|
|
94
|
+
rescue StandardError => e
|
|
95
|
+
CallbackRegistry.report(e)
|
|
96
|
+
fallback = case type
|
|
97
|
+
when TableValueTypeString then ''
|
|
98
|
+
when TableValueTypeImage then nil
|
|
99
|
+
when TableValueTypeInt then 0
|
|
100
|
+
when TableValueTypeColor then [0.0, 0.0, 0.0, 0.0]
|
|
101
|
+
end
|
|
102
|
+
TableValue.new(type, fallback).to_native.to_i
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
@closures[:set_cell_value] = callback(Fiddle::TYPE_VOID,
|
|
106
|
+
[pointer, pointer, integer, integer, pointer]) do |_handler, _model, row, column, native_value|
|
|
107
|
+
@set_cell_value&.call(row, column, TableValue.from_native(native_value)&.value)
|
|
108
|
+
end
|
|
109
|
+
@native.NumColumns = @closures[:num_columns]
|
|
110
|
+
@native.ColumnType = @closures[:column_type]
|
|
111
|
+
@native.NumRows = @closures[:num_rows]
|
|
112
|
+
@native.CellValue = @closures[:cell_value]
|
|
113
|
+
@native.SetCellValue = @closures[:set_cell_value]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def callback(return_type, argument_types, &block)
|
|
117
|
+
Fiddle::Closure::BlockCaller.new(return_type, argument_types) do |*args|
|
|
118
|
+
begin
|
|
119
|
+
block.call(*args)
|
|
120
|
+
rescue StandardError => e
|
|
121
|
+
CallbackRegistry.report(e)
|
|
122
|
+
0
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
class TableModel
|
|
129
|
+
attr_reader :handler
|
|
130
|
+
|
|
131
|
+
def initialize(handler = nil, **options)
|
|
132
|
+
@handler = handler || TableModelHandler.new(**options)
|
|
133
|
+
raise TypeError, 'expected LibUI::TableModelHandler' unless @handler.is_a?(TableModelHandler)
|
|
134
|
+
|
|
135
|
+
@pointer = LibUI.new_table_model(@handler)
|
|
136
|
+
@attached_tables = 0
|
|
137
|
+
@freed = false
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def to_ptr
|
|
141
|
+
raise RuntimeError, 'table model has been freed' if @freed
|
|
142
|
+
|
|
143
|
+
@pointer
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def row_inserted(index)
|
|
147
|
+
LibUI.table_model_row_inserted(to_ptr, index)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def row_changed(index)
|
|
151
|
+
LibUI.table_model_row_changed(to_ptr, index)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def row_deleted(index)
|
|
155
|
+
LibUI.table_model_row_deleted(to_ptr, index)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def free
|
|
159
|
+
raise RuntimeError, 'table model is still attached to a table' if @attached_tables.positive?
|
|
160
|
+
return if @freed
|
|
161
|
+
|
|
162
|
+
LibUI.free_table_model(@pointer)
|
|
163
|
+
@freed = true
|
|
164
|
+
nil
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def attach_table
|
|
168
|
+
@attached_tables += 1
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def detach_table
|
|
172
|
+
@attached_tables -= 1
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
data/lib/libui/version.rb
CHANGED