libui 0.0.5.alpha → 0.0.9
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 +152 -7
- data/lib/libui/ffi.rb +46 -36
- data/lib/libui/utils.rb +19 -0
- data/lib/libui/version.rb +1 -1
- data/lib/libui.rb +20 -22
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dbb5362886495f17bf74055bf1ad4cbc96bb7f0e4518e8db0b18f9572559adf2
|
4
|
+
data.tar.gz: 19040d301c6cb135a3e5ef1270f211f48f007f02ec3e5fe7edcbc3be03f275da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27a0c320d8592b2e6a6531b66ed0de3a83a3f606058d16469af530d0633a02d2d13e848e5ca4dd8d6c184015449a2ba56b4eb6c7e63ede1ccb7bfa6d447b5f1b
|
7
|
+
data.tar.gz: '033190ef229e3f567db9c7a7d338da4107072a6120e79c928a5e03dffcca922ffe75ac76f631fda810133cd6316d6af55ea234eb3fce214540fe1e92fd7d6eaf'
|
data/README.md
CHANGED
@@ -1,37 +1,182 @@
|
|
1
|
-
#
|
1
|
+
# LibUI
|
2
2
|
|
3
3
|

|
4
4
|
[](https://badge.fury.io/rb/libui)
|
5
5
|
|
6
|
-
:radio_button: [libui](https://github.com/andlabs/libui) - a portable GUI library -for Ruby
|
6
|
+
:radio_button: [libui](https://github.com/andlabs/libui) - a portable GUI library - for Ruby
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
|
10
10
|
```sh
|
11
|
-
gem install libui
|
11
|
+
gem install libui
|
12
12
|
```
|
13
13
|
|
14
|
-
The
|
14
|
+
* The gem package contains the [official release](https://github.com/andlabs/libui/releases/tag/alpha4.1) of the libui shared library versions 4.1 for Windows, Mac, and Linux.
|
15
|
+
* Namely `libui.dll`, `libui.dylib`, and `libui.so` (only 1.4MB in total).
|
16
|
+
* No dependency
|
17
|
+
* The libui gem uses the standard Ruby library [Fiddle](https://github.com/ruby/fiddle) to call C functions.
|
18
|
+
|
19
|
+
| Windows | Mac | Linux |
|
20
|
+
|---------|-----|-------|
|
21
|
+
|<img src="https://user-images.githubusercontent.com/5798442/103118046-900ea780-46b0-11eb-81fc-32626762e4df.png">|<img src="https://user-images.githubusercontent.com/5798442/103118059-99980f80-46b0-11eb-9d12-324ec4d297c9.png">|<img src="https://user-images.githubusercontent.com/5798442/103118068-a0bf1d80-46b0-11eb-8c5c-3bdcc3dcfb26.png">|
|
22
|
+
|
23
|
+
Note: If you are using the 32-bit (x86) version of Ruby, you need to download the 32-bit (x86) native dll. See [Development](#development).
|
15
24
|
|
16
25
|
## Usage
|
17
26
|
|
27
|
+
```ruby
|
28
|
+
require 'libui'
|
29
|
+
|
30
|
+
UI = LibUI
|
31
|
+
|
32
|
+
UI.init
|
33
|
+
|
34
|
+
main_window = UI.new_window('hello world', 200, 100, 1)
|
35
|
+
|
36
|
+
button = UI.new_button('Button')
|
37
|
+
|
38
|
+
UI.button_on_clicked(button) do
|
39
|
+
UI.msg_box(main_window, 'Information', 'You clicked the button')
|
40
|
+
end
|
41
|
+
|
42
|
+
UI.window_on_closing(main_window) do
|
43
|
+
puts 'Bye Bye'
|
44
|
+
UI.control_destroy(main_window)
|
45
|
+
UI.quit
|
46
|
+
0
|
47
|
+
end
|
48
|
+
|
49
|
+
UI.window_set_child(main_window, button)
|
50
|
+
UI.control_show(main_window)
|
51
|
+
|
52
|
+
UI.main
|
53
|
+
UI.quit
|
54
|
+
```
|
55
|
+
|
18
56
|
See [examples](https://github.com/kojix2/libui/tree/main/examples) directory.
|
19
57
|
|
58
|
+
### General Rules
|
59
|
+
|
60
|
+
Compared to original libui written in C,
|
61
|
+
|
62
|
+
* The method names are snake_case.
|
63
|
+
* If the last argument is nil, it can be omitted.
|
64
|
+
* You can pass a block as a callback.
|
65
|
+
* The block will be converted to a Proc object and added to the last argument.
|
66
|
+
* Even in that case, it is possible to omit the last argument nil.
|
67
|
+
|
68
|
+
### Not object oriented?
|
69
|
+
|
70
|
+
* At the moment, it is not object-oriented.
|
71
|
+
* Instead of providing a half-baked object-oriented approach, leave it as is.
|
72
|
+
|
73
|
+
### How to use fiddle pointers?
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
require 'libui'
|
77
|
+
UI = LibUI
|
78
|
+
UI.init
|
79
|
+
```
|
80
|
+
|
81
|
+
Convert a pointer to a string.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
label = UI.new_label("Ruby")
|
85
|
+
p pointer = UI.label_text(label) # #<Fiddle::Pointer>
|
86
|
+
p pointer.to_s # Ruby
|
87
|
+
```
|
88
|
+
|
89
|
+
If you need to use C structs, you can do the following.
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
font_button = UI.new_font_button
|
93
|
+
|
94
|
+
# Allocate memory
|
95
|
+
font_descriptor = UI::FFI::FontDescriptor.malloc
|
96
|
+
|
97
|
+
UI.font_button_on_changed(font_button) do
|
98
|
+
UI.font_button_font(font_button, font_descriptor)
|
99
|
+
p family: font_descriptor.Family.to_s,
|
100
|
+
size: font_descriptor.Size,
|
101
|
+
weight: font_descriptor.Weight,
|
102
|
+
italic: font_descriptor.Italic,
|
103
|
+
stretch: font_descriptor.Stretch
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
* Callbacks
|
108
|
+
* In Ruby/Fiddle, C callback function is written as an object of
|
109
|
+
`Fiddle::Closure::BlockCaller` or `Fiddle::Closure`.
|
110
|
+
In this case, you need to be careful about Ruby's garbage collection.
|
111
|
+
If the function object is collected, memory will be freed
|
112
|
+
and a segmentation violation will occur when the callback is invoked.
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
# to a local variable to prevent it from being collected by GC.
|
116
|
+
handler.MouseEvent = (c1 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
|
117
|
+
handler.MouseCrossed = (c2 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
|
118
|
+
handler.DragBroken = (c3 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
|
119
|
+
```
|
120
|
+
|
121
|
+
### How to create an executable (.exe) on Windows
|
122
|
+
|
123
|
+
OCRA (One-Click Ruby Application) builds Windows executables from Ruby source code.
|
124
|
+
* https://github.com/larsch/ocra/
|
125
|
+
|
126
|
+
In order to build a exe with Ocra, include 3 DLLs from ruby_builtin_dlls folder:
|
127
|
+
|
128
|
+
```sh
|
129
|
+
ocra examples/control_gallery.rb ^
|
130
|
+
--dll ruby_builtin_dlls/libssp-0.dll ^
|
131
|
+
--dll ruby_builtin_dlls/libgmp-10.dll ^
|
132
|
+
--dll ruby_builtin_dlls/libffi-7.dll ^
|
133
|
+
--gem-all=fiddle ^
|
134
|
+
```
|
135
|
+
|
136
|
+
Add additional options below if necessary.
|
137
|
+
|
138
|
+
```sh
|
139
|
+
--window ^
|
140
|
+
--add-all-core ^
|
141
|
+
--chdir-first ^
|
142
|
+
--icon assets\app.ico ^
|
143
|
+
--verbose ^
|
144
|
+
--output out\gallery.exe
|
145
|
+
```
|
146
|
+
|
20
147
|
## Development
|
21
148
|
|
22
149
|
```sh
|
23
150
|
git clone https://github.com/kojix2/libui
|
24
151
|
cd libui
|
25
152
|
bundle install
|
26
|
-
bundle exec rake vendor:all
|
153
|
+
bundle exec rake vendor:all_x64 # download shared libraries for all platforms
|
27
154
|
bundle exec rake test
|
28
155
|
```
|
29
156
|
|
30
|
-
|
157
|
+
You can use the following rake tasks to download the shared library required for your platform.
|
158
|
+
|
159
|
+
`rake -T`
|
160
|
+
|
161
|
+
```
|
162
|
+
rake vendor:all_x64 # Download libui.so, libui.dylib, and libui.dll to...
|
163
|
+
rake vendor:linux_x64 # Download libui.so for Linux to vendor directory
|
164
|
+
rake vendor:linux_x86 # Download libui.so for Linux to vendor directory
|
165
|
+
rake vendor:mac_x64 # Download libui.dylib for Mac to vendor directory
|
166
|
+
rake vendor:windows_x64 # Download libui.dll for Windows to vendor directory
|
167
|
+
rake vendor:windows_x86 # Download libui.dll for Windows to vendor directory
|
168
|
+
```
|
169
|
+
|
170
|
+
For example, If you are using a 32-bit (x86) version of Ruby on Windows, type `rake vendor:windows_x86`.
|
171
|
+
|
172
|
+
Or Set environment variable `LIBUIDIR` to specify the path to the shared library.
|
31
173
|
|
32
174
|
## Contributing
|
33
175
|
|
34
|
-
|
176
|
+
Would you like to add your commits to libui?
|
177
|
+
* Please feel free to send us your [pull requests](https://github.com/kojix2/libui/pulls).
|
178
|
+
* Small corrections, such as typofixes, are appreciated.
|
179
|
+
* Did you find any bugs? Write it in the [issues](https://github.com/kojix2/LibUI/issue) section!
|
35
180
|
|
36
181
|
## Acknowledgement
|
37
182
|
|
data/lib/libui/ffi.rb
CHANGED
@@ -4,60 +4,53 @@ require 'fiddle/import'
|
|
4
4
|
|
5
5
|
module Fiddle
|
6
6
|
# Change the Function to hold a little more information.
|
7
|
-
# FIXME: Give inner_function a better name.
|
8
7
|
class Function
|
9
|
-
|
8
|
+
# Note:
|
9
|
+
# Ruby 2.7 Fiddle::Function dose not have @argument_types
|
10
|
+
# Ruby 3.0 Fiddle::Function has @argument_types
|
11
|
+
attr_accessor :callback_argument_types, :argument_types
|
10
12
|
end
|
11
13
|
|
12
14
|
module Importer
|
13
15
|
def parse_signature(signature, tymap = nil)
|
14
16
|
tymap ||= {}
|
15
|
-
|
17
|
+
ctype, func, args = case compact(signature)
|
18
|
+
when /^(?:[\w\*\s]+)\(\*(\w+)\((.*?)\)\)(?:\[\w*\]|\(.*?\));?$/
|
19
|
+
[TYPE_VOIDP, Regexp.last_match(1), Regexp.last_match(2)]
|
20
|
+
when /^([\w\*\s]+[*\s])(\w+)\((.*?)\);?$/
|
21
|
+
[parse_ctype(Regexp.last_match(1).strip, tymap), Regexp.last_match(2), Regexp.last_match(3)]
|
22
|
+
else
|
23
|
+
raise("can't parserake the function prototype: #{signature}")
|
24
|
+
end
|
16
25
|
symname = func
|
17
|
-
|
18
|
-
|
19
|
-
argtype = split_arguments(args).collect.with_index do |arg, idx| # Added with_index
|
26
|
+
callback_argument_types = {} # Added
|
27
|
+
argtype = split_arguments(args).collect.with_index do |arg, idx| # Added with_index
|
20
28
|
# Check if it is a function pointer or not
|
21
|
-
if arg =~ /\(\*.*\)\(.*\)/
|
29
|
+
if arg =~ /\(\*.*\)\(.*\)/ # Added
|
22
30
|
# From the arguments, create a notation that looks like a function declaration
|
23
31
|
# int(*f)(int *, void *) -> int f(int *, void *)
|
24
|
-
func_arg = arg.sub('(*', ' ').sub(')', '')
|
32
|
+
func_arg = arg.sub('(*', ' ').sub(')', '') # Added
|
25
33
|
# Use Fiddle's parse_signature method again.
|
26
|
-
|
27
|
-
end
|
34
|
+
callback_argument_types[idx] = parse_signature(func_arg) # Added
|
35
|
+
end
|
28
36
|
parse_ctype(arg, tymap)
|
29
37
|
end
|
30
|
-
# Added
|
31
|
-
[symname, ctype, argtype,
|
32
|
-
end
|
33
|
-
|
34
|
-
# refactored
|
35
|
-
def split_signature(signature)
|
36
|
-
case compact(signature)
|
37
|
-
when /^(?:[\w*\s]+)\(\*(\w+)\((.*?)\)\)(?:\[\w*\]|\(.*?\));?$/
|
38
|
-
func = Regexp.last_match(1)
|
39
|
-
args = Regexp.last_match(2)
|
40
|
-
[TYPE_VOIDP, func, args]
|
41
|
-
when /^([\w*\s]+[*\s])(\w+)\((.*?)\);?$/
|
42
|
-
ret = Regexp.last_match(1).strip
|
43
|
-
func = Regexp.last_match(2)
|
44
|
-
args = Regexp.last_match(3)
|
45
|
-
[ret, func, args]
|
46
|
-
else
|
47
|
-
raise("can't parse the function prototype: #{signature}")
|
48
|
-
end
|
38
|
+
# Added callback_argument_types. Original method return only 3 values.
|
39
|
+
[symname, ctype, argtype, callback_argument_types]
|
49
40
|
end
|
50
41
|
|
51
42
|
def extern(signature, *opts)
|
52
|
-
symname, ctype, argtype,
|
43
|
+
symname, ctype, argtype, callback_argument_types = parse_signature(signature, type_alias)
|
53
44
|
opt = parse_bind_options(opts)
|
54
|
-
|
45
|
+
func = import_function(symname, ctype, argtype, opt[:call_type])
|
55
46
|
|
56
|
-
|
57
|
-
|
47
|
+
func.callback_argument_types = callback_argument_types # Added
|
48
|
+
# Ruby 2.7 Fiddle::Function dose not have @argument_types
|
49
|
+
# Ruby 3.0 Fiddle::Function has @argument_types
|
50
|
+
func.argument_types = argtype
|
58
51
|
|
59
52
|
name = symname.gsub(/@.+/, '')
|
60
|
-
@func_map[name] =
|
53
|
+
@func_map[name] = func
|
61
54
|
# define_method(name){|*args,&block| f.call(*args,&block)}
|
62
55
|
begin
|
63
56
|
/^(.+?):(\d+)/ =~ caller.first
|
@@ -72,7 +65,7 @@ module Fiddle
|
|
72
65
|
end
|
73
66
|
EOS
|
74
67
|
module_function(name)
|
75
|
-
|
68
|
+
func
|
76
69
|
end
|
77
70
|
end
|
78
71
|
end
|
@@ -95,6 +88,10 @@ module LibUI
|
|
95
88
|
rescue StandardError => e
|
96
89
|
warn "#{e.class.name}: #{e.message}"
|
97
90
|
end
|
91
|
+
|
92
|
+
def ffi_methods
|
93
|
+
@ffi_methods ||= func_map.each_key.to_a
|
94
|
+
end
|
98
95
|
end
|
99
96
|
|
100
97
|
typealias('uint32_t', 'unsigned int')
|
@@ -280,7 +277,20 @@ module LibUI
|
|
280
277
|
try_extern 'void uiRadioButtonsOnSelected(uiRadioButtons *r, void (*f)(uiRadioButtons *, void *), void *data)'
|
281
278
|
try_extern 'uiRadioButtons *uiNewRadioButtons(void)'
|
282
279
|
|
283
|
-
# uiDateTimePicker
|
280
|
+
# uiDateTimePicker
|
281
|
+
|
282
|
+
# time.h
|
283
|
+
TM = struct [
|
284
|
+
'int tm_sec',
|
285
|
+
'int tm_min',
|
286
|
+
'int tm_hour',
|
287
|
+
'int tm_mday',
|
288
|
+
'int tm_mon',
|
289
|
+
'int tm_year',
|
290
|
+
'int tm_wday',
|
291
|
+
'int tm_yday',
|
292
|
+
'int tm_isdst'
|
293
|
+
]
|
284
294
|
|
285
295
|
try_extern 'void uiDateTimePickerTime(uiDateTimePicker *d, struct tm *time)'
|
286
296
|
try_extern 'void uiDateTimePickerSetTime(uiDateTimePicker *d, const struct tm *time)'
|
data/lib/libui/utils.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module LibUI
|
2
|
+
module Utils
|
3
|
+
class << self
|
4
|
+
def convert_to_ruby_method(original_method_name)
|
5
|
+
underscore(original_method_name.delete_prefix('ui'))
|
6
|
+
end
|
7
|
+
|
8
|
+
# Converting camel case to underscore case in ruby
|
9
|
+
# https://stackoverflow.com/questions/1509915/converting-camel-case-to-underscore-case-in-ruby#1509939
|
10
|
+
def underscore(str)
|
11
|
+
str.gsub(/::/, '/') # Maybe we don't need it.
|
12
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
13
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
14
|
+
.tr('-', '_')
|
15
|
+
.downcase
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/libui/version.rb
CHANGED
data/lib/libui.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'libui/version'
|
4
|
+
require_relative 'libui/utils'
|
4
5
|
|
5
6
|
module LibUI
|
6
7
|
class Error < StandardError; end
|
@@ -9,14 +10,7 @@ module LibUI
|
|
9
10
|
attr_accessor :ffi_lib
|
10
11
|
end
|
11
12
|
|
12
|
-
lib_name =
|
13
|
-
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
14
|
-
'libui.dll'
|
15
|
-
when /darwin|mac os/
|
16
|
-
'libui.dylib'
|
17
|
-
else
|
18
|
-
'libui.so'
|
19
|
-
end
|
13
|
+
lib_name = "libui.#{RbConfig::CONFIG["SOEXT"]}"
|
20
14
|
|
21
15
|
self.ffi_lib = if ENV['LIBUIDIR'] && !ENV['LIBUIDIR'].empty?
|
22
16
|
File.expand_path(lib_name, ENV['LIBUIDIR'])
|
@@ -28,14 +22,7 @@ module LibUI
|
|
28
22
|
|
29
23
|
class << self
|
30
24
|
FFI.func_map.each_key do |original_method_name|
|
31
|
-
|
32
|
-
name = original_method_name.delete_prefix('ui')
|
33
|
-
.gsub(/::/, '/')
|
34
|
-
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
35
|
-
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
36
|
-
.tr('-', '_')
|
37
|
-
.downcase
|
38
|
-
|
25
|
+
name = Utils.convert_to_ruby_method(original_method_name)
|
39
26
|
func = FFI.func_map[original_method_name]
|
40
27
|
|
41
28
|
define_method(name) do |*args, &blk|
|
@@ -47,14 +34,25 @@ module LibUI
|
|
47
34
|
if arg.is_a?(Proc)
|
48
35
|
# The types of the function arguments are recorded beforehand.
|
49
36
|
# See the monkey patch in ffi.rb.
|
50
|
-
Fiddle::Closure::BlockCaller.new(
|
37
|
+
callback = Fiddle::Closure::BlockCaller.new(
|
38
|
+
*func.callback_argument_types[idx][1..2], &arg
|
39
|
+
)
|
40
|
+
# Protect from GC
|
41
|
+
# See https://github.com/kojix2/LibUI/issues/8
|
42
|
+
receiver = args[0]
|
43
|
+
if receiver.instance_variable_defined?(:@callbacks)
|
44
|
+
receiver.instance_variable_get(:@callbacks) << callback
|
45
|
+
else
|
46
|
+
receiver.instance_variable_set(:@callbacks, [callback])
|
47
|
+
end
|
48
|
+
callback
|
51
49
|
else
|
52
50
|
arg
|
53
51
|
end
|
54
52
|
end
|
55
53
|
|
56
54
|
# Make it possible to omit the last nil. This may be an over-optimization.
|
57
|
-
siz = func.
|
55
|
+
siz = func.argument_types.size - 1
|
58
56
|
args[siz] = nil if args.size == siz
|
59
57
|
|
60
58
|
FFI.public_send(original_method_name, *args)
|
@@ -64,10 +62,10 @@ module LibUI
|
|
64
62
|
module CustomMethods
|
65
63
|
def init(opt = FFI::InitOptions.malloc)
|
66
64
|
i = super(opt)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
65
|
+
return if i.size.zero?
|
66
|
+
|
67
|
+
warn 'error'
|
68
|
+
warn UI.free_init_error(init)
|
71
69
|
end
|
72
70
|
end
|
73
71
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: libui
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kojix2
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -91,6 +91,7 @@ files:
|
|
91
91
|
- README.md
|
92
92
|
- lib/libui.rb
|
93
93
|
- lib/libui/ffi.rb
|
94
|
+
- lib/libui/utils.rb
|
94
95
|
- lib/libui/version.rb
|
95
96
|
- vendor/LICENSE
|
96
97
|
- vendor/README.md
|
@@ -112,11 +113,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
112
113
|
version: '2.5'
|
113
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
115
|
requirements:
|
115
|
-
- - "
|
116
|
+
- - ">="
|
116
117
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
118
|
+
version: '0'
|
118
119
|
requirements: []
|
119
|
-
rubygems_version: 3.
|
120
|
+
rubygems_version: 3.2.22
|
120
121
|
signing_key:
|
121
122
|
specification_version: 4
|
122
123
|
summary: Ruby bindings to libui
|