libui 0.0.5.alpha → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
![build](https://github.com/kojix2/libui/workflows/build/badge.svg)
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/libui.svg)](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
|